153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include <string.h> 2653a5a1b3Sopenharmony_ci#include <stdio.h> 2753a5a1b3Sopenharmony_ci#include <string.h> 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <pulse/def.h> 3053a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 3153a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 3253a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3353a5a1b3Sopenharmony_ci#include <pulse/fork-detect.h> 3453a5a1b3Sopenharmony_ci 3553a5a1b3Sopenharmony_ci#include <pulsecore/pstream-util.h> 3653a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h> 3753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 3853a5a1b3Sopenharmony_ci#include <pulsecore/hashmap.h> 3953a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 4053a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 4153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_ci#include "internal.h" 4453a5a1b3Sopenharmony_ci#include "stream.h" 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci/* #define STREAM_DEBUG */ 4753a5a1b3Sopenharmony_ci 4853a5a1b3Sopenharmony_ci#define AUTO_TIMING_INTERVAL_START_USEC (10*PA_USEC_PER_MSEC) 4953a5a1b3Sopenharmony_ci#define AUTO_TIMING_INTERVAL_END_USEC (1500*PA_USEC_PER_MSEC) 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci#define SMOOTHER_HISTORY_TIME (5000*PA_USEC_PER_MSEC) 5253a5a1b3Sopenharmony_ci#ifndef USE_SMOOTHER_2 5353a5a1b3Sopenharmony_ci#define SMOOTHER_ADJUST_TIME (1000*PA_USEC_PER_MSEC) 5453a5a1b3Sopenharmony_ci#define SMOOTHER_MIN_HISTORY (4) 5553a5a1b3Sopenharmony_ci#endif 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_cipa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { 5853a5a1b3Sopenharmony_ci return pa_stream_new_with_proplist(c, name, ss, map, NULL); 5953a5a1b3Sopenharmony_ci} 6053a5a1b3Sopenharmony_ci 6153a5a1b3Sopenharmony_cistatic void reset_callbacks(pa_stream *s) { 6253a5a1b3Sopenharmony_ci s->read_callback = NULL; 6353a5a1b3Sopenharmony_ci s->read_userdata = NULL; 6453a5a1b3Sopenharmony_ci s->write_callback = NULL; 6553a5a1b3Sopenharmony_ci s->write_userdata = NULL; 6653a5a1b3Sopenharmony_ci s->state_callback = NULL; 6753a5a1b3Sopenharmony_ci s->state_userdata = NULL; 6853a5a1b3Sopenharmony_ci s->overflow_callback = NULL; 6953a5a1b3Sopenharmony_ci s->overflow_userdata = NULL; 7053a5a1b3Sopenharmony_ci s->underflow_callback = NULL; 7153a5a1b3Sopenharmony_ci s->underflow_userdata = NULL; 7253a5a1b3Sopenharmony_ci s->latency_update_callback = NULL; 7353a5a1b3Sopenharmony_ci s->latency_update_userdata = NULL; 7453a5a1b3Sopenharmony_ci s->moved_callback = NULL; 7553a5a1b3Sopenharmony_ci s->moved_userdata = NULL; 7653a5a1b3Sopenharmony_ci s->suspended_callback = NULL; 7753a5a1b3Sopenharmony_ci s->suspended_userdata = NULL; 7853a5a1b3Sopenharmony_ci s->started_callback = NULL; 7953a5a1b3Sopenharmony_ci s->started_userdata = NULL; 8053a5a1b3Sopenharmony_ci s->event_callback = NULL; 8153a5a1b3Sopenharmony_ci s->event_userdata = NULL; 8253a5a1b3Sopenharmony_ci s->buffer_attr_callback = NULL; 8353a5a1b3Sopenharmony_ci s->buffer_attr_userdata = NULL; 8453a5a1b3Sopenharmony_ci s->underflow_ohos_callback = NULL; 8553a5a1b3Sopenharmony_ci s->underflow_ohos_userdata = NULL; 8653a5a1b3Sopenharmony_ci} 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_cistatic pa_stream *pa_stream_new_with_proplist_internal( 8953a5a1b3Sopenharmony_ci pa_context *c, 9053a5a1b3Sopenharmony_ci const char *name, 9153a5a1b3Sopenharmony_ci const pa_sample_spec *ss, 9253a5a1b3Sopenharmony_ci const pa_channel_map *map, 9353a5a1b3Sopenharmony_ci pa_format_info * const *formats, 9453a5a1b3Sopenharmony_ci unsigned int n_formats, 9553a5a1b3Sopenharmony_ci pa_proplist *p) { 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci pa_stream *s; 9853a5a1b3Sopenharmony_ci unsigned int i; 9953a5a1b3Sopenharmony_ci 10053a5a1b3Sopenharmony_ci pa_assert(c); 10153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 10253a5a1b3Sopenharmony_ci pa_assert((ss == NULL && map == NULL) || (formats == NULL && n_formats == 0)); 10353a5a1b3Sopenharmony_ci pa_assert(n_formats < PA_MAX_FORMATS); 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 10653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID); 10753a5a1b3Sopenharmony_ci 10853a5a1b3Sopenharmony_ci s = pa_xnew(pa_stream, 1); 10953a5a1b3Sopenharmony_ci PA_REFCNT_INIT(s); 11053a5a1b3Sopenharmony_ci s->context = c; 11153a5a1b3Sopenharmony_ci s->mainloop = c->mainloop; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci s->direction = PA_STREAM_NODIRECTION; 11453a5a1b3Sopenharmony_ci s->state = PA_STREAM_UNCONNECTED; 11553a5a1b3Sopenharmony_ci s->flags = 0; 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci if (ss) 11853a5a1b3Sopenharmony_ci s->sample_spec = *ss; 11953a5a1b3Sopenharmony_ci else 12053a5a1b3Sopenharmony_ci pa_sample_spec_init(&s->sample_spec); 12153a5a1b3Sopenharmony_ci 12253a5a1b3Sopenharmony_ci if (map) 12353a5a1b3Sopenharmony_ci s->channel_map = *map; 12453a5a1b3Sopenharmony_ci else 12553a5a1b3Sopenharmony_ci pa_channel_map_init(&s->channel_map); 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci s->n_formats = 0; 12853a5a1b3Sopenharmony_ci if (formats) { 12953a5a1b3Sopenharmony_ci s->n_formats = n_formats; 13053a5a1b3Sopenharmony_ci for (i = 0; i < n_formats; i++) 13153a5a1b3Sopenharmony_ci s->req_formats[i] = pa_format_info_copy(formats[i]); 13253a5a1b3Sopenharmony_ci } 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci /* We'll get the final negotiated format after connecting */ 13553a5a1b3Sopenharmony_ci s->format = NULL; 13653a5a1b3Sopenharmony_ci 13753a5a1b3Sopenharmony_ci s->direct_on_input = PA_INVALID_INDEX; 13853a5a1b3Sopenharmony_ci 13953a5a1b3Sopenharmony_ci s->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); 14053a5a1b3Sopenharmony_ci if (name) 14153a5a1b3Sopenharmony_ci pa_proplist_sets(s->proplist, PA_PROP_MEDIA_NAME, name); 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci s->channel = 0; 14453a5a1b3Sopenharmony_ci s->channel_valid = false; 14553a5a1b3Sopenharmony_ci s->syncid = c->csyncid++; 14653a5a1b3Sopenharmony_ci s->stream_index = PA_INVALID_INDEX; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci s->requested_bytes = 0; 14953a5a1b3Sopenharmony_ci memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci /* We initialize the target length here, so that if the user 15253a5a1b3Sopenharmony_ci * passes no explicit buffering metrics the default is similar to 15353a5a1b3Sopenharmony_ci * what older PA versions provided. */ 15453a5a1b3Sopenharmony_ci 15553a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = (uint32_t) -1; 15653a5a1b3Sopenharmony_ci if (ss) 15753a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, ss); /* 250ms of buffering */ 15853a5a1b3Sopenharmony_ci else { 15953a5a1b3Sopenharmony_ci /* FIXME: We assume a worst-case compressed format corresponding to 16053a5a1b3Sopenharmony_ci * 48000 Hz, 2 ch, S16 PCM, but this can very well be incorrect */ 16153a5a1b3Sopenharmony_ci pa_sample_spec tmp_ss = { 16253a5a1b3Sopenharmony_ci .format = PA_SAMPLE_S16NE, 16353a5a1b3Sopenharmony_ci .rate = 48000, 16453a5a1b3Sopenharmony_ci .channels = 2, 16553a5a1b3Sopenharmony_ci }; 16653a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, &tmp_ss); /* 250ms of buffering */ 16753a5a1b3Sopenharmony_ci } 16853a5a1b3Sopenharmony_ci s->buffer_attr.minreq = (uint32_t) -1; 16953a5a1b3Sopenharmony_ci s->buffer_attr.prebuf = (uint32_t) -1; 17053a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (uint32_t) -1; 17153a5a1b3Sopenharmony_ci 17253a5a1b3Sopenharmony_ci s->device_index = PA_INVALID_INDEX; 17353a5a1b3Sopenharmony_ci s->device_name = NULL; 17453a5a1b3Sopenharmony_ci s->suspended = false; 17553a5a1b3Sopenharmony_ci s->corked = false; 17653a5a1b3Sopenharmony_ci 17753a5a1b3Sopenharmony_ci s->write_memblock = NULL; 17853a5a1b3Sopenharmony_ci s->write_data = NULL; 17953a5a1b3Sopenharmony_ci 18053a5a1b3Sopenharmony_ci pa_memchunk_reset(&s->peek_memchunk); 18153a5a1b3Sopenharmony_ci s->peek_data = NULL; 18253a5a1b3Sopenharmony_ci s->record_memblockq = NULL; 18353a5a1b3Sopenharmony_ci 18453a5a1b3Sopenharmony_ci memset(&s->timing_info, 0, sizeof(s->timing_info)); 18553a5a1b3Sopenharmony_ci s->timing_info_valid = false; 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci s->previous_time = 0; 18853a5a1b3Sopenharmony_ci s->latest_underrun_at_index = -1; 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_ci s->read_index_not_before = 0; 19153a5a1b3Sopenharmony_ci s->write_index_not_before = 0; 19253a5a1b3Sopenharmony_ci for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) 19353a5a1b3Sopenharmony_ci s->write_index_corrections[i].valid = 0; 19453a5a1b3Sopenharmony_ci s->current_write_index_correction = 0; 19553a5a1b3Sopenharmony_ci 19653a5a1b3Sopenharmony_ci s->auto_timing_update_event = NULL; 19753a5a1b3Sopenharmony_ci s->auto_timing_update_requested = false; 19853a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; 19953a5a1b3Sopenharmony_ci 20053a5a1b3Sopenharmony_ci reset_callbacks(s); 20153a5a1b3Sopenharmony_ci 20253a5a1b3Sopenharmony_ci s->smoother = NULL; 20353a5a1b3Sopenharmony_ci 20453a5a1b3Sopenharmony_ci /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ 20553a5a1b3Sopenharmony_ci PA_LLIST_PREPEND(pa_stream, c->streams, s); 20653a5a1b3Sopenharmony_ci pa_stream_ref(s); 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci return s; 20953a5a1b3Sopenharmony_ci} 21053a5a1b3Sopenharmony_ci 21153a5a1b3Sopenharmony_cipa_stream *pa_stream_new_with_proplist( 21253a5a1b3Sopenharmony_ci pa_context *c, 21353a5a1b3Sopenharmony_ci const char *name, 21453a5a1b3Sopenharmony_ci const pa_sample_spec *ss, 21553a5a1b3Sopenharmony_ci const pa_channel_map *map, 21653a5a1b3Sopenharmony_ci pa_proplist *p) { 21753a5a1b3Sopenharmony_ci 21853a5a1b3Sopenharmony_ci pa_channel_map tmap; 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); 22153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE && ss->format != PA_SAMPLE_S32BE), PA_ERR_NOTSUPPORTED); 22253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15 || (ss->format != PA_SAMPLE_S24LE && ss->format != PA_SAMPLE_S24BE), PA_ERR_NOTSUPPORTED); 22353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 15 || (ss->format != PA_SAMPLE_S24_32LE && ss->format != PA_SAMPLE_S24_32BE), PA_ERR_NOTSUPPORTED); 22453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); 22553a5a1b3Sopenharmony_ci 22653a5a1b3Sopenharmony_ci if (!map) 22753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, map = pa_channel_map_init_auto(&tmap, ss->channels, PA_CHANNEL_MAP_DEFAULT), PA_ERR_INVALID); 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci return pa_stream_new_with_proplist_internal(c, name, ss, map, NULL, 0, p); 23053a5a1b3Sopenharmony_ci} 23153a5a1b3Sopenharmony_ci 23253a5a1b3Sopenharmony_cipa_stream *pa_stream_new_extended( 23353a5a1b3Sopenharmony_ci pa_context *c, 23453a5a1b3Sopenharmony_ci const char *name, 23553a5a1b3Sopenharmony_ci pa_format_info * const *formats, 23653a5a1b3Sopenharmony_ci unsigned int n_formats, 23753a5a1b3Sopenharmony_ci pa_proplist *p) { 23853a5a1b3Sopenharmony_ci 23953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 21, PA_ERR_NOTSUPPORTED); 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci return pa_stream_new_with_proplist_internal(c, name, NULL, NULL, formats, n_formats, p); 24253a5a1b3Sopenharmony_ci} 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_cistatic void stream_unlink(pa_stream *s) { 24553a5a1b3Sopenharmony_ci pa_operation *o, *n; 24653a5a1b3Sopenharmony_ci pa_assert(s); 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci if (!s->context) 24953a5a1b3Sopenharmony_ci return; 25053a5a1b3Sopenharmony_ci 25153a5a1b3Sopenharmony_ci /* Detach from context */ 25253a5a1b3Sopenharmony_ci 25353a5a1b3Sopenharmony_ci /* Unref all operation objects that point to us */ 25453a5a1b3Sopenharmony_ci for (o = s->context->operations; o; o = n) { 25553a5a1b3Sopenharmony_ci n = o->next; 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_ci if (o->stream == s) 25853a5a1b3Sopenharmony_ci pa_operation_cancel(o); 25953a5a1b3Sopenharmony_ci } 26053a5a1b3Sopenharmony_ci 26153a5a1b3Sopenharmony_ci /* Drop all outstanding replies for this stream */ 26253a5a1b3Sopenharmony_ci if (s->context->pdispatch) 26353a5a1b3Sopenharmony_ci pa_pdispatch_unregister_reply(s->context->pdispatch, s); 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci if (s->channel_valid) { 26653a5a1b3Sopenharmony_ci pa_hashmap_remove((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, PA_UINT32_TO_PTR(s->channel)); 26753a5a1b3Sopenharmony_ci s->channel = 0; 26853a5a1b3Sopenharmony_ci s->channel_valid = false; 26953a5a1b3Sopenharmony_ci } 27053a5a1b3Sopenharmony_ci 27153a5a1b3Sopenharmony_ci PA_LLIST_REMOVE(pa_stream, s->context->streams, s); 27253a5a1b3Sopenharmony_ci pa_stream_unref(s); 27353a5a1b3Sopenharmony_ci 27453a5a1b3Sopenharmony_ci s->context = NULL; 27553a5a1b3Sopenharmony_ci 27653a5a1b3Sopenharmony_ci if (s->auto_timing_update_event) { 27753a5a1b3Sopenharmony_ci pa_assert(s->mainloop); 27853a5a1b3Sopenharmony_ci s->mainloop->time_free(s->auto_timing_update_event); 27953a5a1b3Sopenharmony_ci } 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci reset_callbacks(s); 28253a5a1b3Sopenharmony_ci} 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_cistatic void stream_free(pa_stream *s) { 28553a5a1b3Sopenharmony_ci unsigned int i; 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci pa_assert(s); 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci stream_unlink(s); 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_ci if (s->write_memblock) { 29253a5a1b3Sopenharmony_ci if (s->write_data) 29353a5a1b3Sopenharmony_ci pa_memblock_release(s->write_memblock); 29453a5a1b3Sopenharmony_ci pa_memblock_unref(s->write_memblock); 29553a5a1b3Sopenharmony_ci } 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci if (s->peek_memchunk.memblock) { 29853a5a1b3Sopenharmony_ci if (s->peek_data) 29953a5a1b3Sopenharmony_ci pa_memblock_release(s->peek_memchunk.memblock); 30053a5a1b3Sopenharmony_ci pa_memblock_unref(s->peek_memchunk.memblock); 30153a5a1b3Sopenharmony_ci } 30253a5a1b3Sopenharmony_ci 30353a5a1b3Sopenharmony_ci if (s->record_memblockq) 30453a5a1b3Sopenharmony_ci pa_memblockq_free(s->record_memblockq); 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci if (s->proplist) 30753a5a1b3Sopenharmony_ci pa_proplist_free(s->proplist); 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci if (s->smoother) 31053a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 31153a5a1b3Sopenharmony_ci pa_smoother_2_free(s->smoother); 31253a5a1b3Sopenharmony_ci#else 31353a5a1b3Sopenharmony_ci pa_smoother_free(s->smoother); 31453a5a1b3Sopenharmony_ci#endif 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_ci for (i = 0; i < s->n_formats; i++) 31753a5a1b3Sopenharmony_ci pa_format_info_free(s->req_formats[i]); 31853a5a1b3Sopenharmony_ci 31953a5a1b3Sopenharmony_ci if (s->format) 32053a5a1b3Sopenharmony_ci pa_format_info_free(s->format); 32153a5a1b3Sopenharmony_ci 32253a5a1b3Sopenharmony_ci pa_xfree(s->device_name); 32353a5a1b3Sopenharmony_ci pa_xfree(s); 32453a5a1b3Sopenharmony_ci} 32553a5a1b3Sopenharmony_ci 32653a5a1b3Sopenharmony_civoid pa_stream_unref(pa_stream *s) { 32753a5a1b3Sopenharmony_ci pa_assert(s); 32853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 32953a5a1b3Sopenharmony_ci 33053a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(s) <= 0) 33153a5a1b3Sopenharmony_ci stream_free(s); 33253a5a1b3Sopenharmony_ci} 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_cipa_stream* pa_stream_ref(pa_stream *s) { 33553a5a1b3Sopenharmony_ci pa_assert(s); 33653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 33753a5a1b3Sopenharmony_ci 33853a5a1b3Sopenharmony_ci PA_REFCNT_INC(s); 33953a5a1b3Sopenharmony_ci return s; 34053a5a1b3Sopenharmony_ci} 34153a5a1b3Sopenharmony_ci 34253a5a1b3Sopenharmony_cipa_stream_state_t pa_stream_get_state(const pa_stream *s) { 34353a5a1b3Sopenharmony_ci pa_assert(s); 34453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 34553a5a1b3Sopenharmony_ci 34653a5a1b3Sopenharmony_ci return s->state; 34753a5a1b3Sopenharmony_ci} 34853a5a1b3Sopenharmony_ci 34953a5a1b3Sopenharmony_civoid pa_stream_terminate(pa_stream *s) { 35053a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_TERMINATED); 35153a5a1b3Sopenharmony_ci} 35253a5a1b3Sopenharmony_ci 35353a5a1b3Sopenharmony_cipa_context* pa_stream_get_context(const pa_stream *s) { 35453a5a1b3Sopenharmony_ci pa_assert(s); 35553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci return s->context; 35853a5a1b3Sopenharmony_ci} 35953a5a1b3Sopenharmony_ci 36053a5a1b3Sopenharmony_ciuint32_t pa_stream_get_index(const pa_stream *s) { 36153a5a1b3Sopenharmony_ci pa_assert(s); 36253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 36353a5a1b3Sopenharmony_ci 36453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX); 36553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci return s->stream_index; 36853a5a1b3Sopenharmony_ci} 36953a5a1b3Sopenharmony_ci 37053a5a1b3Sopenharmony_civoid pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { 37153a5a1b3Sopenharmony_ci pa_assert(s); 37253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci if (s->state == st) 37553a5a1b3Sopenharmony_ci return; 37653a5a1b3Sopenharmony_ci 37753a5a1b3Sopenharmony_ci pa_stream_ref(s); 37853a5a1b3Sopenharmony_ci 37953a5a1b3Sopenharmony_ci s->state = st; 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci if (s->state_callback) 38253a5a1b3Sopenharmony_ci s->state_callback(s, s->state_userdata); 38353a5a1b3Sopenharmony_ci 38453a5a1b3Sopenharmony_ci if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED)) 38553a5a1b3Sopenharmony_ci stream_unlink(s); 38653a5a1b3Sopenharmony_ci 38753a5a1b3Sopenharmony_ci pa_stream_unref(s); 38853a5a1b3Sopenharmony_ci} 38953a5a1b3Sopenharmony_ci 39053a5a1b3Sopenharmony_cistatic void request_auto_timing_update(pa_stream *s, bool force) { 39153a5a1b3Sopenharmony_ci pa_assert(s); 39253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 39353a5a1b3Sopenharmony_ci 39453a5a1b3Sopenharmony_ci if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) 39553a5a1b3Sopenharmony_ci return; 39653a5a1b3Sopenharmony_ci 39753a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_READY && 39853a5a1b3Sopenharmony_ci (force || !s->auto_timing_update_requested)) { 39953a5a1b3Sopenharmony_ci pa_operation *o; 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 40253a5a1b3Sopenharmony_ci pa_log_debug("Automatically requesting new timing data"); 40353a5a1b3Sopenharmony_ci#endif 40453a5a1b3Sopenharmony_ci 40553a5a1b3Sopenharmony_ci if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { 40653a5a1b3Sopenharmony_ci pa_operation_unref(o); 40753a5a1b3Sopenharmony_ci s->auto_timing_update_requested = true; 40853a5a1b3Sopenharmony_ci } 40953a5a1b3Sopenharmony_ci } 41053a5a1b3Sopenharmony_ci 41153a5a1b3Sopenharmony_ci if (s->auto_timing_update_event) { 41253a5a1b3Sopenharmony_ci if (s->suspended && !force) { 41353a5a1b3Sopenharmony_ci pa_assert(s->mainloop); 41453a5a1b3Sopenharmony_ci s->mainloop->time_free(s->auto_timing_update_event); 41553a5a1b3Sopenharmony_ci s->auto_timing_update_event = NULL; 41653a5a1b3Sopenharmony_ci } else { 41753a5a1b3Sopenharmony_ci if (force) 41853a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; 41953a5a1b3Sopenharmony_ci 42053a5a1b3Sopenharmony_ci pa_context_rttime_restart(s->context, s->auto_timing_update_event, pa_rtclock_now() + s->auto_timing_interval_usec); 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = PA_MIN(AUTO_TIMING_INTERVAL_END_USEC, s->auto_timing_interval_usec*2); 42353a5a1b3Sopenharmony_ci } 42453a5a1b3Sopenharmony_ci } 42553a5a1b3Sopenharmony_ci} 42653a5a1b3Sopenharmony_ci 42753a5a1b3Sopenharmony_civoid pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 42853a5a1b3Sopenharmony_ci pa_context *c = userdata; 42953a5a1b3Sopenharmony_ci pa_stream *s; 43053a5a1b3Sopenharmony_ci uint32_t channel; 43153a5a1b3Sopenharmony_ci 43253a5a1b3Sopenharmony_ci pa_assert(pd); 43353a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); 43453a5a1b3Sopenharmony_ci pa_assert(t); 43553a5a1b3Sopenharmony_ci pa_assert(c); 43653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci pa_context_ref(c); 43953a5a1b3Sopenharmony_ci 44053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 44153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 44253a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 44353a5a1b3Sopenharmony_ci goto finish; 44453a5a1b3Sopenharmony_ci } 44553a5a1b3Sopenharmony_ci 44653a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel)))) 44753a5a1b3Sopenharmony_ci goto finish; 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 45053a5a1b3Sopenharmony_ci goto finish; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci pa_context_set_error(c, PA_ERR_KILLED); 45353a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_FAILED); 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_cifinish: 45653a5a1b3Sopenharmony_ci pa_context_unref(c); 45753a5a1b3Sopenharmony_ci} 45853a5a1b3Sopenharmony_ci 45953a5a1b3Sopenharmony_cistatic void check_smoother_status(pa_stream *s, bool aposteriori, bool force_start, bool force_stop) { 46053a5a1b3Sopenharmony_ci pa_usec_t x; 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_ci pa_assert(s); 46353a5a1b3Sopenharmony_ci pa_assert(!force_start || !force_stop); 46453a5a1b3Sopenharmony_ci 46553a5a1b3Sopenharmony_ci if (!s->smoother) 46653a5a1b3Sopenharmony_ci return; 46753a5a1b3Sopenharmony_ci 46853a5a1b3Sopenharmony_ci x = pa_rtclock_now(); 46953a5a1b3Sopenharmony_ci 47053a5a1b3Sopenharmony_ci if (s->timing_info_valid) { 47153a5a1b3Sopenharmony_ci if (aposteriori) 47253a5a1b3Sopenharmony_ci x -= s->timing_info.transport_usec; 47353a5a1b3Sopenharmony_ci else 47453a5a1b3Sopenharmony_ci x += s->timing_info.transport_usec; 47553a5a1b3Sopenharmony_ci } 47653a5a1b3Sopenharmony_ci 47753a5a1b3Sopenharmony_ci if (s->suspended || s->corked || force_stop) 47853a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 47953a5a1b3Sopenharmony_ci pa_smoother_2_pause(s->smoother, x); 48053a5a1b3Sopenharmony_ci#else 48153a5a1b3Sopenharmony_ci pa_smoother_pause(s->smoother, x); 48253a5a1b3Sopenharmony_ci#endif 48353a5a1b3Sopenharmony_ci else if (force_start || s->buffer_attr.prebuf == 0) { 48453a5a1b3Sopenharmony_ci 48553a5a1b3Sopenharmony_ci if (!s->timing_info_valid && 48653a5a1b3Sopenharmony_ci !aposteriori && 48753a5a1b3Sopenharmony_ci !force_start && 48853a5a1b3Sopenharmony_ci !force_stop && 48953a5a1b3Sopenharmony_ci s->context->version >= 13) { 49053a5a1b3Sopenharmony_ci 49153a5a1b3Sopenharmony_ci /* If the server supports STARTED events we take them as 49253a5a1b3Sopenharmony_ci * indications when audio really starts/stops playing, if 49353a5a1b3Sopenharmony_ci * we don't have any timing info yet -- instead of trying 49453a5a1b3Sopenharmony_ci * to be smart and guessing the server time. Otherwise the 49553a5a1b3Sopenharmony_ci * unknown transport delay adds too much noise to our time 49653a5a1b3Sopenharmony_ci * calculations. */ 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci return; 49953a5a1b3Sopenharmony_ci } 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 50253a5a1b3Sopenharmony_ci pa_smoother_2_resume(s->smoother, x); 50353a5a1b3Sopenharmony_ci#else 50453a5a1b3Sopenharmony_ci pa_smoother_resume(s->smoother, x, true); 50553a5a1b3Sopenharmony_ci#endif 50653a5a1b3Sopenharmony_ci } 50753a5a1b3Sopenharmony_ci 50853a5a1b3Sopenharmony_ci /* Please note that we have no idea if playback actually started 50953a5a1b3Sopenharmony_ci * if prebuf is non-zero! */ 51053a5a1b3Sopenharmony_ci} 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_cistatic void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata); 51353a5a1b3Sopenharmony_ci 51453a5a1b3Sopenharmony_civoid pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 51553a5a1b3Sopenharmony_ci pa_context *c = userdata; 51653a5a1b3Sopenharmony_ci pa_stream *s; 51753a5a1b3Sopenharmony_ci uint32_t channel; 51853a5a1b3Sopenharmony_ci const char *dn; 51953a5a1b3Sopenharmony_ci bool suspended; 52053a5a1b3Sopenharmony_ci uint32_t di; 52153a5a1b3Sopenharmony_ci pa_usec_t usec = 0; 52253a5a1b3Sopenharmony_ci uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0; 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci pa_assert(pd); 52553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_MOVED || command == PA_COMMAND_RECORD_STREAM_MOVED); 52653a5a1b3Sopenharmony_ci pa_assert(t); 52753a5a1b3Sopenharmony_ci pa_assert(c); 52853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 52953a5a1b3Sopenharmony_ci 53053a5a1b3Sopenharmony_ci pa_context_ref(c); 53153a5a1b3Sopenharmony_ci 53253a5a1b3Sopenharmony_ci if (c->version < 12) { 53353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 53453a5a1b3Sopenharmony_ci goto finish; 53553a5a1b3Sopenharmony_ci } 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 53853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &di) < 0 || 53953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &dn) < 0 || 54053a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0) { 54153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 54253a5a1b3Sopenharmony_ci goto finish; 54353a5a1b3Sopenharmony_ci } 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci if (c->version >= 13) { 54653a5a1b3Sopenharmony_ci 54753a5a1b3Sopenharmony_ci if (command == PA_COMMAND_RECORD_STREAM_MOVED) { 54853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &maxlength) < 0 || 54953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &fragsize) < 0 || 55053a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 55153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 55253a5a1b3Sopenharmony_ci goto finish; 55353a5a1b3Sopenharmony_ci } 55453a5a1b3Sopenharmony_ci } else { 55553a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &maxlength) < 0 || 55653a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &tlength) < 0 || 55753a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &prebuf) < 0 || 55853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &minreq) < 0 || 55953a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 56053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 56153a5a1b3Sopenharmony_ci goto finish; 56253a5a1b3Sopenharmony_ci } 56353a5a1b3Sopenharmony_ci } 56453a5a1b3Sopenharmony_ci } 56553a5a1b3Sopenharmony_ci 56653a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 56753a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 56853a5a1b3Sopenharmony_ci goto finish; 56953a5a1b3Sopenharmony_ci } 57053a5a1b3Sopenharmony_ci 57153a5a1b3Sopenharmony_ci if (!dn || di == PA_INVALID_INDEX) { 57253a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 57353a5a1b3Sopenharmony_ci goto finish; 57453a5a1b3Sopenharmony_ci } 57553a5a1b3Sopenharmony_ci 57653a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_MOVED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel)))) 57753a5a1b3Sopenharmony_ci goto finish; 57853a5a1b3Sopenharmony_ci 57953a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 58053a5a1b3Sopenharmony_ci goto finish; 58153a5a1b3Sopenharmony_ci 58253a5a1b3Sopenharmony_ci if (c->version >= 13) { 58353a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_RECORD) 58453a5a1b3Sopenharmony_ci s->timing_info.configured_source_usec = usec; 58553a5a1b3Sopenharmony_ci else 58653a5a1b3Sopenharmony_ci s->timing_info.configured_sink_usec = usec; 58753a5a1b3Sopenharmony_ci 58853a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = maxlength; 58953a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = fragsize; 59053a5a1b3Sopenharmony_ci s->buffer_attr.tlength = tlength; 59153a5a1b3Sopenharmony_ci s->buffer_attr.prebuf = prebuf; 59253a5a1b3Sopenharmony_ci s->buffer_attr.minreq = minreq; 59353a5a1b3Sopenharmony_ci } 59453a5a1b3Sopenharmony_ci 59553a5a1b3Sopenharmony_ci pa_xfree(s->device_name); 59653a5a1b3Sopenharmony_ci s->device_name = pa_xstrdup(dn); 59753a5a1b3Sopenharmony_ci s->device_index = di; 59853a5a1b3Sopenharmony_ci 59953a5a1b3Sopenharmony_ci s->suspended = suspended; 60053a5a1b3Sopenharmony_ci 60153a5a1b3Sopenharmony_ci if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) { 60253a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; 60353a5a1b3Sopenharmony_ci s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); 60453a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 60553a5a1b3Sopenharmony_ci } 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_ci check_smoother_status(s, true, false, false); 60853a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 60953a5a1b3Sopenharmony_ci 61053a5a1b3Sopenharmony_ci if (s->moved_callback) 61153a5a1b3Sopenharmony_ci s->moved_callback(s, s->moved_userdata); 61253a5a1b3Sopenharmony_ci 61353a5a1b3Sopenharmony_cifinish: 61453a5a1b3Sopenharmony_ci pa_context_unref(c); 61553a5a1b3Sopenharmony_ci} 61653a5a1b3Sopenharmony_ci 61753a5a1b3Sopenharmony_civoid pa_command_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 61853a5a1b3Sopenharmony_ci pa_context *c = userdata; 61953a5a1b3Sopenharmony_ci pa_stream *s; 62053a5a1b3Sopenharmony_ci uint32_t channel; 62153a5a1b3Sopenharmony_ci pa_usec_t usec = 0; 62253a5a1b3Sopenharmony_ci uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0; 62353a5a1b3Sopenharmony_ci 62453a5a1b3Sopenharmony_ci pa_assert(pd); 62553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED || command == PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED); 62653a5a1b3Sopenharmony_ci pa_assert(t); 62753a5a1b3Sopenharmony_ci pa_assert(c); 62853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 62953a5a1b3Sopenharmony_ci 63053a5a1b3Sopenharmony_ci pa_context_ref(c); 63153a5a1b3Sopenharmony_ci 63253a5a1b3Sopenharmony_ci if (c->version < 15) { 63353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 63453a5a1b3Sopenharmony_ci goto finish; 63553a5a1b3Sopenharmony_ci } 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0) { 63853a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 63953a5a1b3Sopenharmony_ci goto finish; 64053a5a1b3Sopenharmony_ci } 64153a5a1b3Sopenharmony_ci 64253a5a1b3Sopenharmony_ci if (command == PA_COMMAND_RECORD_STREAM_MOVED) { 64353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &maxlength) < 0 || 64453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &fragsize) < 0 || 64553a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 64653a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 64753a5a1b3Sopenharmony_ci goto finish; 64853a5a1b3Sopenharmony_ci } 64953a5a1b3Sopenharmony_ci } else { 65053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &maxlength) < 0 || 65153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &tlength) < 0 || 65253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &prebuf) < 0 || 65353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &minreq) < 0 || 65453a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 65553a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 65653a5a1b3Sopenharmony_ci goto finish; 65753a5a1b3Sopenharmony_ci } 65853a5a1b3Sopenharmony_ci } 65953a5a1b3Sopenharmony_ci 66053a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 66153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 66253a5a1b3Sopenharmony_ci goto finish; 66353a5a1b3Sopenharmony_ci } 66453a5a1b3Sopenharmony_ci 66553a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel)))) 66653a5a1b3Sopenharmony_ci goto finish; 66753a5a1b3Sopenharmony_ci 66853a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 66953a5a1b3Sopenharmony_ci goto finish; 67053a5a1b3Sopenharmony_ci 67153a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_RECORD) 67253a5a1b3Sopenharmony_ci s->timing_info.configured_source_usec = usec; 67353a5a1b3Sopenharmony_ci else 67453a5a1b3Sopenharmony_ci s->timing_info.configured_sink_usec = usec; 67553a5a1b3Sopenharmony_ci 67653a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = maxlength; 67753a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = fragsize; 67853a5a1b3Sopenharmony_ci s->buffer_attr.tlength = tlength; 67953a5a1b3Sopenharmony_ci s->buffer_attr.prebuf = prebuf; 68053a5a1b3Sopenharmony_ci s->buffer_attr.minreq = minreq; 68153a5a1b3Sopenharmony_ci 68253a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 68353a5a1b3Sopenharmony_ci 68453a5a1b3Sopenharmony_ci if (s->buffer_attr_callback) 68553a5a1b3Sopenharmony_ci s->buffer_attr_callback(s, s->buffer_attr_userdata); 68653a5a1b3Sopenharmony_ci 68753a5a1b3Sopenharmony_cifinish: 68853a5a1b3Sopenharmony_ci pa_context_unref(c); 68953a5a1b3Sopenharmony_ci} 69053a5a1b3Sopenharmony_ci 69153a5a1b3Sopenharmony_civoid pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 69253a5a1b3Sopenharmony_ci pa_context *c = userdata; 69353a5a1b3Sopenharmony_ci pa_stream *s; 69453a5a1b3Sopenharmony_ci uint32_t channel; 69553a5a1b3Sopenharmony_ci bool suspended; 69653a5a1b3Sopenharmony_ci 69753a5a1b3Sopenharmony_ci pa_assert(pd); 69853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED || command == PA_COMMAND_RECORD_STREAM_SUSPENDED); 69953a5a1b3Sopenharmony_ci pa_assert(t); 70053a5a1b3Sopenharmony_ci pa_assert(c); 70153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 70253a5a1b3Sopenharmony_ci 70353a5a1b3Sopenharmony_ci pa_context_ref(c); 70453a5a1b3Sopenharmony_ci 70553a5a1b3Sopenharmony_ci if (c->version < 12) { 70653a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 70753a5a1b3Sopenharmony_ci goto finish; 70853a5a1b3Sopenharmony_ci } 70953a5a1b3Sopenharmony_ci 71053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 71153a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0 || 71253a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 71353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 71453a5a1b3Sopenharmony_ci goto finish; 71553a5a1b3Sopenharmony_ci } 71653a5a1b3Sopenharmony_ci 71753a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_SUSPENDED ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel)))) 71853a5a1b3Sopenharmony_ci goto finish; 71953a5a1b3Sopenharmony_ci 72053a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 72153a5a1b3Sopenharmony_ci goto finish; 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ci s->suspended = suspended; 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci if ((s->flags & PA_STREAM_AUTO_TIMING_UPDATE) && !suspended && !s->auto_timing_update_event) { 72653a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; 72753a5a1b3Sopenharmony_ci s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); 72853a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 72953a5a1b3Sopenharmony_ci } 73053a5a1b3Sopenharmony_ci 73153a5a1b3Sopenharmony_ci check_smoother_status(s, true, false, false); 73253a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 73353a5a1b3Sopenharmony_ci 73453a5a1b3Sopenharmony_ci if (s->suspended_callback) 73553a5a1b3Sopenharmony_ci s->suspended_callback(s, s->suspended_userdata); 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_cifinish: 73853a5a1b3Sopenharmony_ci pa_context_unref(c); 73953a5a1b3Sopenharmony_ci} 74053a5a1b3Sopenharmony_ci 74153a5a1b3Sopenharmony_civoid pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 74253a5a1b3Sopenharmony_ci pa_context *c = userdata; 74353a5a1b3Sopenharmony_ci pa_stream *s; 74453a5a1b3Sopenharmony_ci uint32_t channel; 74553a5a1b3Sopenharmony_ci 74653a5a1b3Sopenharmony_ci pa_assert(pd); 74753a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_STARTED); 74853a5a1b3Sopenharmony_ci pa_assert(t); 74953a5a1b3Sopenharmony_ci pa_assert(c); 75053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci pa_context_ref(c); 75353a5a1b3Sopenharmony_ci 75453a5a1b3Sopenharmony_ci if (c->version < 13) { 75553a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 75653a5a1b3Sopenharmony_ci goto finish; 75753a5a1b3Sopenharmony_ci } 75853a5a1b3Sopenharmony_ci 75953a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 76053a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 76153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 76253a5a1b3Sopenharmony_ci goto finish; 76353a5a1b3Sopenharmony_ci } 76453a5a1b3Sopenharmony_ci 76553a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel)))) 76653a5a1b3Sopenharmony_ci goto finish; 76753a5a1b3Sopenharmony_ci 76853a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 76953a5a1b3Sopenharmony_ci goto finish; 77053a5a1b3Sopenharmony_ci 77153a5a1b3Sopenharmony_ci check_smoother_status(s, true, true, false); 77253a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci if (s->started_callback) 77553a5a1b3Sopenharmony_ci s->started_callback(s, s->started_userdata); 77653a5a1b3Sopenharmony_ci 77753a5a1b3Sopenharmony_cifinish: 77853a5a1b3Sopenharmony_ci pa_context_unref(c); 77953a5a1b3Sopenharmony_ci} 78053a5a1b3Sopenharmony_ci 78153a5a1b3Sopenharmony_civoid pa_command_stream_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 78253a5a1b3Sopenharmony_ci pa_context *c = userdata; 78353a5a1b3Sopenharmony_ci pa_stream *s; 78453a5a1b3Sopenharmony_ci uint32_t channel; 78553a5a1b3Sopenharmony_ci pa_proplist *pl = NULL; 78653a5a1b3Sopenharmony_ci const char *event; 78753a5a1b3Sopenharmony_ci 78853a5a1b3Sopenharmony_ci pa_assert(pd); 78953a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_PLAYBACK_STREAM_EVENT || command == PA_COMMAND_RECORD_STREAM_EVENT); 79053a5a1b3Sopenharmony_ci pa_assert(t); 79153a5a1b3Sopenharmony_ci pa_assert(c); 79253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 79353a5a1b3Sopenharmony_ci 79453a5a1b3Sopenharmony_ci pa_context_ref(c); 79553a5a1b3Sopenharmony_ci 79653a5a1b3Sopenharmony_ci if (c->version < 15) { 79753a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 79853a5a1b3Sopenharmony_ci goto finish; 79953a5a1b3Sopenharmony_ci } 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci pl = pa_proplist_new(); 80253a5a1b3Sopenharmony_ci 80353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 80453a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &event) < 0 || 80553a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, pl) < 0 || 80653a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t) || !event) { 80753a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 80853a5a1b3Sopenharmony_ci goto finish; 80953a5a1b3Sopenharmony_ci } 81053a5a1b3Sopenharmony_ci 81153a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(command == PA_COMMAND_PLAYBACK_STREAM_EVENT ? c->playback_streams : c->record_streams, PA_UINT32_TO_PTR(channel)))) 81253a5a1b3Sopenharmony_ci goto finish; 81353a5a1b3Sopenharmony_ci 81453a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 81553a5a1b3Sopenharmony_ci goto finish; 81653a5a1b3Sopenharmony_ci 81753a5a1b3Sopenharmony_ci if (pa_streq(event, PA_STREAM_EVENT_FORMAT_LOST)) { 81853a5a1b3Sopenharmony_ci /* Let client know what the running time was when the stream had to be killed */ 81953a5a1b3Sopenharmony_ci pa_usec_t stream_time; 82053a5a1b3Sopenharmony_ci if (pa_stream_get_time(s, &stream_time) == 0) 82153a5a1b3Sopenharmony_ci pa_proplist_setf(pl, "stream-time", "%llu", (unsigned long long) stream_time); 82253a5a1b3Sopenharmony_ci } 82353a5a1b3Sopenharmony_ci 82453a5a1b3Sopenharmony_ci if (s->event_callback) 82553a5a1b3Sopenharmony_ci s->event_callback(s, event, pl, s->event_userdata); 82653a5a1b3Sopenharmony_ci 82753a5a1b3Sopenharmony_cifinish: 82853a5a1b3Sopenharmony_ci pa_context_unref(c); 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci if (pl) 83153a5a1b3Sopenharmony_ci pa_proplist_free(pl); 83253a5a1b3Sopenharmony_ci} 83353a5a1b3Sopenharmony_ci 83453a5a1b3Sopenharmony_civoid pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 83553a5a1b3Sopenharmony_ci pa_stream *s; 83653a5a1b3Sopenharmony_ci pa_context *c = userdata; 83753a5a1b3Sopenharmony_ci uint32_t bytes, channel; 83853a5a1b3Sopenharmony_ci 83953a5a1b3Sopenharmony_ci pa_assert(pd); 84053a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_REQUEST); 84153a5a1b3Sopenharmony_ci pa_assert(t); 84253a5a1b3Sopenharmony_ci pa_assert(c); 84353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 84453a5a1b3Sopenharmony_ci 84553a5a1b3Sopenharmony_ci pa_context_ref(c); 84653a5a1b3Sopenharmony_ci 84753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 84853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &bytes) < 0 || 84953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 85053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 85153a5a1b3Sopenharmony_ci goto finish; 85253a5a1b3Sopenharmony_ci } 85353a5a1b3Sopenharmony_ci 85453a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel)))) 85553a5a1b3Sopenharmony_ci goto finish; 85653a5a1b3Sopenharmony_ci 85753a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 85853a5a1b3Sopenharmony_ci goto finish; 85953a5a1b3Sopenharmony_ci 86053a5a1b3Sopenharmony_ci s->requested_bytes += bytes; 86153a5a1b3Sopenharmony_ci 86253a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 86353a5a1b3Sopenharmony_ci pa_log_debug("got request for %lli, now at %lli", (long long) bytes, (long long) s->requested_bytes); 86453a5a1b3Sopenharmony_ci#endif 86553a5a1b3Sopenharmony_ci 86653a5a1b3Sopenharmony_ci if (s->requested_bytes > 0 && s->write_callback) 86753a5a1b3Sopenharmony_ci s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata); 86853a5a1b3Sopenharmony_ci 86953a5a1b3Sopenharmony_cifinish: 87053a5a1b3Sopenharmony_ci pa_context_unref(c); 87153a5a1b3Sopenharmony_ci} 87253a5a1b3Sopenharmony_ci 87353a5a1b3Sopenharmony_ciint64_t pa_stream_get_underflow_index(const pa_stream *p) { 87453a5a1b3Sopenharmony_ci pa_assert(p); 87553a5a1b3Sopenharmony_ci return p->latest_underrun_at_index; 87653a5a1b3Sopenharmony_ci} 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_civoid pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 87953a5a1b3Sopenharmony_ci pa_stream *s; 88053a5a1b3Sopenharmony_ci pa_context *c = userdata; 88153a5a1b3Sopenharmony_ci uint32_t channel; 88253a5a1b3Sopenharmony_ci int64_t offset = -1; 88353a5a1b3Sopenharmony_ci 88453a5a1b3Sopenharmony_ci pa_assert(pd); 88553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW 88653a5a1b3Sopenharmony_ci || command == PA_COMMAND_UNDERFLOW_OHOS); 88753a5a1b3Sopenharmony_ci pa_assert(t); 88853a5a1b3Sopenharmony_ci pa_assert(c); 88953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 89053a5a1b3Sopenharmony_ci 89153a5a1b3Sopenharmony_ci pa_context_ref(c); 89253a5a1b3Sopenharmony_ci 89353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0) { 89453a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 89553a5a1b3Sopenharmony_ci goto finish; 89653a5a1b3Sopenharmony_ci } 89753a5a1b3Sopenharmony_ci 89853a5a1b3Sopenharmony_ci if (c->version >= 23 && command == PA_COMMAND_UNDERFLOW) { 89953a5a1b3Sopenharmony_ci if (pa_tagstruct_gets64(t, &offset) < 0) { 90053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 90153a5a1b3Sopenharmony_ci goto finish; 90253a5a1b3Sopenharmony_ci } 90353a5a1b3Sopenharmony_ci } 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 90653a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 90753a5a1b3Sopenharmony_ci goto finish; 90853a5a1b3Sopenharmony_ci } 90953a5a1b3Sopenharmony_ci 91053a5a1b3Sopenharmony_ci if (!(s = pa_hashmap_get(c->playback_streams, PA_UINT32_TO_PTR(channel)))) 91153a5a1b3Sopenharmony_ci goto finish; 91253a5a1b3Sopenharmony_ci 91353a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 91453a5a1b3Sopenharmony_ci goto finish; 91553a5a1b3Sopenharmony_ci 91653a5a1b3Sopenharmony_ci if (command == PA_COMMAND_UNDERFLOW_OHOS) { 91753a5a1b3Sopenharmony_ci if (s->underflow_ohos_callback) { 91853a5a1b3Sopenharmony_ci s->underflow_ohos_callback(s, s->underflow_ohos_userdata); 91953a5a1b3Sopenharmony_ci } 92053a5a1b3Sopenharmony_ci goto finish; 92153a5a1b3Sopenharmony_ci } 92253a5a1b3Sopenharmony_ci 92353a5a1b3Sopenharmony_ci if (offset != -1) 92453a5a1b3Sopenharmony_ci s->latest_underrun_at_index = offset; 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_ci if (s->buffer_attr.prebuf > 0) 92753a5a1b3Sopenharmony_ci check_smoother_status(s, true, false, true); 92853a5a1b3Sopenharmony_ci 92953a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 93053a5a1b3Sopenharmony_ci 93153a5a1b3Sopenharmony_ci if (command == PA_COMMAND_OVERFLOW) { 93253a5a1b3Sopenharmony_ci if (s->overflow_callback) 93353a5a1b3Sopenharmony_ci s->overflow_callback(s, s->overflow_userdata); 93453a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_UNDERFLOW) { 93553a5a1b3Sopenharmony_ci if (s->underflow_callback) 93653a5a1b3Sopenharmony_ci s->underflow_callback(s, s->underflow_userdata); 93753a5a1b3Sopenharmony_ci } 93853a5a1b3Sopenharmony_ci 93953a5a1b3Sopenharmony_cifinish: 94053a5a1b3Sopenharmony_ci pa_context_unref(c); 94153a5a1b3Sopenharmony_ci} 94253a5a1b3Sopenharmony_ci 94353a5a1b3Sopenharmony_cistatic void invalidate_indexes(pa_stream *s, bool r, bool w) { 94453a5a1b3Sopenharmony_ci pa_assert(s); 94553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 94653a5a1b3Sopenharmony_ci 94753a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 94853a5a1b3Sopenharmony_ci pa_log_debug("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); 94953a5a1b3Sopenharmony_ci#endif 95053a5a1b3Sopenharmony_ci 95153a5a1b3Sopenharmony_ci if (s->state != PA_STREAM_READY) 95253a5a1b3Sopenharmony_ci return; 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci if (w) { 95553a5a1b3Sopenharmony_ci s->write_index_not_before = s->context->ctag; 95653a5a1b3Sopenharmony_ci 95753a5a1b3Sopenharmony_ci if (s->timing_info_valid) 95853a5a1b3Sopenharmony_ci s->timing_info.write_index_corrupt = true; 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 96153a5a1b3Sopenharmony_ci pa_log_debug("write_index invalidated"); 96253a5a1b3Sopenharmony_ci#endif 96353a5a1b3Sopenharmony_ci } 96453a5a1b3Sopenharmony_ci 96553a5a1b3Sopenharmony_ci if (r) { 96653a5a1b3Sopenharmony_ci s->read_index_not_before = s->context->ctag; 96753a5a1b3Sopenharmony_ci 96853a5a1b3Sopenharmony_ci if (s->timing_info_valid) 96953a5a1b3Sopenharmony_ci s->timing_info.read_index_corrupt = true; 97053a5a1b3Sopenharmony_ci 97153a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 97253a5a1b3Sopenharmony_ci pa_log_debug("read_index invalidated"); 97353a5a1b3Sopenharmony_ci#endif 97453a5a1b3Sopenharmony_ci } 97553a5a1b3Sopenharmony_ci 97653a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 97753a5a1b3Sopenharmony_ci} 97853a5a1b3Sopenharmony_ci 97953a5a1b3Sopenharmony_cistatic void auto_timing_update_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) { 98053a5a1b3Sopenharmony_ci pa_stream *s = userdata; 98153a5a1b3Sopenharmony_ci 98253a5a1b3Sopenharmony_ci pa_assert(s); 98353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 98453a5a1b3Sopenharmony_ci 98553a5a1b3Sopenharmony_ci pa_stream_ref(s); 98653a5a1b3Sopenharmony_ci request_auto_timing_update(s, false); 98753a5a1b3Sopenharmony_ci pa_stream_unref(s); 98853a5a1b3Sopenharmony_ci} 98953a5a1b3Sopenharmony_ci 99053a5a1b3Sopenharmony_cistatic void create_stream_complete(pa_stream *s) { 99153a5a1b3Sopenharmony_ci pa_assert(s); 99253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 99353a5a1b3Sopenharmony_ci pa_assert(s->state == PA_STREAM_CREATING); 99453a5a1b3Sopenharmony_ci 99553a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_READY); 99653a5a1b3Sopenharmony_ci 99753a5a1b3Sopenharmony_ci if (s->requested_bytes > 0 && s->write_callback) 99853a5a1b3Sopenharmony_ci s->write_callback(s, (size_t) s->requested_bytes, s->write_userdata); 99953a5a1b3Sopenharmony_ci 100053a5a1b3Sopenharmony_ci if (s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { 100153a5a1b3Sopenharmony_ci s->auto_timing_interval_usec = AUTO_TIMING_INTERVAL_START_USEC; 100253a5a1b3Sopenharmony_ci pa_assert(!s->auto_timing_update_event); 100353a5a1b3Sopenharmony_ci s->auto_timing_update_event = pa_context_rttime_new(s->context, pa_rtclock_now() + s->auto_timing_interval_usec, &auto_timing_update_callback, s); 100453a5a1b3Sopenharmony_ci 100553a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 100653a5a1b3Sopenharmony_ci } 100753a5a1b3Sopenharmony_ci 100853a5a1b3Sopenharmony_ci check_smoother_status(s, true, false, false); 100953a5a1b3Sopenharmony_ci} 101053a5a1b3Sopenharmony_ci 101153a5a1b3Sopenharmony_cistatic void patch_buffer_attr(pa_stream *s, pa_buffer_attr *attr, pa_stream_flags_t *flags) { 101253a5a1b3Sopenharmony_ci const char *e; 101353a5a1b3Sopenharmony_ci 101453a5a1b3Sopenharmony_ci pa_assert(s); 101553a5a1b3Sopenharmony_ci pa_assert(attr); 101653a5a1b3Sopenharmony_ci 101753a5a1b3Sopenharmony_ci if ((e = getenv("PULSE_LATENCY_MSEC"))) { 101853a5a1b3Sopenharmony_ci uint32_t ms; 101953a5a1b3Sopenharmony_ci pa_sample_spec ss; 102053a5a1b3Sopenharmony_ci 102153a5a1b3Sopenharmony_ci pa_sample_spec_init(&ss); 102253a5a1b3Sopenharmony_ci 102353a5a1b3Sopenharmony_ci if (pa_sample_spec_valid(&s->sample_spec)) 102453a5a1b3Sopenharmony_ci ss = s->sample_spec; 102553a5a1b3Sopenharmony_ci else if (s->n_formats == 1) 102653a5a1b3Sopenharmony_ci pa_format_info_to_sample_spec(s->req_formats[0], &ss, NULL); 102753a5a1b3Sopenharmony_ci 102853a5a1b3Sopenharmony_ci if (pa_atou(e, &ms) < 0 || ms <= 0) 102953a5a1b3Sopenharmony_ci pa_log_debug("Failed to parse $PULSE_LATENCY_MSEC: %s", e); 103053a5a1b3Sopenharmony_ci else if (!pa_sample_spec_valid(&s->sample_spec)) 103153a5a1b3Sopenharmony_ci pa_log_debug("Ignoring $PULSE_LATENCY_MSEC: %s (invalid sample spec)", e); 103253a5a1b3Sopenharmony_ci else { 103353a5a1b3Sopenharmony_ci attr->maxlength = (uint32_t) -1; 103453a5a1b3Sopenharmony_ci attr->tlength = pa_usec_to_bytes(ms * PA_USEC_PER_MSEC, &ss); 103553a5a1b3Sopenharmony_ci attr->minreq = (uint32_t) -1; 103653a5a1b3Sopenharmony_ci attr->prebuf = (uint32_t) -1; 103753a5a1b3Sopenharmony_ci attr->fragsize = attr->tlength; 103853a5a1b3Sopenharmony_ci 103953a5a1b3Sopenharmony_ci if (flags) 104053a5a1b3Sopenharmony_ci *flags |= PA_STREAM_ADJUST_LATENCY; 104153a5a1b3Sopenharmony_ci } 104253a5a1b3Sopenharmony_ci } 104353a5a1b3Sopenharmony_ci 104453a5a1b3Sopenharmony_ci if (s->context->version >= 13) 104553a5a1b3Sopenharmony_ci return; 104653a5a1b3Sopenharmony_ci 104753a5a1b3Sopenharmony_ci /* Version older than 0.9.10 didn't do server side buffer_attr 104853a5a1b3Sopenharmony_ci * selection, hence we have to fake it on the client side. */ 104953a5a1b3Sopenharmony_ci 105053a5a1b3Sopenharmony_ci /* We choose fairly conservative values here, to not confuse 105153a5a1b3Sopenharmony_ci * old clients with extremely large playback buffers */ 105253a5a1b3Sopenharmony_ci 105353a5a1b3Sopenharmony_ci if (attr->maxlength == (uint32_t) -1) 105453a5a1b3Sopenharmony_ci attr->maxlength = 4*1024*1024; /* 4MB is the maximum queue length PulseAudio <= 0.9.9 supported. */ 105553a5a1b3Sopenharmony_ci 105653a5a1b3Sopenharmony_ci if (attr->tlength == (uint32_t) -1) 105753a5a1b3Sopenharmony_ci attr->tlength = (uint32_t) pa_usec_to_bytes(250*PA_USEC_PER_MSEC, &s->sample_spec); /* 250ms of buffering */ 105853a5a1b3Sopenharmony_ci 105953a5a1b3Sopenharmony_ci if (attr->minreq == (uint32_t) -1) 106053a5a1b3Sopenharmony_ci attr->minreq = (attr->tlength)/5; /* Ask for more data when there are only 200ms left in the playback buffer */ 106153a5a1b3Sopenharmony_ci 106253a5a1b3Sopenharmony_ci if (attr->prebuf == (uint32_t) -1) 106353a5a1b3Sopenharmony_ci attr->prebuf = attr->tlength; /* Start to play only when the playback is fully filled up once */ 106453a5a1b3Sopenharmony_ci 106553a5a1b3Sopenharmony_ci if (attr->fragsize == (uint32_t) -1) 106653a5a1b3Sopenharmony_ci attr->fragsize = attr->tlength; /* Pass data to the app only when the buffer is filled up once */ 106753a5a1b3Sopenharmony_ci} 106853a5a1b3Sopenharmony_ci 106953a5a1b3Sopenharmony_civoid pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 107053a5a1b3Sopenharmony_ci pa_stream *s = userdata; 107153a5a1b3Sopenharmony_ci uint32_t requested_bytes = 0; 107253a5a1b3Sopenharmony_ci 107353a5a1b3Sopenharmony_ci pa_assert(pd); 107453a5a1b3Sopenharmony_ci pa_assert(s); 107553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 107653a5a1b3Sopenharmony_ci pa_assert(s->state == PA_STREAM_CREATING); 107753a5a1b3Sopenharmony_ci 107853a5a1b3Sopenharmony_ci pa_stream_ref(s); 107953a5a1b3Sopenharmony_ci 108053a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 108153a5a1b3Sopenharmony_ci if (pa_context_handle_error(s->context, command, t, false) < 0) 108253a5a1b3Sopenharmony_ci goto finish; 108353a5a1b3Sopenharmony_ci 108453a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_FAILED); 108553a5a1b3Sopenharmony_ci goto finish; 108653a5a1b3Sopenharmony_ci } 108753a5a1b3Sopenharmony_ci 108853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &s->channel) < 0 || 108953a5a1b3Sopenharmony_ci s->channel == PA_INVALID_INDEX || 109053a5a1b3Sopenharmony_ci ((s->direction != PA_STREAM_UPLOAD) && (pa_tagstruct_getu32(t, &s->stream_index) < 0 || s->stream_index == PA_INVALID_INDEX)) || 109153a5a1b3Sopenharmony_ci ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &requested_bytes) < 0)) { 109253a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 109353a5a1b3Sopenharmony_ci goto finish; 109453a5a1b3Sopenharmony_ci } 109553a5a1b3Sopenharmony_ci 109653a5a1b3Sopenharmony_ci s->requested_bytes = (int64_t) requested_bytes; 109753a5a1b3Sopenharmony_ci 109853a5a1b3Sopenharmony_ci if (s->context->version >= 9) { 109953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 110053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || 110153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || 110253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || 110353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) { 110453a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 110553a5a1b3Sopenharmony_ci goto finish; 110653a5a1b3Sopenharmony_ci } 110753a5a1b3Sopenharmony_ci } else if (s->direction == PA_STREAM_RECORD) { 110853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || 110953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) { 111053a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 111153a5a1b3Sopenharmony_ci goto finish; 111253a5a1b3Sopenharmony_ci } 111353a5a1b3Sopenharmony_ci } 111453a5a1b3Sopenharmony_ci } 111553a5a1b3Sopenharmony_ci 111653a5a1b3Sopenharmony_ci if (s->context->version >= 12 && s->direction != PA_STREAM_UPLOAD) { 111753a5a1b3Sopenharmony_ci pa_sample_spec ss; 111853a5a1b3Sopenharmony_ci pa_channel_map cm; 111953a5a1b3Sopenharmony_ci const char *dn = NULL; 112053a5a1b3Sopenharmony_ci bool suspended; 112153a5a1b3Sopenharmony_ci 112253a5a1b3Sopenharmony_ci if (pa_tagstruct_get_sample_spec(t, &ss) < 0 || 112353a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &cm) < 0 || 112453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &s->device_index) < 0 || 112553a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &dn) < 0 || 112653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0) { 112753a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 112853a5a1b3Sopenharmony_ci goto finish; 112953a5a1b3Sopenharmony_ci } 113053a5a1b3Sopenharmony_ci 113153a5a1b3Sopenharmony_ci if (!dn || s->device_index == PA_INVALID_INDEX || 113253a5a1b3Sopenharmony_ci ss.channels != cm.channels || 113353a5a1b3Sopenharmony_ci !pa_channel_map_valid(&cm) || 113453a5a1b3Sopenharmony_ci !pa_sample_spec_valid(&ss) || 113553a5a1b3Sopenharmony_ci (s->n_formats == 0 && ( 113653a5a1b3Sopenharmony_ci (!(s->flags & PA_STREAM_FIX_FORMAT) && ss.format != s->sample_spec.format) || 113753a5a1b3Sopenharmony_ci (!(s->flags & PA_STREAM_FIX_RATE) && ss.rate != s->sample_spec.rate) || 113853a5a1b3Sopenharmony_ci (!(s->flags & PA_STREAM_FIX_CHANNELS) && !pa_channel_map_equal(&cm, &s->channel_map))))) { 113953a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 114053a5a1b3Sopenharmony_ci goto finish; 114153a5a1b3Sopenharmony_ci } 114253a5a1b3Sopenharmony_ci 114353a5a1b3Sopenharmony_ci pa_xfree(s->device_name); 114453a5a1b3Sopenharmony_ci s->device_name = pa_xstrdup(dn); 114553a5a1b3Sopenharmony_ci s->suspended = suspended; 114653a5a1b3Sopenharmony_ci 114753a5a1b3Sopenharmony_ci s->channel_map = cm; 114853a5a1b3Sopenharmony_ci s->sample_spec = ss; 114953a5a1b3Sopenharmony_ci } 115053a5a1b3Sopenharmony_ci 115153a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 115253a5a1b3Sopenharmony_ci if (s->flags & PA_STREAM_INTERPOLATE_TIMING) 115353a5a1b3Sopenharmony_ci pa_smoother_2_set_sample_spec(s->smoother, pa_rtclock_now(), &s->sample_spec); 115453a5a1b3Sopenharmony_ci#endif 115553a5a1b3Sopenharmony_ci 115653a5a1b3Sopenharmony_ci if (s->context->version >= 13 && s->direction != PA_STREAM_UPLOAD) { 115753a5a1b3Sopenharmony_ci pa_usec_t usec; 115853a5a1b3Sopenharmony_ci 115953a5a1b3Sopenharmony_ci if (pa_tagstruct_get_usec(t, &usec) < 0) { 116053a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 116153a5a1b3Sopenharmony_ci goto finish; 116253a5a1b3Sopenharmony_ci } 116353a5a1b3Sopenharmony_ci 116453a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_RECORD) 116553a5a1b3Sopenharmony_ci s->timing_info.configured_source_usec = usec; 116653a5a1b3Sopenharmony_ci else 116753a5a1b3Sopenharmony_ci s->timing_info.configured_sink_usec = usec; 116853a5a1b3Sopenharmony_ci } 116953a5a1b3Sopenharmony_ci 117053a5a1b3Sopenharmony_ci if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK) 117153a5a1b3Sopenharmony_ci || s->context->version >= 22) { 117253a5a1b3Sopenharmony_ci 117353a5a1b3Sopenharmony_ci pa_format_info *f = pa_format_info_new(); 117453a5a1b3Sopenharmony_ci 117553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, f) < 0 || !pa_format_info_valid(f)) { 117653a5a1b3Sopenharmony_ci pa_format_info_free(f); 117753a5a1b3Sopenharmony_ci if (s->n_formats > 0) { 117853a5a1b3Sopenharmony_ci /* We used the extended API, so we should have got back a proper format */ 117953a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 118053a5a1b3Sopenharmony_ci goto finish; 118153a5a1b3Sopenharmony_ci } 118253a5a1b3Sopenharmony_ci } else 118353a5a1b3Sopenharmony_ci s->format = f; 118453a5a1b3Sopenharmony_ci } 118553a5a1b3Sopenharmony_ci 118653a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 118753a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 118853a5a1b3Sopenharmony_ci goto finish; 118953a5a1b3Sopenharmony_ci } 119053a5a1b3Sopenharmony_ci 119153a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_RECORD) { 119253a5a1b3Sopenharmony_ci pa_assert(!s->record_memblockq); 119353a5a1b3Sopenharmony_ci 119453a5a1b3Sopenharmony_ci s->record_memblockq = pa_memblockq_new( 119553a5a1b3Sopenharmony_ci "client side record memblockq", 119653a5a1b3Sopenharmony_ci 0, 119753a5a1b3Sopenharmony_ci s->buffer_attr.maxlength, 119853a5a1b3Sopenharmony_ci 0, 119953a5a1b3Sopenharmony_ci &s->sample_spec, 120053a5a1b3Sopenharmony_ci 1, 120153a5a1b3Sopenharmony_ci 0, 120253a5a1b3Sopenharmony_ci 0, 120353a5a1b3Sopenharmony_ci NULL); 120453a5a1b3Sopenharmony_ci } 120553a5a1b3Sopenharmony_ci 120653a5a1b3Sopenharmony_ci s->channel_valid = true; 120753a5a1b3Sopenharmony_ci pa_hashmap_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, PA_UINT32_TO_PTR(s->channel), s); 120853a5a1b3Sopenharmony_ci 120953a5a1b3Sopenharmony_ci create_stream_complete(s); 121053a5a1b3Sopenharmony_ci 121153a5a1b3Sopenharmony_cifinish: 121253a5a1b3Sopenharmony_ci pa_stream_unref(s); 121353a5a1b3Sopenharmony_ci} 121453a5a1b3Sopenharmony_ci 121553a5a1b3Sopenharmony_cistatic int create_stream( 121653a5a1b3Sopenharmony_ci pa_stream_direction_t direction, 121753a5a1b3Sopenharmony_ci pa_stream *s, 121853a5a1b3Sopenharmony_ci const char *dev, 121953a5a1b3Sopenharmony_ci const pa_buffer_attr *attr, 122053a5a1b3Sopenharmony_ci pa_stream_flags_t flags, 122153a5a1b3Sopenharmony_ci const pa_cvolume *volume, 122253a5a1b3Sopenharmony_ci pa_stream *sync_stream) { 122353a5a1b3Sopenharmony_ci 122453a5a1b3Sopenharmony_ci pa_tagstruct *t; 122553a5a1b3Sopenharmony_ci uint32_t tag; 122653a5a1b3Sopenharmony_ci bool volume_set = !!volume; 122753a5a1b3Sopenharmony_ci pa_cvolume cv; 122853a5a1b3Sopenharmony_ci uint32_t i; 122953a5a1b3Sopenharmony_ci 123053a5a1b3Sopenharmony_ci pa_assert(s); 123153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 123253a5a1b3Sopenharmony_ci pa_assert(direction == PA_STREAM_PLAYBACK || direction == PA_STREAM_RECORD); 123353a5a1b3Sopenharmony_ci 123453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 123553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); 123653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direct_on_input == PA_INVALID_INDEX || direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); 123753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !(flags & ~(PA_STREAM_START_CORKED| 123853a5a1b3Sopenharmony_ci PA_STREAM_INTERPOLATE_TIMING| 123953a5a1b3Sopenharmony_ci PA_STREAM_NOT_MONOTONIC| 124053a5a1b3Sopenharmony_ci PA_STREAM_AUTO_TIMING_UPDATE| 124153a5a1b3Sopenharmony_ci PA_STREAM_NO_REMAP_CHANNELS| 124253a5a1b3Sopenharmony_ci PA_STREAM_NO_REMIX_CHANNELS| 124353a5a1b3Sopenharmony_ci PA_STREAM_FIX_FORMAT| 124453a5a1b3Sopenharmony_ci PA_STREAM_FIX_RATE| 124553a5a1b3Sopenharmony_ci PA_STREAM_FIX_CHANNELS| 124653a5a1b3Sopenharmony_ci PA_STREAM_DONT_MOVE| 124753a5a1b3Sopenharmony_ci PA_STREAM_VARIABLE_RATE| 124853a5a1b3Sopenharmony_ci PA_STREAM_PEAK_DETECT| 124953a5a1b3Sopenharmony_ci PA_STREAM_START_MUTED| 125053a5a1b3Sopenharmony_ci PA_STREAM_ADJUST_LATENCY| 125153a5a1b3Sopenharmony_ci PA_STREAM_EARLY_REQUESTS| 125253a5a1b3Sopenharmony_ci PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND| 125353a5a1b3Sopenharmony_ci PA_STREAM_START_UNMUTED| 125453a5a1b3Sopenharmony_ci PA_STREAM_FAIL_ON_SUSPEND| 125553a5a1b3Sopenharmony_ci PA_STREAM_RELATIVE_VOLUME| 125653a5a1b3Sopenharmony_ci PA_STREAM_PASSTHROUGH)), PA_ERR_INVALID); 125753a5a1b3Sopenharmony_ci 125853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED); 125953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED); 126053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 126153a5a1b3Sopenharmony_ci /* Although some of the other flags are not supported on older 126253a5a1b3Sopenharmony_ci * version, we don't check for them here, because it doesn't hurt 126353a5a1b3Sopenharmony_ci * when they are passed but actually not supported. This makes 126453a5a1b3Sopenharmony_ci * client development easier */ 126553a5a1b3Sopenharmony_ci 126653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, direction == PA_STREAM_RECORD || !(flags & (PA_STREAM_PEAK_DETECT)), PA_ERR_INVALID); 126753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); 126853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, (flags & (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS)) != (PA_STREAM_ADJUST_LATENCY|PA_STREAM_EARLY_REQUESTS), PA_ERR_INVALID); 126953a5a1b3Sopenharmony_ci 127053a5a1b3Sopenharmony_ci pa_stream_ref(s); 127153a5a1b3Sopenharmony_ci 127253a5a1b3Sopenharmony_ci s->direction = direction; 127353a5a1b3Sopenharmony_ci 127453a5a1b3Sopenharmony_ci if (sync_stream) 127553a5a1b3Sopenharmony_ci s->syncid = sync_stream->syncid; 127653a5a1b3Sopenharmony_ci 127753a5a1b3Sopenharmony_ci if (attr) 127853a5a1b3Sopenharmony_ci s->buffer_attr = *attr; 127953a5a1b3Sopenharmony_ci patch_buffer_attr(s, &s->buffer_attr, &flags); 128053a5a1b3Sopenharmony_ci 128153a5a1b3Sopenharmony_ci s->flags = flags; 128253a5a1b3Sopenharmony_ci s->corked = !!(flags & PA_STREAM_START_CORKED); 128353a5a1b3Sopenharmony_ci 128453a5a1b3Sopenharmony_ci if (flags & PA_STREAM_INTERPOLATE_TIMING) { 128553a5a1b3Sopenharmony_ci pa_usec_t x; 128653a5a1b3Sopenharmony_ci 128753a5a1b3Sopenharmony_ci x = pa_rtclock_now(); 128853a5a1b3Sopenharmony_ci 128953a5a1b3Sopenharmony_ci pa_assert(!s->smoother); 129053a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 129153a5a1b3Sopenharmony_ci s->smoother = pa_smoother_2_new(SMOOTHER_HISTORY_TIME, x, 0, 0); 129253a5a1b3Sopenharmony_ci#else 129353a5a1b3Sopenharmony_ci s->smoother = pa_smoother_new( 129453a5a1b3Sopenharmony_ci SMOOTHER_ADJUST_TIME, 129553a5a1b3Sopenharmony_ci SMOOTHER_HISTORY_TIME, 129653a5a1b3Sopenharmony_ci !(flags & PA_STREAM_NOT_MONOTONIC), 129753a5a1b3Sopenharmony_ci true, 129853a5a1b3Sopenharmony_ci SMOOTHER_MIN_HISTORY, 129953a5a1b3Sopenharmony_ci x, 130053a5a1b3Sopenharmony_ci true); 130153a5a1b3Sopenharmony_ci#endif 130253a5a1b3Sopenharmony_ci } 130353a5a1b3Sopenharmony_ci 130453a5a1b3Sopenharmony_ci if (!dev) 130553a5a1b3Sopenharmony_ci dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; 130653a5a1b3Sopenharmony_ci 130753a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 130853a5a1b3Sopenharmony_ci s->context, 130953a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM), 131053a5a1b3Sopenharmony_ci &tag); 131153a5a1b3Sopenharmony_ci 131253a5a1b3Sopenharmony_ci if (s->context->version < 13) 131353a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME)); 131453a5a1b3Sopenharmony_ci 131553a5a1b3Sopenharmony_ci pa_tagstruct_put( 131653a5a1b3Sopenharmony_ci t, 131753a5a1b3Sopenharmony_ci PA_TAG_SAMPLE_SPEC, &s->sample_spec, 131853a5a1b3Sopenharmony_ci PA_TAG_CHANNEL_MAP, &s->channel_map, 131953a5a1b3Sopenharmony_ci PA_TAG_U32, PA_INVALID_INDEX, 132053a5a1b3Sopenharmony_ci PA_TAG_STRING, dev, 132153a5a1b3Sopenharmony_ci PA_TAG_U32, s->buffer_attr.maxlength, 132253a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, s->corked, 132353a5a1b3Sopenharmony_ci PA_TAG_INVALID); 132453a5a1b3Sopenharmony_ci 132553a5a1b3Sopenharmony_ci if (!volume) { 132653a5a1b3Sopenharmony_ci if (pa_sample_spec_valid(&s->sample_spec)) 132753a5a1b3Sopenharmony_ci volume = pa_cvolume_reset(&cv, s->sample_spec.channels); 132853a5a1b3Sopenharmony_ci else { 132953a5a1b3Sopenharmony_ci /* This is not really relevant, since no volume was set, and 133053a5a1b3Sopenharmony_ci * the real number of channels is embedded in the format_info 133153a5a1b3Sopenharmony_ci * structure */ 133253a5a1b3Sopenharmony_ci volume = pa_cvolume_reset(&cv, PA_CHANNELS_MAX); 133353a5a1b3Sopenharmony_ci } 133453a5a1b3Sopenharmony_ci } 133553a5a1b3Sopenharmony_ci 133653a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 133753a5a1b3Sopenharmony_ci pa_tagstruct_put( 133853a5a1b3Sopenharmony_ci t, 133953a5a1b3Sopenharmony_ci PA_TAG_U32, s->buffer_attr.tlength, 134053a5a1b3Sopenharmony_ci PA_TAG_U32, s->buffer_attr.prebuf, 134153a5a1b3Sopenharmony_ci PA_TAG_U32, s->buffer_attr.minreq, 134253a5a1b3Sopenharmony_ci PA_TAG_U32, s->syncid, 134353a5a1b3Sopenharmony_ci PA_TAG_INVALID); 134453a5a1b3Sopenharmony_ci 134553a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, volume); 134653a5a1b3Sopenharmony_ci } else 134753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.fragsize); 134853a5a1b3Sopenharmony_ci 134953a5a1b3Sopenharmony_ci if (s->context->version >= 12) { 135053a5a1b3Sopenharmony_ci pa_tagstruct_put( 135153a5a1b3Sopenharmony_ci t, 135253a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMAP_CHANNELS, 135353a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_NO_REMIX_CHANNELS, 135453a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_FORMAT, 135553a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_RATE, 135653a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_FIX_CHANNELS, 135753a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_DONT_MOVE, 135853a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_VARIABLE_RATE, 135953a5a1b3Sopenharmony_ci PA_TAG_INVALID); 136053a5a1b3Sopenharmony_ci } 136153a5a1b3Sopenharmony_ci 136253a5a1b3Sopenharmony_ci if (s->context->version >= 13) { 136353a5a1b3Sopenharmony_ci 136453a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 136553a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED); 136653a5a1b3Sopenharmony_ci else 136753a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_PEAK_DETECT); 136853a5a1b3Sopenharmony_ci 136953a5a1b3Sopenharmony_ci pa_tagstruct_put( 137053a5a1b3Sopenharmony_ci t, 137153a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, flags & PA_STREAM_ADJUST_LATENCY, 137253a5a1b3Sopenharmony_ci PA_TAG_PROPLIST, s->proplist, 137353a5a1b3Sopenharmony_ci PA_TAG_INVALID); 137453a5a1b3Sopenharmony_ci 137553a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_RECORD) 137653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->direct_on_input); 137753a5a1b3Sopenharmony_ci } 137853a5a1b3Sopenharmony_ci 137953a5a1b3Sopenharmony_ci if (s->context->version >= 14) { 138053a5a1b3Sopenharmony_ci 138153a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 138253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, volume_set); 138353a5a1b3Sopenharmony_ci 138453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_EARLY_REQUESTS); 138553a5a1b3Sopenharmony_ci } 138653a5a1b3Sopenharmony_ci 138753a5a1b3Sopenharmony_ci if (s->context->version >= 15) { 138853a5a1b3Sopenharmony_ci 138953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 139053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED)); 139153a5a1b3Sopenharmony_ci 139253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND); 139353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_FAIL_ON_SUSPEND); 139453a5a1b3Sopenharmony_ci } 139553a5a1b3Sopenharmony_ci 139653a5a1b3Sopenharmony_ci if (s->context->version >= 17 && s->direction == PA_STREAM_PLAYBACK) 139753a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME); 139853a5a1b3Sopenharmony_ci 139953a5a1b3Sopenharmony_ci if (s->context->version >= 18 && s->direction == PA_STREAM_PLAYBACK) 140053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH)); 140153a5a1b3Sopenharmony_ci 140253a5a1b3Sopenharmony_ci if ((s->context->version >= 21 && s->direction == PA_STREAM_PLAYBACK) 140353a5a1b3Sopenharmony_ci || s->context->version >= 22) { 140453a5a1b3Sopenharmony_ci 140553a5a1b3Sopenharmony_ci pa_tagstruct_putu8(t, s->n_formats); 140653a5a1b3Sopenharmony_ci for (i = 0; i < s->n_formats; i++) 140753a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(t, s->req_formats[i]); 140853a5a1b3Sopenharmony_ci } 140953a5a1b3Sopenharmony_ci 141053a5a1b3Sopenharmony_ci if (s->context->version >= 22 && s->direction == PA_STREAM_RECORD) { 141153a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, volume); 141253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_START_MUTED); 141353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, volume_set); 141453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED)); 141553a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & PA_STREAM_RELATIVE_VOLUME); 141653a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, flags & (PA_STREAM_PASSTHROUGH)); 141753a5a1b3Sopenharmony_ci } 141853a5a1b3Sopenharmony_ci 141953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 142053a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); 142153a5a1b3Sopenharmony_ci 142253a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_CREATING); 142353a5a1b3Sopenharmony_ci 142453a5a1b3Sopenharmony_ci pa_stream_unref(s); 142553a5a1b3Sopenharmony_ci return 0; 142653a5a1b3Sopenharmony_ci} 142753a5a1b3Sopenharmony_ci 142853a5a1b3Sopenharmony_ciint pa_stream_connect_playback( 142953a5a1b3Sopenharmony_ci pa_stream *s, 143053a5a1b3Sopenharmony_ci const char *dev, 143153a5a1b3Sopenharmony_ci const pa_buffer_attr *attr, 143253a5a1b3Sopenharmony_ci pa_stream_flags_t flags, 143353a5a1b3Sopenharmony_ci const pa_cvolume *volume, 143453a5a1b3Sopenharmony_ci pa_stream *sync_stream) { 143553a5a1b3Sopenharmony_ci 143653a5a1b3Sopenharmony_ci pa_assert(s); 143753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 143853a5a1b3Sopenharmony_ci 143953a5a1b3Sopenharmony_ci return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); 144053a5a1b3Sopenharmony_ci} 144153a5a1b3Sopenharmony_ci 144253a5a1b3Sopenharmony_ciint pa_stream_connect_record( 144353a5a1b3Sopenharmony_ci pa_stream *s, 144453a5a1b3Sopenharmony_ci const char *dev, 144553a5a1b3Sopenharmony_ci const pa_buffer_attr *attr, 144653a5a1b3Sopenharmony_ci pa_stream_flags_t flags) { 144753a5a1b3Sopenharmony_ci 144853a5a1b3Sopenharmony_ci pa_assert(s); 144953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 145053a5a1b3Sopenharmony_ci 145153a5a1b3Sopenharmony_ci return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); 145253a5a1b3Sopenharmony_ci} 145353a5a1b3Sopenharmony_ci 145453a5a1b3Sopenharmony_ciint pa_stream_begin_write( 145553a5a1b3Sopenharmony_ci pa_stream *s, 145653a5a1b3Sopenharmony_ci void **data, 145753a5a1b3Sopenharmony_ci size_t *nbytes) { 145853a5a1b3Sopenharmony_ci 145953a5a1b3Sopenharmony_ci pa_assert(s); 146053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 146153a5a1b3Sopenharmony_ci 146253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 146353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 146453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 146553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, data, PA_ERR_INVALID); 146653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, nbytes && *nbytes != 0, PA_ERR_INVALID); 146753a5a1b3Sopenharmony_ci 146853a5a1b3Sopenharmony_ci if (*nbytes != (size_t) -1) { 146953a5a1b3Sopenharmony_ci size_t m, fs; 147053a5a1b3Sopenharmony_ci 147153a5a1b3Sopenharmony_ci m = pa_mempool_block_size_max(s->context->mempool); 147253a5a1b3Sopenharmony_ci fs = pa_frame_size(&s->sample_spec); 147353a5a1b3Sopenharmony_ci 147453a5a1b3Sopenharmony_ci m = (m / fs) * fs; 147553a5a1b3Sopenharmony_ci if (*nbytes > m) 147653a5a1b3Sopenharmony_ci *nbytes = m; 147753a5a1b3Sopenharmony_ci } 147853a5a1b3Sopenharmony_ci 147953a5a1b3Sopenharmony_ci if (!s->write_memblock) { 148053a5a1b3Sopenharmony_ci s->write_memblock = pa_memblock_new(s->context->mempool, *nbytes); 148153a5a1b3Sopenharmony_ci s->write_data = pa_memblock_acquire(s->write_memblock); 148253a5a1b3Sopenharmony_ci } 148353a5a1b3Sopenharmony_ci 148453a5a1b3Sopenharmony_ci *data = s->write_data; 148553a5a1b3Sopenharmony_ci *nbytes = pa_memblock_get_length(s->write_memblock); 148653a5a1b3Sopenharmony_ci 148753a5a1b3Sopenharmony_ci return 0; 148853a5a1b3Sopenharmony_ci} 148953a5a1b3Sopenharmony_ci 149053a5a1b3Sopenharmony_ciint pa_stream_cancel_write( 149153a5a1b3Sopenharmony_ci pa_stream *s) { 149253a5a1b3Sopenharmony_ci 149353a5a1b3Sopenharmony_ci pa_assert(s); 149453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 149553a5a1b3Sopenharmony_ci 149653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 149753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 149853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 149953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->write_memblock, PA_ERR_BADSTATE); 150053a5a1b3Sopenharmony_ci 150153a5a1b3Sopenharmony_ci pa_assert(s->write_data); 150253a5a1b3Sopenharmony_ci 150353a5a1b3Sopenharmony_ci pa_memblock_release(s->write_memblock); 150453a5a1b3Sopenharmony_ci pa_memblock_unref(s->write_memblock); 150553a5a1b3Sopenharmony_ci s->write_memblock = NULL; 150653a5a1b3Sopenharmony_ci s->write_data = NULL; 150753a5a1b3Sopenharmony_ci 150853a5a1b3Sopenharmony_ci return 0; 150953a5a1b3Sopenharmony_ci} 151053a5a1b3Sopenharmony_ci 151153a5a1b3Sopenharmony_ciint pa_stream_write_ext_free( 151253a5a1b3Sopenharmony_ci pa_stream *s, 151353a5a1b3Sopenharmony_ci const void *data, 151453a5a1b3Sopenharmony_ci size_t length, 151553a5a1b3Sopenharmony_ci pa_free_cb_t free_cb, 151653a5a1b3Sopenharmony_ci void *free_cb_data, 151753a5a1b3Sopenharmony_ci int64_t offset, 151853a5a1b3Sopenharmony_ci pa_seek_mode_t seek) { 151953a5a1b3Sopenharmony_ci 152053a5a1b3Sopenharmony_ci pa_assert(s); 152153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 152253a5a1b3Sopenharmony_ci pa_assert(data); 152353a5a1b3Sopenharmony_ci 152453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 152553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 152653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 152753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); 152853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); 152953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, 153053a5a1b3Sopenharmony_ci !s->write_memblock || 153153a5a1b3Sopenharmony_ci ((data >= s->write_data) && 153253a5a1b3Sopenharmony_ci ((const char*) data + length <= (const char*) s->write_data + pa_memblock_get_length(s->write_memblock))), 153353a5a1b3Sopenharmony_ci PA_ERR_INVALID); 153453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, offset % pa_frame_size(&s->sample_spec) == 0, PA_ERR_INVALID); 153553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, length % pa_frame_size(&s->sample_spec) == 0, PA_ERR_INVALID); 153653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !free_cb || !s->write_memblock, PA_ERR_INVALID); 153753a5a1b3Sopenharmony_ci 153853a5a1b3Sopenharmony_ci if (s->write_memblock) { 153953a5a1b3Sopenharmony_ci pa_memchunk chunk; 154053a5a1b3Sopenharmony_ci 154153a5a1b3Sopenharmony_ci /* pa_stream_write_begin() was called before */ 154253a5a1b3Sopenharmony_ci 154353a5a1b3Sopenharmony_ci pa_memblock_release(s->write_memblock); 154453a5a1b3Sopenharmony_ci 154553a5a1b3Sopenharmony_ci chunk.memblock = s->write_memblock; 154653a5a1b3Sopenharmony_ci chunk.index = (const char *) data - (const char *) s->write_data; 154753a5a1b3Sopenharmony_ci chunk.length = length; 154853a5a1b3Sopenharmony_ci 154953a5a1b3Sopenharmony_ci s->write_memblock = NULL; 155053a5a1b3Sopenharmony_ci s->write_data = NULL; 155153a5a1b3Sopenharmony_ci 155253a5a1b3Sopenharmony_ci pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); 155353a5a1b3Sopenharmony_ci pa_memblock_unref(chunk.memblock); 155453a5a1b3Sopenharmony_ci 155553a5a1b3Sopenharmony_ci } else { 155653a5a1b3Sopenharmony_ci pa_seek_mode_t t_seek = seek; 155753a5a1b3Sopenharmony_ci int64_t t_offset = offset; 155853a5a1b3Sopenharmony_ci size_t t_length = length; 155953a5a1b3Sopenharmony_ci const void *t_data = data; 156053a5a1b3Sopenharmony_ci 156153a5a1b3Sopenharmony_ci /* pa_stream_write_begin() was not called before */ 156253a5a1b3Sopenharmony_ci 156353a5a1b3Sopenharmony_ci while (t_length > 0) { 156453a5a1b3Sopenharmony_ci pa_memchunk chunk; 156553a5a1b3Sopenharmony_ci 156653a5a1b3Sopenharmony_ci chunk.index = 0; 156753a5a1b3Sopenharmony_ci 156853a5a1b3Sopenharmony_ci if (free_cb && !pa_pstream_get_shm(s->context->pstream)) { 156953a5a1b3Sopenharmony_ci chunk.memblock = pa_memblock_new_user(s->context->mempool, (void*) t_data, t_length, free_cb, free_cb_data, 1); 157053a5a1b3Sopenharmony_ci chunk.length = t_length; 157153a5a1b3Sopenharmony_ci } else { 157253a5a1b3Sopenharmony_ci void *d; 157353a5a1b3Sopenharmony_ci size_t blk_size_max; 157453a5a1b3Sopenharmony_ci 157553a5a1b3Sopenharmony_ci /* Break large audio streams into _aligned_ blocks or the 157653a5a1b3Sopenharmony_ci * other endpoint will happily discard them upon arrival. */ 157753a5a1b3Sopenharmony_ci blk_size_max = pa_frame_align(pa_mempool_block_size_max(s->context->mempool), &s->sample_spec); 157853a5a1b3Sopenharmony_ci chunk.length = PA_MIN(t_length, blk_size_max); 157953a5a1b3Sopenharmony_ci chunk.memblock = pa_memblock_new(s->context->mempool, chunk.length); 158053a5a1b3Sopenharmony_ci 158153a5a1b3Sopenharmony_ci d = pa_memblock_acquire(chunk.memblock); 158253a5a1b3Sopenharmony_ci memcpy(d, t_data, chunk.length); 158353a5a1b3Sopenharmony_ci pa_memblock_release(chunk.memblock); 158453a5a1b3Sopenharmony_ci } 158553a5a1b3Sopenharmony_ci 158653a5a1b3Sopenharmony_ci pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); 158753a5a1b3Sopenharmony_ci 158853a5a1b3Sopenharmony_ci t_offset = 0; 158953a5a1b3Sopenharmony_ci t_seek = PA_SEEK_RELATIVE; 159053a5a1b3Sopenharmony_ci 159153a5a1b3Sopenharmony_ci t_data = (const uint8_t*) t_data + chunk.length; 159253a5a1b3Sopenharmony_ci t_length -= chunk.length; 159353a5a1b3Sopenharmony_ci 159453a5a1b3Sopenharmony_ci pa_memblock_unref(chunk.memblock); 159553a5a1b3Sopenharmony_ci } 159653a5a1b3Sopenharmony_ci 159753a5a1b3Sopenharmony_ci if (free_cb && pa_pstream_get_shm(s->context->pstream)) 159853a5a1b3Sopenharmony_ci free_cb(free_cb_data); 159953a5a1b3Sopenharmony_ci } 160053a5a1b3Sopenharmony_ci 160153a5a1b3Sopenharmony_ci /* This is obviously wrong since we ignore the seeking index . But 160253a5a1b3Sopenharmony_ci * that's OK, the server side applies the same error */ 160353a5a1b3Sopenharmony_ci s->requested_bytes -= (seek == PA_SEEK_RELATIVE ? offset : 0) + (int64_t) length; 160453a5a1b3Sopenharmony_ci 160553a5a1b3Sopenharmony_ci#ifdef STREAM_DEBUG 160653a5a1b3Sopenharmony_ci pa_log_debug("wrote %lli, now at %lli", (long long) length, (long long) s->requested_bytes); 160753a5a1b3Sopenharmony_ci#endif 160853a5a1b3Sopenharmony_ci 160953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 161053a5a1b3Sopenharmony_ci 161153a5a1b3Sopenharmony_ci /* Update latency request correction */ 161253a5a1b3Sopenharmony_ci if (s->write_index_corrections[s->current_write_index_correction].valid) { 161353a5a1b3Sopenharmony_ci 161453a5a1b3Sopenharmony_ci if (seek == PA_SEEK_ABSOLUTE) { 161553a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].corrupt = false; 161653a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].absolute = true; 161753a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].value = offset + (int64_t) length; 161853a5a1b3Sopenharmony_ci } else if (seek == PA_SEEK_RELATIVE) { 161953a5a1b3Sopenharmony_ci if (!s->write_index_corrections[s->current_write_index_correction].corrupt) 162053a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].value += offset + (int64_t) length; 162153a5a1b3Sopenharmony_ci } else 162253a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].corrupt = true; 162353a5a1b3Sopenharmony_ci } 162453a5a1b3Sopenharmony_ci 162553a5a1b3Sopenharmony_ci /* Update the write index in the already available latency data */ 162653a5a1b3Sopenharmony_ci if (s->timing_info_valid) { 162753a5a1b3Sopenharmony_ci 162853a5a1b3Sopenharmony_ci if (seek == PA_SEEK_ABSOLUTE) { 162953a5a1b3Sopenharmony_ci s->timing_info.write_index_corrupt = false; 163053a5a1b3Sopenharmony_ci s->timing_info.write_index = offset + (int64_t) length; 163153a5a1b3Sopenharmony_ci } else if (seek == PA_SEEK_RELATIVE) { 163253a5a1b3Sopenharmony_ci if (!s->timing_info.write_index_corrupt) 163353a5a1b3Sopenharmony_ci s->timing_info.write_index += offset + (int64_t) length; 163453a5a1b3Sopenharmony_ci } else 163553a5a1b3Sopenharmony_ci s->timing_info.write_index_corrupt = true; 163653a5a1b3Sopenharmony_ci } 163753a5a1b3Sopenharmony_ci 163853a5a1b3Sopenharmony_ci if (!s->timing_info_valid || s->timing_info.write_index_corrupt) 163953a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 164053a5a1b3Sopenharmony_ci } 164153a5a1b3Sopenharmony_ci 164253a5a1b3Sopenharmony_ci return 0; 164353a5a1b3Sopenharmony_ci} 164453a5a1b3Sopenharmony_ci 164553a5a1b3Sopenharmony_ciint pa_stream_write( 164653a5a1b3Sopenharmony_ci pa_stream *s, 164753a5a1b3Sopenharmony_ci const void *data, 164853a5a1b3Sopenharmony_ci size_t length, 164953a5a1b3Sopenharmony_ci pa_free_cb_t free_cb, 165053a5a1b3Sopenharmony_ci int64_t offset, 165153a5a1b3Sopenharmony_ci pa_seek_mode_t seek) { 165253a5a1b3Sopenharmony_ci 165353a5a1b3Sopenharmony_ci return pa_stream_write_ext_free(s, data, length, free_cb, (void*) data, offset, seek); 165453a5a1b3Sopenharmony_ci} 165553a5a1b3Sopenharmony_ci 165653a5a1b3Sopenharmony_ciint pa_stream_peek(pa_stream *s, const void **data, size_t *length) { 165753a5a1b3Sopenharmony_ci pa_assert(s); 165853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 165953a5a1b3Sopenharmony_ci pa_assert(data); 166053a5a1b3Sopenharmony_ci pa_assert(length); 166153a5a1b3Sopenharmony_ci 166253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 166353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 166453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); 166553a5a1b3Sopenharmony_ci 166653a5a1b3Sopenharmony_ci if (!s->peek_memchunk.memblock) { 166753a5a1b3Sopenharmony_ci 166853a5a1b3Sopenharmony_ci if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { 166953a5a1b3Sopenharmony_ci /* record_memblockq is empty. */ 167053a5a1b3Sopenharmony_ci *data = NULL; 167153a5a1b3Sopenharmony_ci *length = 0; 167253a5a1b3Sopenharmony_ci return 0; 167353a5a1b3Sopenharmony_ci 167453a5a1b3Sopenharmony_ci } else if (!s->peek_memchunk.memblock) { 167553a5a1b3Sopenharmony_ci /* record_memblockq isn't empty, but it doesn't have any data at 167653a5a1b3Sopenharmony_ci * the current read index. */ 167753a5a1b3Sopenharmony_ci *data = NULL; 167853a5a1b3Sopenharmony_ci *length = s->peek_memchunk.length; 167953a5a1b3Sopenharmony_ci return 0; 168053a5a1b3Sopenharmony_ci } 168153a5a1b3Sopenharmony_ci 168253a5a1b3Sopenharmony_ci s->peek_data = pa_memblock_acquire(s->peek_memchunk.memblock); 168353a5a1b3Sopenharmony_ci } 168453a5a1b3Sopenharmony_ci 168553a5a1b3Sopenharmony_ci pa_assert(s->peek_data); 168653a5a1b3Sopenharmony_ci *data = (uint8_t*) s->peek_data + s->peek_memchunk.index; 168753a5a1b3Sopenharmony_ci *length = s->peek_memchunk.length; 168853a5a1b3Sopenharmony_ci return 0; 168953a5a1b3Sopenharmony_ci} 169053a5a1b3Sopenharmony_ci 169153a5a1b3Sopenharmony_ciint pa_stream_drop(pa_stream *s) { 169253a5a1b3Sopenharmony_ci pa_assert(s); 169353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 169453a5a1b3Sopenharmony_ci 169553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 169653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 169753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); 169853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->peek_memchunk.length > 0, PA_ERR_BADSTATE); 169953a5a1b3Sopenharmony_ci 170053a5a1b3Sopenharmony_ci pa_memblockq_drop(s->record_memblockq, s->peek_memchunk.length); 170153a5a1b3Sopenharmony_ci 170253a5a1b3Sopenharmony_ci /* Fix the simulated local read index */ 170353a5a1b3Sopenharmony_ci if (s->timing_info_valid && !s->timing_info.read_index_corrupt) 170453a5a1b3Sopenharmony_ci s->timing_info.read_index += (int64_t) s->peek_memchunk.length; 170553a5a1b3Sopenharmony_ci 170653a5a1b3Sopenharmony_ci if (s->peek_memchunk.memblock) { 170753a5a1b3Sopenharmony_ci pa_assert(s->peek_data); 170853a5a1b3Sopenharmony_ci s->peek_data = NULL; 170953a5a1b3Sopenharmony_ci pa_memblock_release(s->peek_memchunk.memblock); 171053a5a1b3Sopenharmony_ci pa_memblock_unref(s->peek_memchunk.memblock); 171153a5a1b3Sopenharmony_ci } 171253a5a1b3Sopenharmony_ci 171353a5a1b3Sopenharmony_ci pa_memchunk_reset(&s->peek_memchunk); 171453a5a1b3Sopenharmony_ci 171553a5a1b3Sopenharmony_ci return 0; 171653a5a1b3Sopenharmony_ci} 171753a5a1b3Sopenharmony_ci 171853a5a1b3Sopenharmony_cisize_t pa_stream_writable_size(const pa_stream *s) { 171953a5a1b3Sopenharmony_ci pa_assert(s); 172053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 172153a5a1b3Sopenharmony_ci 172253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1); 172353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); 172453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); 172553a5a1b3Sopenharmony_ci 172653a5a1b3Sopenharmony_ci return s->requested_bytes > 0 ? (size_t) s->requested_bytes : 0; 172753a5a1b3Sopenharmony_ci} 172853a5a1b3Sopenharmony_ci 172953a5a1b3Sopenharmony_cisize_t pa_stream_readable_size(const pa_stream *s) { 173053a5a1b3Sopenharmony_ci pa_assert(s); 173153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 173253a5a1b3Sopenharmony_ci 173353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1); 173453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); 173553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); 173653a5a1b3Sopenharmony_ci 173753a5a1b3Sopenharmony_ci return pa_memblockq_get_length(s->record_memblockq); 173853a5a1b3Sopenharmony_ci} 173953a5a1b3Sopenharmony_ci 174053a5a1b3Sopenharmony_cipa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { 174153a5a1b3Sopenharmony_ci pa_operation *o; 174253a5a1b3Sopenharmony_ci pa_tagstruct *t; 174353a5a1b3Sopenharmony_ci uint32_t tag; 174453a5a1b3Sopenharmony_ci 174553a5a1b3Sopenharmony_ci pa_assert(s); 174653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 174753a5a1b3Sopenharmony_ci 174853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 174953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 175053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); 175153a5a1b3Sopenharmony_ci 175253a5a1b3Sopenharmony_ci /* Ask for a timing update before we cork/uncork to get the best 175353a5a1b3Sopenharmony_ci * accuracy for the transport latency suitable for the 175453a5a1b3Sopenharmony_ci * check_smoother_status() call in the started callback */ 175553a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 175653a5a1b3Sopenharmony_ci 175753a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 175853a5a1b3Sopenharmony_ci 175953a5a1b3Sopenharmony_ci t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); 176053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 176153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 176253a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 176353a5a1b3Sopenharmony_ci 176453a5a1b3Sopenharmony_ci /* This might cause the read index to continue again, hence 176553a5a1b3Sopenharmony_ci * let's request a timing update */ 176653a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 176753a5a1b3Sopenharmony_ci 176853a5a1b3Sopenharmony_ci return o; 176953a5a1b3Sopenharmony_ci} 177053a5a1b3Sopenharmony_ci 177153a5a1b3Sopenharmony_cistatic pa_usec_t calc_time(const pa_stream *s, bool ignore_transport) { 177253a5a1b3Sopenharmony_ci pa_usec_t usec; 177353a5a1b3Sopenharmony_ci 177453a5a1b3Sopenharmony_ci pa_assert(s); 177553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 177653a5a1b3Sopenharmony_ci pa_assert(s->state == PA_STREAM_READY); 177753a5a1b3Sopenharmony_ci pa_assert(s->direction != PA_STREAM_UPLOAD); 177853a5a1b3Sopenharmony_ci pa_assert(s->timing_info_valid); 177953a5a1b3Sopenharmony_ci pa_assert(s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt); 178053a5a1b3Sopenharmony_ci pa_assert(s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt); 178153a5a1b3Sopenharmony_ci 178253a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 178353a5a1b3Sopenharmony_ci /* The last byte that was written into the output device 178453a5a1b3Sopenharmony_ci * had this time value associated */ 178553a5a1b3Sopenharmony_ci usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); 178653a5a1b3Sopenharmony_ci 178753a5a1b3Sopenharmony_ci if (!s->corked && !s->suspended) { 178853a5a1b3Sopenharmony_ci 178953a5a1b3Sopenharmony_ci if (!ignore_transport) 179053a5a1b3Sopenharmony_ci /* Because the latency info took a little time to come 179153a5a1b3Sopenharmony_ci * to us, we assume that the real output time is actually 179253a5a1b3Sopenharmony_ci * a little ahead */ 179353a5a1b3Sopenharmony_ci usec += s->timing_info.transport_usec; 179453a5a1b3Sopenharmony_ci 179553a5a1b3Sopenharmony_ci /* However, the output device usually maintains a buffer 179653a5a1b3Sopenharmony_ci too, hence the real sample currently played is a little 179753a5a1b3Sopenharmony_ci back */ 179853a5a1b3Sopenharmony_ci if (s->timing_info.sink_usec >= usec) 179953a5a1b3Sopenharmony_ci usec = 0; 180053a5a1b3Sopenharmony_ci else 180153a5a1b3Sopenharmony_ci usec -= s->timing_info.sink_usec; 180253a5a1b3Sopenharmony_ci } 180353a5a1b3Sopenharmony_ci 180453a5a1b3Sopenharmony_ci } else { 180553a5a1b3Sopenharmony_ci pa_assert(s->direction == PA_STREAM_RECORD); 180653a5a1b3Sopenharmony_ci 180753a5a1b3Sopenharmony_ci /* The last byte written into the server side queue had 180853a5a1b3Sopenharmony_ci * this time value associated */ 180953a5a1b3Sopenharmony_ci usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); 181053a5a1b3Sopenharmony_ci 181153a5a1b3Sopenharmony_ci if (!s->corked && !s->suspended) { 181253a5a1b3Sopenharmony_ci 181353a5a1b3Sopenharmony_ci if (!ignore_transport) 181453a5a1b3Sopenharmony_ci /* Add transport latency */ 181553a5a1b3Sopenharmony_ci usec += s->timing_info.transport_usec; 181653a5a1b3Sopenharmony_ci 181753a5a1b3Sopenharmony_ci /* Add latency of data in device buffer */ 181853a5a1b3Sopenharmony_ci usec += s->timing_info.source_usec; 181953a5a1b3Sopenharmony_ci 182053a5a1b3Sopenharmony_ci /* If this is a monitor source, we need to correct the 182153a5a1b3Sopenharmony_ci * time by the playback device buffer */ 182253a5a1b3Sopenharmony_ci if (s->timing_info.sink_usec >= usec) 182353a5a1b3Sopenharmony_ci usec = 0; 182453a5a1b3Sopenharmony_ci else 182553a5a1b3Sopenharmony_ci usec -= s->timing_info.sink_usec; 182653a5a1b3Sopenharmony_ci } 182753a5a1b3Sopenharmony_ci } 182853a5a1b3Sopenharmony_ci 182953a5a1b3Sopenharmony_ci return usec; 183053a5a1b3Sopenharmony_ci} 183153a5a1b3Sopenharmony_ci 183253a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 183353a5a1b3Sopenharmony_cistatic inline uint64_t calc_bytes(pa_stream *s, bool ignore_transport) { 183453a5a1b3Sopenharmony_ci return (uint64_t)(calc_time(s, ignore_transport) * s->sample_spec.rate / PA_USEC_PER_SEC * pa_frame_size(&s->sample_spec)); 183553a5a1b3Sopenharmony_ci} 183653a5a1b3Sopenharmony_ci#endif 183753a5a1b3Sopenharmony_ci 183853a5a1b3Sopenharmony_cistatic void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 183953a5a1b3Sopenharmony_ci pa_operation *o = userdata; 184053a5a1b3Sopenharmony_ci struct timeval local, remote, now; 184153a5a1b3Sopenharmony_ci pa_timing_info *i; 184253a5a1b3Sopenharmony_ci bool playing = false; 184353a5a1b3Sopenharmony_ci uint64_t underrun_for = 0, playing_for = 0; 184453a5a1b3Sopenharmony_ci 184553a5a1b3Sopenharmony_ci pa_assert(pd); 184653a5a1b3Sopenharmony_ci pa_assert(o); 184753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 184853a5a1b3Sopenharmony_ci 184953a5a1b3Sopenharmony_ci if (!o->context || !o->stream) 185053a5a1b3Sopenharmony_ci goto finish; 185153a5a1b3Sopenharmony_ci 185253a5a1b3Sopenharmony_ci i = &o->stream->timing_info; 185353a5a1b3Sopenharmony_ci 185453a5a1b3Sopenharmony_ci o->stream->timing_info_valid = false; 185553a5a1b3Sopenharmony_ci i->write_index_corrupt = true; 185653a5a1b3Sopenharmony_ci i->read_index_corrupt = true; 185753a5a1b3Sopenharmony_ci 185853a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 185953a5a1b3Sopenharmony_ci if (pa_context_handle_error(o->context, command, t, false) < 0) 186053a5a1b3Sopenharmony_ci goto finish; 186153a5a1b3Sopenharmony_ci 186253a5a1b3Sopenharmony_ci } else { 186353a5a1b3Sopenharmony_ci 186453a5a1b3Sopenharmony_ci if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || 186553a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &i->source_usec) < 0 || 186653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &playing) < 0 || 186753a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &local) < 0 || 186853a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &remote) < 0 || 186953a5a1b3Sopenharmony_ci pa_tagstruct_gets64(t, &i->write_index) < 0 || 187053a5a1b3Sopenharmony_ci pa_tagstruct_gets64(t, &i->read_index) < 0) { 187153a5a1b3Sopenharmony_ci 187253a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 187353a5a1b3Sopenharmony_ci goto finish; 187453a5a1b3Sopenharmony_ci } 187553a5a1b3Sopenharmony_ci 187653a5a1b3Sopenharmony_ci if (o->context->version >= 13 && 187753a5a1b3Sopenharmony_ci o->stream->direction == PA_STREAM_PLAYBACK) 187853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu64(t, &underrun_for) < 0 || 187953a5a1b3Sopenharmony_ci pa_tagstruct_getu64(t, &playing_for) < 0) { 188053a5a1b3Sopenharmony_ci 188153a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 188253a5a1b3Sopenharmony_ci goto finish; 188353a5a1b3Sopenharmony_ci } 188453a5a1b3Sopenharmony_ci 188553a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 188653a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 188753a5a1b3Sopenharmony_ci goto finish; 188853a5a1b3Sopenharmony_ci } 188953a5a1b3Sopenharmony_ci o->stream->timing_info_valid = true; 189053a5a1b3Sopenharmony_ci i->write_index_corrupt = false; 189153a5a1b3Sopenharmony_ci i->read_index_corrupt = false; 189253a5a1b3Sopenharmony_ci 189353a5a1b3Sopenharmony_ci i->playing = (int) playing; 189453a5a1b3Sopenharmony_ci i->since_underrun = (int64_t) (playing ? playing_for : underrun_for); 189553a5a1b3Sopenharmony_ci 189653a5a1b3Sopenharmony_ci pa_gettimeofday(&now); 189753a5a1b3Sopenharmony_ci 189853a5a1b3Sopenharmony_ci /* Calculate timestamps */ 189953a5a1b3Sopenharmony_ci if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { 190053a5a1b3Sopenharmony_ci /* local and remote seem to have synchronized clocks */ 190153a5a1b3Sopenharmony_ci 190253a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_PLAYBACK) 190353a5a1b3Sopenharmony_ci i->transport_usec = pa_timeval_diff(&remote, &local); 190453a5a1b3Sopenharmony_ci else 190553a5a1b3Sopenharmony_ci i->transport_usec = pa_timeval_diff(&now, &remote); 190653a5a1b3Sopenharmony_ci 190753a5a1b3Sopenharmony_ci i->synchronized_clocks = true; 190853a5a1b3Sopenharmony_ci i->timestamp = remote; 190953a5a1b3Sopenharmony_ci } else { 191053a5a1b3Sopenharmony_ci /* clocks are not synchronized, let's estimate latency then */ 191153a5a1b3Sopenharmony_ci i->transport_usec = pa_timeval_diff(&now, &local)/2; 191253a5a1b3Sopenharmony_ci i->synchronized_clocks = false; 191353a5a1b3Sopenharmony_ci i->timestamp = local; 191453a5a1b3Sopenharmony_ci pa_timeval_add(&i->timestamp, i->transport_usec); 191553a5a1b3Sopenharmony_ci } 191653a5a1b3Sopenharmony_ci 191753a5a1b3Sopenharmony_ci /* Invalidate read and write indexes if necessary */ 191853a5a1b3Sopenharmony_ci if (tag < o->stream->read_index_not_before) 191953a5a1b3Sopenharmony_ci i->read_index_corrupt = true; 192053a5a1b3Sopenharmony_ci 192153a5a1b3Sopenharmony_ci if (tag < o->stream->write_index_not_before) 192253a5a1b3Sopenharmony_ci i->write_index_corrupt = true; 192353a5a1b3Sopenharmony_ci 192453a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_PLAYBACK) { 192553a5a1b3Sopenharmony_ci /* Write index correction */ 192653a5a1b3Sopenharmony_ci 192753a5a1b3Sopenharmony_ci int n, j; 192853a5a1b3Sopenharmony_ci uint32_t ctag = tag; 192953a5a1b3Sopenharmony_ci 193053a5a1b3Sopenharmony_ci /* Go through the saved correction values and add up the 193153a5a1b3Sopenharmony_ci * total correction.*/ 193253a5a1b3Sopenharmony_ci for (n = 0, j = o->stream->current_write_index_correction+1; 193353a5a1b3Sopenharmony_ci n < PA_MAX_WRITE_INDEX_CORRECTIONS; 193453a5a1b3Sopenharmony_ci n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { 193553a5a1b3Sopenharmony_ci 193653a5a1b3Sopenharmony_ci /* Step over invalid data or out-of-date data */ 193753a5a1b3Sopenharmony_ci if (!o->stream->write_index_corrections[j].valid || 193853a5a1b3Sopenharmony_ci o->stream->write_index_corrections[j].tag < ctag) 193953a5a1b3Sopenharmony_ci continue; 194053a5a1b3Sopenharmony_ci 194153a5a1b3Sopenharmony_ci /* Make sure that everything is in order */ 194253a5a1b3Sopenharmony_ci ctag = o->stream->write_index_corrections[j].tag+1; 194353a5a1b3Sopenharmony_ci 194453a5a1b3Sopenharmony_ci /* Now fix the write index */ 194553a5a1b3Sopenharmony_ci if (o->stream->write_index_corrections[j].corrupt) { 194653a5a1b3Sopenharmony_ci /* A corrupting seek was made */ 194753a5a1b3Sopenharmony_ci i->write_index_corrupt = true; 194853a5a1b3Sopenharmony_ci } else if (o->stream->write_index_corrections[j].absolute) { 194953a5a1b3Sopenharmony_ci /* An absolute seek was made */ 195053a5a1b3Sopenharmony_ci i->write_index = o->stream->write_index_corrections[j].value; 195153a5a1b3Sopenharmony_ci i->write_index_corrupt = false; 195253a5a1b3Sopenharmony_ci } else if (!i->write_index_corrupt) { 195353a5a1b3Sopenharmony_ci /* A relative seek was made */ 195453a5a1b3Sopenharmony_ci i->write_index += o->stream->write_index_corrections[j].value; 195553a5a1b3Sopenharmony_ci } 195653a5a1b3Sopenharmony_ci } 195753a5a1b3Sopenharmony_ci 195853a5a1b3Sopenharmony_ci /* Clear old correction entries */ 195953a5a1b3Sopenharmony_ci for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { 196053a5a1b3Sopenharmony_ci if (!o->stream->write_index_corrections[n].valid) 196153a5a1b3Sopenharmony_ci continue; 196253a5a1b3Sopenharmony_ci 196353a5a1b3Sopenharmony_ci if (o->stream->write_index_corrections[n].tag <= tag) 196453a5a1b3Sopenharmony_ci o->stream->write_index_corrections[n].valid = false; 196553a5a1b3Sopenharmony_ci } 196653a5a1b3Sopenharmony_ci } 196753a5a1b3Sopenharmony_ci 196853a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_RECORD) { 196953a5a1b3Sopenharmony_ci /* Read index correction */ 197053a5a1b3Sopenharmony_ci 197153a5a1b3Sopenharmony_ci if (!i->read_index_corrupt) 197253a5a1b3Sopenharmony_ci i->read_index -= (int64_t) pa_memblockq_get_length(o->stream->record_memblockq); 197353a5a1b3Sopenharmony_ci } 197453a5a1b3Sopenharmony_ci 197553a5a1b3Sopenharmony_ci /* Update smoother if we're not corked */ 197653a5a1b3Sopenharmony_ci if (o->stream->smoother && !o->stream->corked) { 197753a5a1b3Sopenharmony_ci pa_usec_t u, x; 197853a5a1b3Sopenharmony_ci 197953a5a1b3Sopenharmony_ci u = x = pa_rtclock_now() - i->transport_usec; 198053a5a1b3Sopenharmony_ci 198153a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_PLAYBACK && o->context->version >= 13) { 198253a5a1b3Sopenharmony_ci pa_usec_t su; 198353a5a1b3Sopenharmony_ci 198453a5a1b3Sopenharmony_ci /* If we weren't playing then it will take some time 198553a5a1b3Sopenharmony_ci * until the audio will actually come out through the 198653a5a1b3Sopenharmony_ci * speakers. Since we follow that timing here, we need 198753a5a1b3Sopenharmony_ci * to try to fix this up */ 198853a5a1b3Sopenharmony_ci 198953a5a1b3Sopenharmony_ci su = pa_bytes_to_usec((uint64_t) i->since_underrun, &o->stream->sample_spec); 199053a5a1b3Sopenharmony_ci 199153a5a1b3Sopenharmony_ci if (su < i->sink_usec) 199253a5a1b3Sopenharmony_ci x += i->sink_usec - su; 199353a5a1b3Sopenharmony_ci } 199453a5a1b3Sopenharmony_ci 199553a5a1b3Sopenharmony_ci if (!i->playing) 199653a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 199753a5a1b3Sopenharmony_ci pa_smoother_2_pause(o->stream->smoother, x); 199853a5a1b3Sopenharmony_ci#else 199953a5a1b3Sopenharmony_ci pa_smoother_pause(o->stream->smoother, x); 200053a5a1b3Sopenharmony_ci#endif 200153a5a1b3Sopenharmony_ci 200253a5a1b3Sopenharmony_ci /* Update the smoother */ 200353a5a1b3Sopenharmony_ci if ((o->stream->direction == PA_STREAM_PLAYBACK && !i->read_index_corrupt) || 200453a5a1b3Sopenharmony_ci (o->stream->direction == PA_STREAM_RECORD && !i->write_index_corrupt)) 200553a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 200653a5a1b3Sopenharmony_ci pa_smoother_2_put(o->stream->smoother, u, calc_bytes(o->stream, true)); 200753a5a1b3Sopenharmony_ci#else 200853a5a1b3Sopenharmony_ci pa_smoother_put(o->stream->smoother, u, calc_time(o->stream, true)); 200953a5a1b3Sopenharmony_ci#endif 201053a5a1b3Sopenharmony_ci 201153a5a1b3Sopenharmony_ci if (i->playing) 201253a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 201353a5a1b3Sopenharmony_ci pa_smoother_2_resume(o->stream->smoother, x); 201453a5a1b3Sopenharmony_ci#else 201553a5a1b3Sopenharmony_ci pa_smoother_resume(o->stream->smoother, x, true); 201653a5a1b3Sopenharmony_ci#endif 201753a5a1b3Sopenharmony_ci } 201853a5a1b3Sopenharmony_ci } 201953a5a1b3Sopenharmony_ci 202053a5a1b3Sopenharmony_ci o->stream->auto_timing_update_requested = false; 202153a5a1b3Sopenharmony_ci 202253a5a1b3Sopenharmony_ci if (o->stream->latency_update_callback) 202353a5a1b3Sopenharmony_ci o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); 202453a5a1b3Sopenharmony_ci 202553a5a1b3Sopenharmony_ci if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { 202653a5a1b3Sopenharmony_ci pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; 202753a5a1b3Sopenharmony_ci cb(o->stream, o->stream->timing_info_valid, o->userdata); 202853a5a1b3Sopenharmony_ci } 202953a5a1b3Sopenharmony_ci 203053a5a1b3Sopenharmony_cifinish: 203153a5a1b3Sopenharmony_ci 203253a5a1b3Sopenharmony_ci pa_operation_done(o); 203353a5a1b3Sopenharmony_ci pa_operation_unref(o); 203453a5a1b3Sopenharmony_ci} 203553a5a1b3Sopenharmony_ci 203653a5a1b3Sopenharmony_cipa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { 203753a5a1b3Sopenharmony_ci uint32_t tag; 203853a5a1b3Sopenharmony_ci pa_operation *o; 203953a5a1b3Sopenharmony_ci pa_tagstruct *t; 204053a5a1b3Sopenharmony_ci struct timeval now; 204153a5a1b3Sopenharmony_ci int cidx = 0; 204253a5a1b3Sopenharmony_ci 204353a5a1b3Sopenharmony_ci pa_assert(s); 204453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 204553a5a1b3Sopenharmony_ci 204653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 204753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 204853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 204953a5a1b3Sopenharmony_ci 205053a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 205153a5a1b3Sopenharmony_ci /* Find a place to store the write_index correction data for this entry */ 205253a5a1b3Sopenharmony_ci cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; 205353a5a1b3Sopenharmony_ci 205453a5a1b3Sopenharmony_ci /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ 205553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); 205653a5a1b3Sopenharmony_ci } 205753a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 205853a5a1b3Sopenharmony_ci 205953a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 206053a5a1b3Sopenharmony_ci s->context, 206153a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY), 206253a5a1b3Sopenharmony_ci &tag); 206353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 206453a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); 206553a5a1b3Sopenharmony_ci 206653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 206753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 206853a5a1b3Sopenharmony_ci 206953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 207053a5a1b3Sopenharmony_ci /* Fill in initial correction data */ 207153a5a1b3Sopenharmony_ci 207253a5a1b3Sopenharmony_ci s->current_write_index_correction = cidx; 207353a5a1b3Sopenharmony_ci 207453a5a1b3Sopenharmony_ci s->write_index_corrections[cidx].valid = true; 207553a5a1b3Sopenharmony_ci s->write_index_corrections[cidx].absolute = false; 207653a5a1b3Sopenharmony_ci s->write_index_corrections[cidx].corrupt = false; 207753a5a1b3Sopenharmony_ci s->write_index_corrections[cidx].tag = tag; 207853a5a1b3Sopenharmony_ci s->write_index_corrections[cidx].value = 0; 207953a5a1b3Sopenharmony_ci } 208053a5a1b3Sopenharmony_ci 208153a5a1b3Sopenharmony_ci return o; 208253a5a1b3Sopenharmony_ci} 208353a5a1b3Sopenharmony_ci 208453a5a1b3Sopenharmony_civoid pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 208553a5a1b3Sopenharmony_ci pa_stream *s = userdata; 208653a5a1b3Sopenharmony_ci 208753a5a1b3Sopenharmony_ci pa_assert(pd); 208853a5a1b3Sopenharmony_ci pa_assert(s); 208953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 209053a5a1b3Sopenharmony_ci 209153a5a1b3Sopenharmony_ci pa_stream_ref(s); 209253a5a1b3Sopenharmony_ci 209353a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 209453a5a1b3Sopenharmony_ci if (pa_context_handle_error(s->context, command, t, false) < 0) 209553a5a1b3Sopenharmony_ci goto finish; 209653a5a1b3Sopenharmony_ci 209753a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_FAILED); 209853a5a1b3Sopenharmony_ci goto finish; 209953a5a1b3Sopenharmony_ci } else if (!pa_tagstruct_eof(t)) { 210053a5a1b3Sopenharmony_ci pa_context_fail(s->context, PA_ERR_PROTOCOL); 210153a5a1b3Sopenharmony_ci goto finish; 210253a5a1b3Sopenharmony_ci } 210353a5a1b3Sopenharmony_ci 210453a5a1b3Sopenharmony_ci pa_stream_set_state(s, PA_STREAM_TERMINATED); 210553a5a1b3Sopenharmony_ci 210653a5a1b3Sopenharmony_cifinish: 210753a5a1b3Sopenharmony_ci pa_stream_unref(s); 210853a5a1b3Sopenharmony_ci} 210953a5a1b3Sopenharmony_ci 211053a5a1b3Sopenharmony_ciint pa_stream_disconnect(pa_stream *s) { 211153a5a1b3Sopenharmony_ci pa_tagstruct *t; 211253a5a1b3Sopenharmony_ci uint32_t tag; 211353a5a1b3Sopenharmony_ci 211453a5a1b3Sopenharmony_ci pa_assert(s); 211553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 211653a5a1b3Sopenharmony_ci 211753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 211853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); 211953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 212053a5a1b3Sopenharmony_ci 212153a5a1b3Sopenharmony_ci pa_stream_ref(s); 212253a5a1b3Sopenharmony_ci 212353a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 212453a5a1b3Sopenharmony_ci s->context, 212553a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : 212653a5a1b3Sopenharmony_ci (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)), 212753a5a1b3Sopenharmony_ci &tag); 212853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 212953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 213053a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); 213153a5a1b3Sopenharmony_ci 213253a5a1b3Sopenharmony_ci pa_stream_unref(s); 213353a5a1b3Sopenharmony_ci return 0; 213453a5a1b3Sopenharmony_ci} 213553a5a1b3Sopenharmony_ci 213653a5a1b3Sopenharmony_civoid pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { 213753a5a1b3Sopenharmony_ci pa_assert(s); 213853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 213953a5a1b3Sopenharmony_ci 214053a5a1b3Sopenharmony_ci if (pa_detect_fork()) 214153a5a1b3Sopenharmony_ci return; 214253a5a1b3Sopenharmony_ci 214353a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 214453a5a1b3Sopenharmony_ci return; 214553a5a1b3Sopenharmony_ci 214653a5a1b3Sopenharmony_ci s->read_callback = cb; 214753a5a1b3Sopenharmony_ci s->read_userdata = userdata; 214853a5a1b3Sopenharmony_ci} 214953a5a1b3Sopenharmony_ci 215053a5a1b3Sopenharmony_civoid pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { 215153a5a1b3Sopenharmony_ci pa_assert(s); 215253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 215353a5a1b3Sopenharmony_ci 215453a5a1b3Sopenharmony_ci if (pa_detect_fork()) 215553a5a1b3Sopenharmony_ci return; 215653a5a1b3Sopenharmony_ci 215753a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 215853a5a1b3Sopenharmony_ci return; 215953a5a1b3Sopenharmony_ci 216053a5a1b3Sopenharmony_ci s->write_callback = cb; 216153a5a1b3Sopenharmony_ci s->write_userdata = userdata; 216253a5a1b3Sopenharmony_ci} 216353a5a1b3Sopenharmony_ci 216453a5a1b3Sopenharmony_civoid pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 216553a5a1b3Sopenharmony_ci pa_assert(s); 216653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 216753a5a1b3Sopenharmony_ci 216853a5a1b3Sopenharmony_ci if (pa_detect_fork()) 216953a5a1b3Sopenharmony_ci return; 217053a5a1b3Sopenharmony_ci 217153a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 217253a5a1b3Sopenharmony_ci return; 217353a5a1b3Sopenharmony_ci 217453a5a1b3Sopenharmony_ci s->state_callback = cb; 217553a5a1b3Sopenharmony_ci s->state_userdata = userdata; 217653a5a1b3Sopenharmony_ci} 217753a5a1b3Sopenharmony_ci 217853a5a1b3Sopenharmony_civoid pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 217953a5a1b3Sopenharmony_ci pa_assert(s); 218053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 218153a5a1b3Sopenharmony_ci 218253a5a1b3Sopenharmony_ci if (pa_detect_fork()) 218353a5a1b3Sopenharmony_ci return; 218453a5a1b3Sopenharmony_ci 218553a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 218653a5a1b3Sopenharmony_ci return; 218753a5a1b3Sopenharmony_ci 218853a5a1b3Sopenharmony_ci s->overflow_callback = cb; 218953a5a1b3Sopenharmony_ci s->overflow_userdata = userdata; 219053a5a1b3Sopenharmony_ci} 219153a5a1b3Sopenharmony_ci 219253a5a1b3Sopenharmony_civoid pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 219353a5a1b3Sopenharmony_ci pa_assert(s); 219453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 219553a5a1b3Sopenharmony_ci 219653a5a1b3Sopenharmony_ci if (pa_detect_fork()) 219753a5a1b3Sopenharmony_ci return; 219853a5a1b3Sopenharmony_ci 219953a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 220053a5a1b3Sopenharmony_ci return; 220153a5a1b3Sopenharmony_ci 220253a5a1b3Sopenharmony_ci s->underflow_callback = cb; 220353a5a1b3Sopenharmony_ci s->underflow_userdata = userdata; 220453a5a1b3Sopenharmony_ci} 220553a5a1b3Sopenharmony_ci 220653a5a1b3Sopenharmony_civoid pa_stream_set_underflow_ohos_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 220753a5a1b3Sopenharmony_ci pa_assert(s); 220853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 220953a5a1b3Sopenharmony_ci 221053a5a1b3Sopenharmony_ci if (pa_detect_fork()) 221153a5a1b3Sopenharmony_ci return; 221253a5a1b3Sopenharmony_ci 221353a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 221453a5a1b3Sopenharmony_ci return; 221553a5a1b3Sopenharmony_ci 221653a5a1b3Sopenharmony_ci s->underflow_ohos_callback = cb; 221753a5a1b3Sopenharmony_ci s->underflow_ohos_userdata = userdata; 221853a5a1b3Sopenharmony_ci} 221953a5a1b3Sopenharmony_ci 222053a5a1b3Sopenharmony_civoid pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 222153a5a1b3Sopenharmony_ci pa_assert(s); 222253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 222353a5a1b3Sopenharmony_ci 222453a5a1b3Sopenharmony_ci if (pa_detect_fork()) 222553a5a1b3Sopenharmony_ci return; 222653a5a1b3Sopenharmony_ci 222753a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 222853a5a1b3Sopenharmony_ci return; 222953a5a1b3Sopenharmony_ci 223053a5a1b3Sopenharmony_ci s->latency_update_callback = cb; 223153a5a1b3Sopenharmony_ci s->latency_update_userdata = userdata; 223253a5a1b3Sopenharmony_ci} 223353a5a1b3Sopenharmony_ci 223453a5a1b3Sopenharmony_civoid pa_stream_set_moved_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 223553a5a1b3Sopenharmony_ci pa_assert(s); 223653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 223753a5a1b3Sopenharmony_ci 223853a5a1b3Sopenharmony_ci if (pa_detect_fork()) 223953a5a1b3Sopenharmony_ci return; 224053a5a1b3Sopenharmony_ci 224153a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 224253a5a1b3Sopenharmony_ci return; 224353a5a1b3Sopenharmony_ci 224453a5a1b3Sopenharmony_ci s->moved_callback = cb; 224553a5a1b3Sopenharmony_ci s->moved_userdata = userdata; 224653a5a1b3Sopenharmony_ci} 224753a5a1b3Sopenharmony_ci 224853a5a1b3Sopenharmony_civoid pa_stream_set_suspended_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 224953a5a1b3Sopenharmony_ci pa_assert(s); 225053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 225153a5a1b3Sopenharmony_ci 225253a5a1b3Sopenharmony_ci if (pa_detect_fork()) 225353a5a1b3Sopenharmony_ci return; 225453a5a1b3Sopenharmony_ci 225553a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 225653a5a1b3Sopenharmony_ci return; 225753a5a1b3Sopenharmony_ci 225853a5a1b3Sopenharmony_ci s->suspended_callback = cb; 225953a5a1b3Sopenharmony_ci s->suspended_userdata = userdata; 226053a5a1b3Sopenharmony_ci} 226153a5a1b3Sopenharmony_ci 226253a5a1b3Sopenharmony_civoid pa_stream_set_started_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 226353a5a1b3Sopenharmony_ci pa_assert(s); 226453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 226553a5a1b3Sopenharmony_ci 226653a5a1b3Sopenharmony_ci if (pa_detect_fork()) 226753a5a1b3Sopenharmony_ci return; 226853a5a1b3Sopenharmony_ci 226953a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 227053a5a1b3Sopenharmony_ci return; 227153a5a1b3Sopenharmony_ci 227253a5a1b3Sopenharmony_ci s->started_callback = cb; 227353a5a1b3Sopenharmony_ci s->started_userdata = userdata; 227453a5a1b3Sopenharmony_ci} 227553a5a1b3Sopenharmony_ci 227653a5a1b3Sopenharmony_civoid pa_stream_set_event_callback(pa_stream *s, pa_stream_event_cb_t cb, void *userdata) { 227753a5a1b3Sopenharmony_ci pa_assert(s); 227853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 227953a5a1b3Sopenharmony_ci 228053a5a1b3Sopenharmony_ci if (pa_detect_fork()) 228153a5a1b3Sopenharmony_ci return; 228253a5a1b3Sopenharmony_ci 228353a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 228453a5a1b3Sopenharmony_ci return; 228553a5a1b3Sopenharmony_ci 228653a5a1b3Sopenharmony_ci s->event_callback = cb; 228753a5a1b3Sopenharmony_ci s->event_userdata = userdata; 228853a5a1b3Sopenharmony_ci} 228953a5a1b3Sopenharmony_ci 229053a5a1b3Sopenharmony_civoid pa_stream_set_buffer_attr_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { 229153a5a1b3Sopenharmony_ci pa_assert(s); 229253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 229353a5a1b3Sopenharmony_ci 229453a5a1b3Sopenharmony_ci if (pa_detect_fork()) 229553a5a1b3Sopenharmony_ci return; 229653a5a1b3Sopenharmony_ci 229753a5a1b3Sopenharmony_ci if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED) 229853a5a1b3Sopenharmony_ci return; 229953a5a1b3Sopenharmony_ci 230053a5a1b3Sopenharmony_ci s->buffer_attr_callback = cb; 230153a5a1b3Sopenharmony_ci s->buffer_attr_userdata = userdata; 230253a5a1b3Sopenharmony_ci} 230353a5a1b3Sopenharmony_ci 230453a5a1b3Sopenharmony_civoid pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 230553a5a1b3Sopenharmony_ci pa_operation *o = userdata; 230653a5a1b3Sopenharmony_ci int success = 1; 230753a5a1b3Sopenharmony_ci 230853a5a1b3Sopenharmony_ci pa_assert(pd); 230953a5a1b3Sopenharmony_ci pa_assert(o); 231053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 231153a5a1b3Sopenharmony_ci 231253a5a1b3Sopenharmony_ci if (!o->context) 231353a5a1b3Sopenharmony_ci goto finish; 231453a5a1b3Sopenharmony_ci 231553a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 231653a5a1b3Sopenharmony_ci if (pa_context_handle_error(o->context, command, t, false) < 0) 231753a5a1b3Sopenharmony_ci goto finish; 231853a5a1b3Sopenharmony_ci 231953a5a1b3Sopenharmony_ci success = 0; 232053a5a1b3Sopenharmony_ci } else if (!pa_tagstruct_eof(t)) { 232153a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 232253a5a1b3Sopenharmony_ci goto finish; 232353a5a1b3Sopenharmony_ci } 232453a5a1b3Sopenharmony_ci 232553a5a1b3Sopenharmony_ci if (o->callback) { 232653a5a1b3Sopenharmony_ci pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; 232753a5a1b3Sopenharmony_ci cb(o->stream, success, o->userdata); 232853a5a1b3Sopenharmony_ci } 232953a5a1b3Sopenharmony_ci 233053a5a1b3Sopenharmony_cifinish: 233153a5a1b3Sopenharmony_ci pa_operation_done(o); 233253a5a1b3Sopenharmony_ci pa_operation_unref(o); 233353a5a1b3Sopenharmony_ci} 233453a5a1b3Sopenharmony_ci 233553a5a1b3Sopenharmony_cipa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { 233653a5a1b3Sopenharmony_ci pa_operation *o; 233753a5a1b3Sopenharmony_ci pa_tagstruct *t; 233853a5a1b3Sopenharmony_ci uint32_t tag; 233953a5a1b3Sopenharmony_ci 234053a5a1b3Sopenharmony_ci pa_assert(s); 234153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 234253a5a1b3Sopenharmony_ci 234353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 234453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 234553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 234653a5a1b3Sopenharmony_ci 234753a5a1b3Sopenharmony_ci /* Ask for a timing update before we cork/uncork to get the best 234853a5a1b3Sopenharmony_ci * accuracy for the transport latency suitable for the 234953a5a1b3Sopenharmony_ci * check_smoother_status() call in the started callback */ 235053a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 235153a5a1b3Sopenharmony_ci 235253a5a1b3Sopenharmony_ci s->corked = b; 235353a5a1b3Sopenharmony_ci 235453a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 235553a5a1b3Sopenharmony_ci 235653a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 235753a5a1b3Sopenharmony_ci s->context, 235853a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM), 235953a5a1b3Sopenharmony_ci &tag); 236053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 236153a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, !!b); 236253a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 236353a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 236453a5a1b3Sopenharmony_ci 236553a5a1b3Sopenharmony_ci check_smoother_status(s, false, false, false); 236653a5a1b3Sopenharmony_ci 236753a5a1b3Sopenharmony_ci /* This might cause the indexes to hang/start again, hence let's 236853a5a1b3Sopenharmony_ci * request a timing update, after the cork/uncork, too */ 236953a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 237053a5a1b3Sopenharmony_ci 237153a5a1b3Sopenharmony_ci return o; 237253a5a1b3Sopenharmony_ci} 237353a5a1b3Sopenharmony_ci 237453a5a1b3Sopenharmony_cistatic pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { 237553a5a1b3Sopenharmony_ci pa_tagstruct *t; 237653a5a1b3Sopenharmony_ci pa_operation *o; 237753a5a1b3Sopenharmony_ci uint32_t tag; 237853a5a1b3Sopenharmony_ci 237953a5a1b3Sopenharmony_ci pa_assert(s); 238053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 238153a5a1b3Sopenharmony_ci 238253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 238353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 238453a5a1b3Sopenharmony_ci 238553a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 238653a5a1b3Sopenharmony_ci 238753a5a1b3Sopenharmony_ci t = pa_tagstruct_command(s->context, command, &tag); 238853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 238953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 239053a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 239153a5a1b3Sopenharmony_ci 239253a5a1b3Sopenharmony_ci return o; 239353a5a1b3Sopenharmony_ci} 239453a5a1b3Sopenharmony_ci 239553a5a1b3Sopenharmony_cipa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { 239653a5a1b3Sopenharmony_ci pa_operation *o; 239753a5a1b3Sopenharmony_ci 239853a5a1b3Sopenharmony_ci pa_assert(s); 239953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 240053a5a1b3Sopenharmony_ci 240153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 240253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 240353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 240453a5a1b3Sopenharmony_ci 240553a5a1b3Sopenharmony_ci /* Ask for a timing update *before* the flush, so that the 240653a5a1b3Sopenharmony_ci * transport usec is as up to date as possible when we get the 240753a5a1b3Sopenharmony_ci * underflow message and update the smoother status*/ 240853a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 240953a5a1b3Sopenharmony_ci 241053a5a1b3Sopenharmony_ci if (!(o = stream_send_simple_command(s, (uint32_t) (s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM), cb, userdata))) 241153a5a1b3Sopenharmony_ci return NULL; 241253a5a1b3Sopenharmony_ci 241353a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) { 241453a5a1b3Sopenharmony_ci 241553a5a1b3Sopenharmony_ci if (s->write_index_corrections[s->current_write_index_correction].valid) 241653a5a1b3Sopenharmony_ci s->write_index_corrections[s->current_write_index_correction].corrupt = true; 241753a5a1b3Sopenharmony_ci 241853a5a1b3Sopenharmony_ci if (s->buffer_attr.prebuf > 0) 241953a5a1b3Sopenharmony_ci check_smoother_status(s, false, false, true); 242053a5a1b3Sopenharmony_ci 242153a5a1b3Sopenharmony_ci /* This will change the write index, but leave the 242253a5a1b3Sopenharmony_ci * read index untouched. */ 242353a5a1b3Sopenharmony_ci invalidate_indexes(s, false, true); 242453a5a1b3Sopenharmony_ci 242553a5a1b3Sopenharmony_ci } else 242653a5a1b3Sopenharmony_ci /* For record streams this has no influence on the write 242753a5a1b3Sopenharmony_ci * index, but the read index might jump. */ 242853a5a1b3Sopenharmony_ci invalidate_indexes(s, true, false); 242953a5a1b3Sopenharmony_ci 243053a5a1b3Sopenharmony_ci /* Note that we do not update requested_bytes here. This is 243153a5a1b3Sopenharmony_ci * because we cannot really know how data actually was dropped 243253a5a1b3Sopenharmony_ci * from the write index due to this. This 'error' will be applied 243353a5a1b3Sopenharmony_ci * by both client and server and hence we should be fine. */ 243453a5a1b3Sopenharmony_ci 243553a5a1b3Sopenharmony_ci return o; 243653a5a1b3Sopenharmony_ci} 243753a5a1b3Sopenharmony_ci 243853a5a1b3Sopenharmony_cipa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { 243953a5a1b3Sopenharmony_ci pa_operation *o; 244053a5a1b3Sopenharmony_ci 244153a5a1b3Sopenharmony_ci pa_assert(s); 244253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 244353a5a1b3Sopenharmony_ci 244453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 244553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 244653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); 244753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); 244853a5a1b3Sopenharmony_ci 244953a5a1b3Sopenharmony_ci /* Ask for a timing update before we cork/uncork to get the best 245053a5a1b3Sopenharmony_ci * accuracy for the transport latency suitable for the 245153a5a1b3Sopenharmony_ci * check_smoother_status() call in the started callback */ 245253a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 245353a5a1b3Sopenharmony_ci 245453a5a1b3Sopenharmony_ci if (!(o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) 245553a5a1b3Sopenharmony_ci return NULL; 245653a5a1b3Sopenharmony_ci 245753a5a1b3Sopenharmony_ci /* This might cause the read index to hang again, hence 245853a5a1b3Sopenharmony_ci * let's request a timing update */ 245953a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 246053a5a1b3Sopenharmony_ci 246153a5a1b3Sopenharmony_ci return o; 246253a5a1b3Sopenharmony_ci} 246353a5a1b3Sopenharmony_ci 246453a5a1b3Sopenharmony_cipa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { 246553a5a1b3Sopenharmony_ci pa_operation *o; 246653a5a1b3Sopenharmony_ci 246753a5a1b3Sopenharmony_ci pa_assert(s); 246853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 246953a5a1b3Sopenharmony_ci 247053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 247153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 247253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); 247353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); 247453a5a1b3Sopenharmony_ci 247553a5a1b3Sopenharmony_ci /* Ask for a timing update before we cork/uncork to get the best 247653a5a1b3Sopenharmony_ci * accuracy for the transport latency suitable for the 247753a5a1b3Sopenharmony_ci * check_smoother_status() call in the started callback */ 247853a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 247953a5a1b3Sopenharmony_ci 248053a5a1b3Sopenharmony_ci if (!(o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) 248153a5a1b3Sopenharmony_ci return NULL; 248253a5a1b3Sopenharmony_ci 248353a5a1b3Sopenharmony_ci /* This might cause the read index to start moving again, hence 248453a5a1b3Sopenharmony_ci * let's request a timing update */ 248553a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 248653a5a1b3Sopenharmony_ci 248753a5a1b3Sopenharmony_ci return o; 248853a5a1b3Sopenharmony_ci} 248953a5a1b3Sopenharmony_ci 249053a5a1b3Sopenharmony_cipa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { 249153a5a1b3Sopenharmony_ci pa_operation *o; 249253a5a1b3Sopenharmony_ci 249353a5a1b3Sopenharmony_ci pa_assert(s); 249453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 249553a5a1b3Sopenharmony_ci pa_assert(name); 249653a5a1b3Sopenharmony_ci 249753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 249853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 249953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 250053a5a1b3Sopenharmony_ci 250153a5a1b3Sopenharmony_ci if (s->context->version >= 13) { 250253a5a1b3Sopenharmony_ci pa_proplist *p = pa_proplist_new(); 250353a5a1b3Sopenharmony_ci 250453a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name); 250553a5a1b3Sopenharmony_ci o = pa_stream_proplist_update(s, PA_UPDATE_REPLACE, p, cb, userdata); 250653a5a1b3Sopenharmony_ci pa_proplist_free(p); 250753a5a1b3Sopenharmony_ci } else { 250853a5a1b3Sopenharmony_ci pa_tagstruct *t; 250953a5a1b3Sopenharmony_ci uint32_t tag; 251053a5a1b3Sopenharmony_ci 251153a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 251253a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 251353a5a1b3Sopenharmony_ci s->context, 251453a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME), 251553a5a1b3Sopenharmony_ci &tag); 251653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 251753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, name); 251853a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 251953a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 252053a5a1b3Sopenharmony_ci } 252153a5a1b3Sopenharmony_ci 252253a5a1b3Sopenharmony_ci return o; 252353a5a1b3Sopenharmony_ci} 252453a5a1b3Sopenharmony_ci 252553a5a1b3Sopenharmony_ciint pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { 252653a5a1b3Sopenharmony_ci pa_usec_t usec; 252753a5a1b3Sopenharmony_ci 252853a5a1b3Sopenharmony_ci pa_assert(s); 252953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 253053a5a1b3Sopenharmony_ci 253153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 253253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 253353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 253453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); 253553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); 253653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); 253753a5a1b3Sopenharmony_ci 253853a5a1b3Sopenharmony_ci if (s->smoother) 253953a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 254053a5a1b3Sopenharmony_ci usec = pa_smoother_2_get(s->smoother, pa_rtclock_now()); 254153a5a1b3Sopenharmony_ci#else 254253a5a1b3Sopenharmony_ci usec = pa_smoother_get(s->smoother, pa_rtclock_now()); 254353a5a1b3Sopenharmony_ci#endif 254453a5a1b3Sopenharmony_ci 254553a5a1b3Sopenharmony_ci else 254653a5a1b3Sopenharmony_ci usec = calc_time(s, false); 254753a5a1b3Sopenharmony_ci 254853a5a1b3Sopenharmony_ci /* Make sure the time runs monotonically */ 254953a5a1b3Sopenharmony_ci if (!(s->flags & PA_STREAM_NOT_MONOTONIC)) { 255053a5a1b3Sopenharmony_ci if (usec < s->previous_time) 255153a5a1b3Sopenharmony_ci usec = s->previous_time; 255253a5a1b3Sopenharmony_ci else 255353a5a1b3Sopenharmony_ci s->previous_time = usec; 255453a5a1b3Sopenharmony_ci } 255553a5a1b3Sopenharmony_ci 255653a5a1b3Sopenharmony_ci if (r_usec) 255753a5a1b3Sopenharmony_ci *r_usec = usec; 255853a5a1b3Sopenharmony_ci 255953a5a1b3Sopenharmony_ci return 0; 256053a5a1b3Sopenharmony_ci} 256153a5a1b3Sopenharmony_ci 256253a5a1b3Sopenharmony_cistatic pa_usec_t time_counter_diff(const pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { 256353a5a1b3Sopenharmony_ci pa_assert(s); 256453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 256553a5a1b3Sopenharmony_ci 256653a5a1b3Sopenharmony_ci if (negative) 256753a5a1b3Sopenharmony_ci *negative = 0; 256853a5a1b3Sopenharmony_ci 256953a5a1b3Sopenharmony_ci if (a >= b) 257053a5a1b3Sopenharmony_ci return a-b; 257153a5a1b3Sopenharmony_ci else { 257253a5a1b3Sopenharmony_ci if (negative && s->direction == PA_STREAM_RECORD) { 257353a5a1b3Sopenharmony_ci *negative = 1; 257453a5a1b3Sopenharmony_ci return b-a; 257553a5a1b3Sopenharmony_ci } else 257653a5a1b3Sopenharmony_ci return 0; 257753a5a1b3Sopenharmony_ci } 257853a5a1b3Sopenharmony_ci} 257953a5a1b3Sopenharmony_ci 258053a5a1b3Sopenharmony_ciint pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { 258153a5a1b3Sopenharmony_ci pa_usec_t t, c; 258253a5a1b3Sopenharmony_ci int r; 258353a5a1b3Sopenharmony_ci int64_t cindex; 258453a5a1b3Sopenharmony_ci 258553a5a1b3Sopenharmony_ci pa_assert(s); 258653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 258753a5a1b3Sopenharmony_ci pa_assert(r_usec); 258853a5a1b3Sopenharmony_ci 258953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 259053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 259153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 259253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); 259353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); 259453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); 259553a5a1b3Sopenharmony_ci 259653a5a1b3Sopenharmony_ci if ((r = pa_stream_get_time(s, &t)) < 0) 259753a5a1b3Sopenharmony_ci return r; 259853a5a1b3Sopenharmony_ci 259953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 260053a5a1b3Sopenharmony_ci cindex = s->timing_info.write_index; 260153a5a1b3Sopenharmony_ci else 260253a5a1b3Sopenharmony_ci cindex = s->timing_info.read_index; 260353a5a1b3Sopenharmony_ci 260453a5a1b3Sopenharmony_ci if (cindex < 0) 260553a5a1b3Sopenharmony_ci cindex = 0; 260653a5a1b3Sopenharmony_ci 260753a5a1b3Sopenharmony_ci c = pa_bytes_to_usec((uint64_t) cindex, &s->sample_spec); 260853a5a1b3Sopenharmony_ci 260953a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 261053a5a1b3Sopenharmony_ci *r_usec = time_counter_diff(s, c, t, negative); 261153a5a1b3Sopenharmony_ci else 261253a5a1b3Sopenharmony_ci *r_usec = time_counter_diff(s, t, c, negative); 261353a5a1b3Sopenharmony_ci 261453a5a1b3Sopenharmony_ci return 0; 261553a5a1b3Sopenharmony_ci} 261653a5a1b3Sopenharmony_ci 261753a5a1b3Sopenharmony_ciconst pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { 261853a5a1b3Sopenharmony_ci pa_assert(s); 261953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 262053a5a1b3Sopenharmony_ci 262153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 262253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 262353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 262453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_NODATA); 262553a5a1b3Sopenharmony_ci 262653a5a1b3Sopenharmony_ci return &s->timing_info; 262753a5a1b3Sopenharmony_ci} 262853a5a1b3Sopenharmony_ci 262953a5a1b3Sopenharmony_ciconst pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { 263053a5a1b3Sopenharmony_ci pa_assert(s); 263153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 263253a5a1b3Sopenharmony_ci 263353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 263453a5a1b3Sopenharmony_ci 263553a5a1b3Sopenharmony_ci return &s->sample_spec; 263653a5a1b3Sopenharmony_ci} 263753a5a1b3Sopenharmony_ci 263853a5a1b3Sopenharmony_ciconst pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { 263953a5a1b3Sopenharmony_ci pa_assert(s); 264053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 264153a5a1b3Sopenharmony_ci 264253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 264353a5a1b3Sopenharmony_ci 264453a5a1b3Sopenharmony_ci return &s->channel_map; 264553a5a1b3Sopenharmony_ci} 264653a5a1b3Sopenharmony_ci 264753a5a1b3Sopenharmony_ciconst pa_format_info* pa_stream_get_format_info(const pa_stream *s) { 264853a5a1b3Sopenharmony_ci pa_assert(s); 264953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 265053a5a1b3Sopenharmony_ci 265153a5a1b3Sopenharmony_ci /* We don't have the format till routing is done */ 265253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 265353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 265453a5a1b3Sopenharmony_ci 265553a5a1b3Sopenharmony_ci return s->format; 265653a5a1b3Sopenharmony_ci} 265753a5a1b3Sopenharmony_ciconst pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { 265853a5a1b3Sopenharmony_ci pa_assert(s); 265953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 266053a5a1b3Sopenharmony_ci 266153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 266253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 266353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 9, PA_ERR_NOTSUPPORTED); 266453a5a1b3Sopenharmony_ci 266553a5a1b3Sopenharmony_ci return &s->buffer_attr; 266653a5a1b3Sopenharmony_ci} 266753a5a1b3Sopenharmony_ci 266853a5a1b3Sopenharmony_cistatic void stream_set_buffer_attr_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 266953a5a1b3Sopenharmony_ci pa_operation *o = userdata; 267053a5a1b3Sopenharmony_ci int success = 1; 267153a5a1b3Sopenharmony_ci 267253a5a1b3Sopenharmony_ci pa_assert(pd); 267353a5a1b3Sopenharmony_ci pa_assert(o); 267453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 267553a5a1b3Sopenharmony_ci 267653a5a1b3Sopenharmony_ci if (!o->context) 267753a5a1b3Sopenharmony_ci goto finish; 267853a5a1b3Sopenharmony_ci 267953a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 268053a5a1b3Sopenharmony_ci if (pa_context_handle_error(o->context, command, t, false) < 0) 268153a5a1b3Sopenharmony_ci goto finish; 268253a5a1b3Sopenharmony_ci 268353a5a1b3Sopenharmony_ci success = 0; 268453a5a1b3Sopenharmony_ci } else { 268553a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_PLAYBACK) { 268653a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 || 268753a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &o->stream->buffer_attr.tlength) < 0 || 268853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &o->stream->buffer_attr.prebuf) < 0 || 268953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &o->stream->buffer_attr.minreq) < 0) { 269053a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 269153a5a1b3Sopenharmony_ci goto finish; 269253a5a1b3Sopenharmony_ci } 269353a5a1b3Sopenharmony_ci } else if (o->stream->direction == PA_STREAM_RECORD) { 269453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &o->stream->buffer_attr.maxlength) < 0 || 269553a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &o->stream->buffer_attr.fragsize) < 0) { 269653a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 269753a5a1b3Sopenharmony_ci goto finish; 269853a5a1b3Sopenharmony_ci } 269953a5a1b3Sopenharmony_ci } 270053a5a1b3Sopenharmony_ci 270153a5a1b3Sopenharmony_ci if (o->stream->context->version >= 13) { 270253a5a1b3Sopenharmony_ci pa_usec_t usec; 270353a5a1b3Sopenharmony_ci 270453a5a1b3Sopenharmony_ci if (pa_tagstruct_get_usec(t, &usec) < 0) { 270553a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 270653a5a1b3Sopenharmony_ci goto finish; 270753a5a1b3Sopenharmony_ci } 270853a5a1b3Sopenharmony_ci 270953a5a1b3Sopenharmony_ci if (o->stream->direction == PA_STREAM_RECORD) 271053a5a1b3Sopenharmony_ci o->stream->timing_info.configured_source_usec = usec; 271153a5a1b3Sopenharmony_ci else 271253a5a1b3Sopenharmony_ci o->stream->timing_info.configured_sink_usec = usec; 271353a5a1b3Sopenharmony_ci } 271453a5a1b3Sopenharmony_ci 271553a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 271653a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 271753a5a1b3Sopenharmony_ci goto finish; 271853a5a1b3Sopenharmony_ci } 271953a5a1b3Sopenharmony_ci } 272053a5a1b3Sopenharmony_ci 272153a5a1b3Sopenharmony_ci if (o->callback) { 272253a5a1b3Sopenharmony_ci pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; 272353a5a1b3Sopenharmony_ci cb(o->stream, success, o->userdata); 272453a5a1b3Sopenharmony_ci } 272553a5a1b3Sopenharmony_ci 272653a5a1b3Sopenharmony_cifinish: 272753a5a1b3Sopenharmony_ci pa_operation_done(o); 272853a5a1b3Sopenharmony_ci pa_operation_unref(o); 272953a5a1b3Sopenharmony_ci} 273053a5a1b3Sopenharmony_ci 273153a5a1b3Sopenharmony_cipa_operation* pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr, pa_stream_success_cb_t cb, void *userdata) { 273253a5a1b3Sopenharmony_ci pa_operation *o; 273353a5a1b3Sopenharmony_ci pa_tagstruct *t; 273453a5a1b3Sopenharmony_ci uint32_t tag; 273553a5a1b3Sopenharmony_ci pa_buffer_attr copy; 273653a5a1b3Sopenharmony_ci 273753a5a1b3Sopenharmony_ci pa_assert(s); 273853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 273953a5a1b3Sopenharmony_ci pa_assert(attr); 274053a5a1b3Sopenharmony_ci 274153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 274253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 274353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 274453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); 274553a5a1b3Sopenharmony_ci 274653a5a1b3Sopenharmony_ci /* Ask for a timing update before we cork/uncork to get the best 274753a5a1b3Sopenharmony_ci * accuracy for the transport latency suitable for the 274853a5a1b3Sopenharmony_ci * check_smoother_status() call in the started callback */ 274953a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 275053a5a1b3Sopenharmony_ci 275153a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 275253a5a1b3Sopenharmony_ci 275353a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 275453a5a1b3Sopenharmony_ci s->context, 275553a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR : PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR), 275653a5a1b3Sopenharmony_ci &tag); 275753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 275853a5a1b3Sopenharmony_ci 275953a5a1b3Sopenharmony_ci copy = *attr; 276053a5a1b3Sopenharmony_ci patch_buffer_attr(s, ©, NULL); 276153a5a1b3Sopenharmony_ci attr = © 276253a5a1b3Sopenharmony_ci 276353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, attr->maxlength); 276453a5a1b3Sopenharmony_ci 276553a5a1b3Sopenharmony_ci if (s->direction == PA_STREAM_PLAYBACK) 276653a5a1b3Sopenharmony_ci pa_tagstruct_put( 276753a5a1b3Sopenharmony_ci t, 276853a5a1b3Sopenharmony_ci PA_TAG_U32, attr->tlength, 276953a5a1b3Sopenharmony_ci PA_TAG_U32, attr->prebuf, 277053a5a1b3Sopenharmony_ci PA_TAG_U32, attr->minreq, 277153a5a1b3Sopenharmony_ci PA_TAG_INVALID); 277253a5a1b3Sopenharmony_ci else 277353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, attr->fragsize); 277453a5a1b3Sopenharmony_ci 277553a5a1b3Sopenharmony_ci if (s->context->version >= 13) 277653a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, !!(s->flags & PA_STREAM_ADJUST_LATENCY)); 277753a5a1b3Sopenharmony_ci 277853a5a1b3Sopenharmony_ci if (s->context->version >= 14) 277953a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, !!(s->flags & PA_STREAM_EARLY_REQUESTS)); 278053a5a1b3Sopenharmony_ci 278153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 278253a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_set_buffer_attr_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 278353a5a1b3Sopenharmony_ci 278453a5a1b3Sopenharmony_ci /* This might cause changes in the read/write index, hence let's 278553a5a1b3Sopenharmony_ci * request a timing update */ 278653a5a1b3Sopenharmony_ci request_auto_timing_update(s, true); 278753a5a1b3Sopenharmony_ci 278853a5a1b3Sopenharmony_ci return o; 278953a5a1b3Sopenharmony_ci} 279053a5a1b3Sopenharmony_ci 279153a5a1b3Sopenharmony_ciuint32_t pa_stream_get_device_index(const pa_stream *s) { 279253a5a1b3Sopenharmony_ci pa_assert(s); 279353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 279453a5a1b3Sopenharmony_ci 279553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX); 279653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); 279753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE, PA_INVALID_INDEX); 279853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX); 279953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->device_index != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX); 280053a5a1b3Sopenharmony_ci 280153a5a1b3Sopenharmony_ci return s->device_index; 280253a5a1b3Sopenharmony_ci} 280353a5a1b3Sopenharmony_ci 280453a5a1b3Sopenharmony_ciconst char *pa_stream_get_device_name(const pa_stream *s) { 280553a5a1b3Sopenharmony_ci pa_assert(s); 280653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 280753a5a1b3Sopenharmony_ci 280853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 280953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 281053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 281153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); 281253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->device_name, PA_ERR_BADSTATE); 281353a5a1b3Sopenharmony_ci 281453a5a1b3Sopenharmony_ci return s->device_name; 281553a5a1b3Sopenharmony_ci} 281653a5a1b3Sopenharmony_ci 281753a5a1b3Sopenharmony_ciint pa_stream_is_suspended(const pa_stream *s) { 281853a5a1b3Sopenharmony_ci pa_assert(s); 281953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 282053a5a1b3Sopenharmony_ci 282153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 282253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 282353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 282453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); 282553a5a1b3Sopenharmony_ci 282653a5a1b3Sopenharmony_ci return s->suspended; 282753a5a1b3Sopenharmony_ci} 282853a5a1b3Sopenharmony_ci 282953a5a1b3Sopenharmony_ciint pa_stream_is_corked(const pa_stream *s) { 283053a5a1b3Sopenharmony_ci pa_assert(s); 283153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 283253a5a1b3Sopenharmony_ci 283353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 283453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 283553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 283653a5a1b3Sopenharmony_ci 283753a5a1b3Sopenharmony_ci return s->corked; 283853a5a1b3Sopenharmony_ci} 283953a5a1b3Sopenharmony_ci 284053a5a1b3Sopenharmony_cistatic void stream_update_sample_rate_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 284153a5a1b3Sopenharmony_ci pa_operation *o = userdata; 284253a5a1b3Sopenharmony_ci int success = 1; 284353a5a1b3Sopenharmony_ci 284453a5a1b3Sopenharmony_ci pa_assert(pd); 284553a5a1b3Sopenharmony_ci pa_assert(o); 284653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 284753a5a1b3Sopenharmony_ci 284853a5a1b3Sopenharmony_ci if (!o->context) 284953a5a1b3Sopenharmony_ci goto finish; 285053a5a1b3Sopenharmony_ci 285153a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 285253a5a1b3Sopenharmony_ci if (pa_context_handle_error(o->context, command, t, false) < 0) 285353a5a1b3Sopenharmony_ci goto finish; 285453a5a1b3Sopenharmony_ci 285553a5a1b3Sopenharmony_ci success = 0; 285653a5a1b3Sopenharmony_ci } else { 285753a5a1b3Sopenharmony_ci 285853a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 285953a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 286053a5a1b3Sopenharmony_ci goto finish; 286153a5a1b3Sopenharmony_ci } 286253a5a1b3Sopenharmony_ci } 286353a5a1b3Sopenharmony_ci 286453a5a1b3Sopenharmony_ci o->stream->sample_spec.rate = PA_PTR_TO_UINT(o->private); 286553a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 286653a5a1b3Sopenharmony_ci if (o->stream->smoother) 286753a5a1b3Sopenharmony_ci pa_smoother_2_set_rate(o->stream->smoother, pa_rtclock_now(), o->stream->sample_spec.rate); 286853a5a1b3Sopenharmony_ci#endif 286953a5a1b3Sopenharmony_ci pa_assert(pa_sample_spec_valid(&o->stream->sample_spec)); 287053a5a1b3Sopenharmony_ci 287153a5a1b3Sopenharmony_ci if (o->callback) { 287253a5a1b3Sopenharmony_ci pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; 287353a5a1b3Sopenharmony_ci cb(o->stream, success, o->userdata); 287453a5a1b3Sopenharmony_ci } 287553a5a1b3Sopenharmony_ci 287653a5a1b3Sopenharmony_cifinish: 287753a5a1b3Sopenharmony_ci pa_operation_done(o); 287853a5a1b3Sopenharmony_ci pa_operation_unref(o); 287953a5a1b3Sopenharmony_ci} 288053a5a1b3Sopenharmony_ci 288153a5a1b3Sopenharmony_cipa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata) { 288253a5a1b3Sopenharmony_ci pa_operation *o; 288353a5a1b3Sopenharmony_ci pa_tagstruct *t; 288453a5a1b3Sopenharmony_ci uint32_t tag; 288553a5a1b3Sopenharmony_ci 288653a5a1b3Sopenharmony_ci pa_assert(s); 288753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 288853a5a1b3Sopenharmony_ci 288953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 289053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, pa_sample_rate_valid(rate), PA_ERR_INVALID); 289153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 289253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 289353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->flags & PA_STREAM_VARIABLE_RATE, PA_ERR_BADSTATE); 289453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 12, PA_ERR_NOTSUPPORTED); 289553a5a1b3Sopenharmony_ci 289653a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 289753a5a1b3Sopenharmony_ci o->private = PA_UINT_TO_PTR(rate); 289853a5a1b3Sopenharmony_ci 289953a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 290053a5a1b3Sopenharmony_ci s->context, 290153a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE : PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE), 290253a5a1b3Sopenharmony_ci &tag); 290353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 290453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, rate); 290553a5a1b3Sopenharmony_ci 290653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 290753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_update_sample_rate_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 290853a5a1b3Sopenharmony_ci 290953a5a1b3Sopenharmony_ci return o; 291053a5a1b3Sopenharmony_ci} 291153a5a1b3Sopenharmony_ci 291253a5a1b3Sopenharmony_cipa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata) { 291353a5a1b3Sopenharmony_ci pa_operation *o; 291453a5a1b3Sopenharmony_ci pa_tagstruct *t; 291553a5a1b3Sopenharmony_ci uint32_t tag; 291653a5a1b3Sopenharmony_ci 291753a5a1b3Sopenharmony_ci pa_assert(s); 291853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 291953a5a1b3Sopenharmony_ci 292053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 292153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID); 292253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 292353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 292453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED); 292553a5a1b3Sopenharmony_ci 292653a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 292753a5a1b3Sopenharmony_ci 292853a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 292953a5a1b3Sopenharmony_ci s->context, 293053a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST : PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST), 293153a5a1b3Sopenharmony_ci &tag); 293253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 293353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) mode); 293453a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, p); 293553a5a1b3Sopenharmony_ci 293653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 293753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 293853a5a1b3Sopenharmony_ci 293953a5a1b3Sopenharmony_ci /* Please note that we don't update s->proplist here, because we 294053a5a1b3Sopenharmony_ci * don't export that field */ 294153a5a1b3Sopenharmony_ci 294253a5a1b3Sopenharmony_ci return o; 294353a5a1b3Sopenharmony_ci} 294453a5a1b3Sopenharmony_ci 294553a5a1b3Sopenharmony_cipa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata) { 294653a5a1b3Sopenharmony_ci pa_operation *o; 294753a5a1b3Sopenharmony_ci pa_tagstruct *t; 294853a5a1b3Sopenharmony_ci uint32_t tag; 294953a5a1b3Sopenharmony_ci const char * const*k; 295053a5a1b3Sopenharmony_ci 295153a5a1b3Sopenharmony_ci pa_assert(s); 295253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 295353a5a1b3Sopenharmony_ci 295453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, !pa_detect_fork(), PA_ERR_FORKED); 295553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, keys && keys[0], PA_ERR_INVALID); 295653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); 295753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); 295853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED); 295953a5a1b3Sopenharmony_ci 296053a5a1b3Sopenharmony_ci o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); 296153a5a1b3Sopenharmony_ci 296253a5a1b3Sopenharmony_ci t = pa_tagstruct_command( 296353a5a1b3Sopenharmony_ci s->context, 296453a5a1b3Sopenharmony_ci (uint32_t) (s->direction == PA_STREAM_RECORD ? PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST : PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST), 296553a5a1b3Sopenharmony_ci &tag); 296653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->channel); 296753a5a1b3Sopenharmony_ci 296853a5a1b3Sopenharmony_ci for (k = keys; *k; k++) 296953a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, *k); 297053a5a1b3Sopenharmony_ci 297153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, NULL); 297253a5a1b3Sopenharmony_ci 297353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->context->pstream, t); 297453a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 297553a5a1b3Sopenharmony_ci 297653a5a1b3Sopenharmony_ci /* Please note that we don't update s->proplist here, because we 297753a5a1b3Sopenharmony_ci * don't export that field */ 297853a5a1b3Sopenharmony_ci 297953a5a1b3Sopenharmony_ci return o; 298053a5a1b3Sopenharmony_ci} 298153a5a1b3Sopenharmony_ci 298253a5a1b3Sopenharmony_ciint pa_stream_set_monitor_stream(pa_stream *s, uint32_t sink_input_idx) { 298353a5a1b3Sopenharmony_ci pa_assert(s); 298453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 298553a5a1b3Sopenharmony_ci 298653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, !pa_detect_fork(), PA_ERR_FORKED); 298753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, sink_input_idx != PA_INVALID_INDEX, PA_ERR_INVALID); 298853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); 298953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED); 299053a5a1b3Sopenharmony_ci 299153a5a1b3Sopenharmony_ci s->direct_on_input = sink_input_idx; 299253a5a1b3Sopenharmony_ci 299353a5a1b3Sopenharmony_ci return 0; 299453a5a1b3Sopenharmony_ci} 299553a5a1b3Sopenharmony_ci 299653a5a1b3Sopenharmony_ciuint32_t pa_stream_get_monitor_stream(const pa_stream *s) { 299753a5a1b3Sopenharmony_ci pa_assert(s); 299853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(s) >= 1); 299953a5a1b3Sopenharmony_ci 300053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX); 300153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direct_on_input != PA_INVALID_INDEX, PA_ERR_BADSTATE, PA_INVALID_INDEX); 300253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->context->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX); 300353a5a1b3Sopenharmony_ci 300453a5a1b3Sopenharmony_ci return s->direct_on_input; 300553a5a1b3Sopenharmony_ci} 3006