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, &copy, NULL);
276153a5a1b3Sopenharmony_ci    attr = &copy;
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