153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci
653a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
753a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
853a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
953a5a1b3Sopenharmony_ci  or (at your option) any later version.
1053a5a1b3Sopenharmony_ci
1153a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1253a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1353a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1453a5a1b3Sopenharmony_ci  General Public License for more details.
1553a5a1b3Sopenharmony_ci
1653a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1753a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1853a5a1b3Sopenharmony_ci***/
1953a5a1b3Sopenharmony_ci
2053a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2153a5a1b3Sopenharmony_ci#include <config.h>
2253a5a1b3Sopenharmony_ci#endif
2353a5a1b3Sopenharmony_ci
2453a5a1b3Sopenharmony_ci#include <stdlib.h>
2553a5a1b3Sopenharmony_ci#include <stdio.h>
2653a5a1b3Sopenharmony_ci#include <errno.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
2953a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
3053a5a1b3Sopenharmony_ci
3153a5a1b3Sopenharmony_ci#include <pulsecore/sink-input.h>
3253a5a1b3Sopenharmony_ci#include <pulsecore/source-output.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/client.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/atomic.h>
3953a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h>
4053a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
4153a5a1b3Sopenharmony_ci#include <pulsecore/shared.h>
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci#include "protocol-simple.h"
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_ci/* Don't allow more than this many concurrent connections */
4653a5a1b3Sopenharmony_ci#define MAX_CONNECTIONS 10
4753a5a1b3Sopenharmony_ci
4853a5a1b3Sopenharmony_citypedef struct connection {
4953a5a1b3Sopenharmony_ci    pa_msgobject parent;
5053a5a1b3Sopenharmony_ci    pa_simple_protocol *protocol;
5153a5a1b3Sopenharmony_ci    pa_simple_options *options;
5253a5a1b3Sopenharmony_ci    pa_iochannel *io;
5353a5a1b3Sopenharmony_ci    pa_sink_input *sink_input;
5453a5a1b3Sopenharmony_ci    pa_source_output *source_output;
5553a5a1b3Sopenharmony_ci    pa_client *client;
5653a5a1b3Sopenharmony_ci    pa_memblockq *input_memblockq, *output_memblockq;
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_ci    bool dead;
5953a5a1b3Sopenharmony_ci
6053a5a1b3Sopenharmony_ci    struct {
6153a5a1b3Sopenharmony_ci        pa_memblock *current_memblock;
6253a5a1b3Sopenharmony_ci        size_t memblock_index;
6353a5a1b3Sopenharmony_ci        pa_atomic_t missing;
6453a5a1b3Sopenharmony_ci        bool underrun;
6553a5a1b3Sopenharmony_ci    } playback;
6653a5a1b3Sopenharmony_ci} connection;
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ciPA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
6953a5a1b3Sopenharmony_ci#define CONNECTION(o) (connection_cast(o))
7053a5a1b3Sopenharmony_ci
7153a5a1b3Sopenharmony_cistruct pa_simple_protocol {
7253a5a1b3Sopenharmony_ci    PA_REFCNT_DECLARE;
7353a5a1b3Sopenharmony_ci
7453a5a1b3Sopenharmony_ci    pa_core *core;
7553a5a1b3Sopenharmony_ci    pa_idxset *connections;
7653a5a1b3Sopenharmony_ci};
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_cienum {
7953a5a1b3Sopenharmony_ci    SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */
8053a5a1b3Sopenharmony_ci    SINK_INPUT_MESSAGE_DISABLE_PREBUF /* disabled prebuf, get playback started. */
8153a5a1b3Sopenharmony_ci};
8253a5a1b3Sopenharmony_ci
8353a5a1b3Sopenharmony_cienum {
8453a5a1b3Sopenharmony_ci    CONNECTION_MESSAGE_REQUEST_DATA,      /* data requested from sink input from the main loop */
8553a5a1b3Sopenharmony_ci    CONNECTION_MESSAGE_POST_DATA,         /* data from source output to main loop */
8653a5a1b3Sopenharmony_ci    CONNECTION_MESSAGE_UNLINK_CONNECTION  /* Please drop the connection now */
8753a5a1b3Sopenharmony_ci};
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci#define PLAYBACK_BUFFER_SECONDS (.5)
9053a5a1b3Sopenharmony_ci#define PLAYBACK_BUFFER_FRAGMENTS (10)
9153a5a1b3Sopenharmony_ci#define RECORD_BUFFER_SECONDS (5)
9253a5a1b3Sopenharmony_ci#define DEFAULT_SINK_LATENCY (300*PA_USEC_PER_MSEC)
9353a5a1b3Sopenharmony_ci#define DEFAULT_SOURCE_LATENCY (300*PA_USEC_PER_MSEC)
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_cistatic void connection_unlink(connection *c) {
9653a5a1b3Sopenharmony_ci    pa_assert(c);
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    if (!c->protocol)
9953a5a1b3Sopenharmony_ci        return;
10053a5a1b3Sopenharmony_ci
10153a5a1b3Sopenharmony_ci    if (c->options) {
10253a5a1b3Sopenharmony_ci        pa_simple_options_unref(c->options);
10353a5a1b3Sopenharmony_ci        c->options = NULL;
10453a5a1b3Sopenharmony_ci    }
10553a5a1b3Sopenharmony_ci
10653a5a1b3Sopenharmony_ci    if (c->sink_input) {
10753a5a1b3Sopenharmony_ci        pa_sink_input_unlink(c->sink_input);
10853a5a1b3Sopenharmony_ci        pa_sink_input_unref(c->sink_input);
10953a5a1b3Sopenharmony_ci        c->sink_input = NULL;
11053a5a1b3Sopenharmony_ci    }
11153a5a1b3Sopenharmony_ci
11253a5a1b3Sopenharmony_ci    if (c->source_output) {
11353a5a1b3Sopenharmony_ci        pa_source_output_unlink(c->source_output);
11453a5a1b3Sopenharmony_ci        pa_source_output_unref(c->source_output);
11553a5a1b3Sopenharmony_ci        c->source_output = NULL;
11653a5a1b3Sopenharmony_ci    }
11753a5a1b3Sopenharmony_ci
11853a5a1b3Sopenharmony_ci    if (c->client) {
11953a5a1b3Sopenharmony_ci        pa_client_free(c->client);
12053a5a1b3Sopenharmony_ci        c->client = NULL;
12153a5a1b3Sopenharmony_ci    }
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    if (c->io) {
12453a5a1b3Sopenharmony_ci        pa_iochannel_free(c->io);
12553a5a1b3Sopenharmony_ci        c->io = NULL;
12653a5a1b3Sopenharmony_ci    }
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_ci    pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
12953a5a1b3Sopenharmony_ci    c->protocol = NULL;
13053a5a1b3Sopenharmony_ci    connection_unref(c);
13153a5a1b3Sopenharmony_ci}
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_cistatic void connection_free(pa_object *o) {
13453a5a1b3Sopenharmony_ci    connection *c = CONNECTION(o);
13553a5a1b3Sopenharmony_ci    pa_assert(c);
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci    if (c->playback.current_memblock)
13853a5a1b3Sopenharmony_ci        pa_memblock_unref(c->playback.current_memblock);
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci    if (c->input_memblockq)
14153a5a1b3Sopenharmony_ci        pa_memblockq_free(c->input_memblockq);
14253a5a1b3Sopenharmony_ci    if (c->output_memblockq)
14353a5a1b3Sopenharmony_ci        pa_memblockq_free(c->output_memblockq);
14453a5a1b3Sopenharmony_ci
14553a5a1b3Sopenharmony_ci    pa_xfree(c);
14653a5a1b3Sopenharmony_ci}
14753a5a1b3Sopenharmony_ci
14853a5a1b3Sopenharmony_cistatic int do_read(connection *c) {
14953a5a1b3Sopenharmony_ci    pa_memchunk chunk;
15053a5a1b3Sopenharmony_ci    ssize_t r;
15153a5a1b3Sopenharmony_ci    size_t l;
15253a5a1b3Sopenharmony_ci    void *p;
15353a5a1b3Sopenharmony_ci    size_t space = 0;
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    connection_assert_ref(c);
15653a5a1b3Sopenharmony_ci
15753a5a1b3Sopenharmony_ci    if (!c->sink_input || (l = (size_t) pa_atomic_load(&c->playback.missing)) <= 0)
15853a5a1b3Sopenharmony_ci        return 0;
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci    if (c->playback.current_memblock) {
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci        space = pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index;
16353a5a1b3Sopenharmony_ci
16453a5a1b3Sopenharmony_ci        if (space <= 0) {
16553a5a1b3Sopenharmony_ci            pa_memblock_unref(c->playback.current_memblock);
16653a5a1b3Sopenharmony_ci            c->playback.current_memblock = NULL;
16753a5a1b3Sopenharmony_ci        }
16853a5a1b3Sopenharmony_ci    }
16953a5a1b3Sopenharmony_ci
17053a5a1b3Sopenharmony_ci    if (!c->playback.current_memblock) {
17153a5a1b3Sopenharmony_ci        pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1));
17253a5a1b3Sopenharmony_ci        c->playback.memblock_index = 0;
17353a5a1b3Sopenharmony_ci
17453a5a1b3Sopenharmony_ci        space = pa_memblock_get_length(c->playback.current_memblock);
17553a5a1b3Sopenharmony_ci    }
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci    if (l > space)
17853a5a1b3Sopenharmony_ci        l = space;
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci    p = pa_memblock_acquire(c->playback.current_memblock);
18153a5a1b3Sopenharmony_ci    r = pa_iochannel_read(c->io, (uint8_t*) p + c->playback.memblock_index, l);
18253a5a1b3Sopenharmony_ci    pa_memblock_release(c->playback.current_memblock);
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    if (r <= 0) {
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci        if (r < 0 && errno == EAGAIN)
18753a5a1b3Sopenharmony_ci            return 0;
18853a5a1b3Sopenharmony_ci
18953a5a1b3Sopenharmony_ci        pa_log_debug("read(): %s", r == 0 ? "EOF" : pa_cstrerror(errno));
19053a5a1b3Sopenharmony_ci        return -1;
19153a5a1b3Sopenharmony_ci    }
19253a5a1b3Sopenharmony_ci
19353a5a1b3Sopenharmony_ci    chunk.memblock = c->playback.current_memblock;
19453a5a1b3Sopenharmony_ci    chunk.index = c->playback.memblock_index;
19553a5a1b3Sopenharmony_ci    chunk.length = (size_t) r;
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    c->playback.memblock_index += (size_t) r;
19853a5a1b3Sopenharmony_ci
19953a5a1b3Sopenharmony_ci    pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL);
20053a5a1b3Sopenharmony_ci    pa_atomic_sub(&c->playback.missing, (int) r);
20153a5a1b3Sopenharmony_ci
20253a5a1b3Sopenharmony_ci    return 0;
20353a5a1b3Sopenharmony_ci}
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_cistatic int do_write(connection *c) {
20653a5a1b3Sopenharmony_ci    pa_memchunk chunk;
20753a5a1b3Sopenharmony_ci    ssize_t r;
20853a5a1b3Sopenharmony_ci    void *p;
20953a5a1b3Sopenharmony_ci
21053a5a1b3Sopenharmony_ci    connection_assert_ref(c);
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_ci    if (!c->source_output)
21353a5a1b3Sopenharmony_ci        return 0;
21453a5a1b3Sopenharmony_ci
21553a5a1b3Sopenharmony_ci    if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) {
21653a5a1b3Sopenharmony_ci/*         pa_log("peek failed"); */
21753a5a1b3Sopenharmony_ci        return 0;
21853a5a1b3Sopenharmony_ci    }
21953a5a1b3Sopenharmony_ci
22053a5a1b3Sopenharmony_ci    pa_assert(chunk.memblock);
22153a5a1b3Sopenharmony_ci    pa_assert(chunk.length);
22253a5a1b3Sopenharmony_ci
22353a5a1b3Sopenharmony_ci    p = pa_memblock_acquire(chunk.memblock);
22453a5a1b3Sopenharmony_ci    r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
22553a5a1b3Sopenharmony_ci    pa_memblock_release(chunk.memblock);
22653a5a1b3Sopenharmony_ci
22753a5a1b3Sopenharmony_ci    pa_memblock_unref(chunk.memblock);
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci    if (r < 0) {
23053a5a1b3Sopenharmony_ci        pa_log("write(): %s", pa_cstrerror(errno));
23153a5a1b3Sopenharmony_ci        return -1;
23253a5a1b3Sopenharmony_ci    }
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_ci    pa_memblockq_drop(c->output_memblockq, (size_t) r);
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci    return 1;
23753a5a1b3Sopenharmony_ci}
23853a5a1b3Sopenharmony_ci
23953a5a1b3Sopenharmony_cistatic void do_work(connection *c) {
24053a5a1b3Sopenharmony_ci    connection_assert_ref(c);
24153a5a1b3Sopenharmony_ci
24253a5a1b3Sopenharmony_ci    if (c->dead)
24353a5a1b3Sopenharmony_ci        return;
24453a5a1b3Sopenharmony_ci
24553a5a1b3Sopenharmony_ci    if (pa_iochannel_is_readable(c->io))
24653a5a1b3Sopenharmony_ci        if (do_read(c) < 0)
24753a5a1b3Sopenharmony_ci            goto fail;
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_ci    if (!c->sink_input && pa_iochannel_is_hungup(c->io))
25053a5a1b3Sopenharmony_ci        goto fail;
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci    while (pa_iochannel_is_writable(c->io)) {
25353a5a1b3Sopenharmony_ci        int r = do_write(c);
25453a5a1b3Sopenharmony_ci        if (r < 0)
25553a5a1b3Sopenharmony_ci            goto fail;
25653a5a1b3Sopenharmony_ci        if (r == 0)
25753a5a1b3Sopenharmony_ci            break;
25853a5a1b3Sopenharmony_ci    }
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_ci    return;
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_cifail:
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_ci    if (c->sink_input) {
26553a5a1b3Sopenharmony_ci
26653a5a1b3Sopenharmony_ci        /* If there is a sink input, we first drain what we already have read before shutting down the connection */
26753a5a1b3Sopenharmony_ci        c->dead = true;
26853a5a1b3Sopenharmony_ci
26953a5a1b3Sopenharmony_ci        pa_iochannel_free(c->io);
27053a5a1b3Sopenharmony_ci        c->io = NULL;
27153a5a1b3Sopenharmony_ci
27253a5a1b3Sopenharmony_ci        pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL);
27353a5a1b3Sopenharmony_ci    } else
27453a5a1b3Sopenharmony_ci        connection_unlink(c);
27553a5a1b3Sopenharmony_ci}
27653a5a1b3Sopenharmony_ci
27753a5a1b3Sopenharmony_cistatic int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
27853a5a1b3Sopenharmony_ci    connection *c = CONNECTION(o);
27953a5a1b3Sopenharmony_ci    connection_assert_ref(c);
28053a5a1b3Sopenharmony_ci
28153a5a1b3Sopenharmony_ci    if (!c->protocol)
28253a5a1b3Sopenharmony_ci        return -1;
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci    switch (code) {
28553a5a1b3Sopenharmony_ci        case CONNECTION_MESSAGE_REQUEST_DATA:
28653a5a1b3Sopenharmony_ci            do_work(c);
28753a5a1b3Sopenharmony_ci            break;
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci        case CONNECTION_MESSAGE_POST_DATA:
29053a5a1b3Sopenharmony_ci/*             pa_log("got data %u", chunk->length); */
29153a5a1b3Sopenharmony_ci            pa_memblockq_push_align(c->output_memblockq, chunk);
29253a5a1b3Sopenharmony_ci            do_work(c);
29353a5a1b3Sopenharmony_ci            break;
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci        case CONNECTION_MESSAGE_UNLINK_CONNECTION:
29653a5a1b3Sopenharmony_ci            connection_unlink(c);
29753a5a1b3Sopenharmony_ci            break;
29853a5a1b3Sopenharmony_ci    }
29953a5a1b3Sopenharmony_ci
30053a5a1b3Sopenharmony_ci    return 0;
30153a5a1b3Sopenharmony_ci}
30253a5a1b3Sopenharmony_ci
30353a5a1b3Sopenharmony_ci/*** sink_input callbacks ***/
30453a5a1b3Sopenharmony_ci
30553a5a1b3Sopenharmony_ci/* Called from thread context */
30653a5a1b3Sopenharmony_cistatic int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
30753a5a1b3Sopenharmony_ci    pa_sink_input *i = PA_SINK_INPUT(o);
30853a5a1b3Sopenharmony_ci    connection*c;
30953a5a1b3Sopenharmony_ci
31053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
31153a5a1b3Sopenharmony_ci    c = CONNECTION(i->userdata);
31253a5a1b3Sopenharmony_ci    connection_assert_ref(c);
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_ci    switch (code) {
31553a5a1b3Sopenharmony_ci
31653a5a1b3Sopenharmony_ci        case SINK_INPUT_MESSAGE_POST_DATA: {
31753a5a1b3Sopenharmony_ci            pa_assert(chunk);
31853a5a1b3Sopenharmony_ci
31953a5a1b3Sopenharmony_ci            /* New data from the main loop */
32053a5a1b3Sopenharmony_ci            pa_memblockq_push_align(c->input_memblockq, chunk);
32153a5a1b3Sopenharmony_ci
32253a5a1b3Sopenharmony_ci            if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
32353a5a1b3Sopenharmony_ci                pa_log_debug("Requesting rewind due to end of underrun.");
32453a5a1b3Sopenharmony_ci                pa_sink_input_request_rewind(c->sink_input, 0, false, true, false);
32553a5a1b3Sopenharmony_ci            }
32653a5a1b3Sopenharmony_ci
32753a5a1b3Sopenharmony_ci/*             pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci            return 0;
33053a5a1b3Sopenharmony_ci        }
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci        case SINK_INPUT_MESSAGE_DISABLE_PREBUF:
33353a5a1b3Sopenharmony_ci            pa_memblockq_prebuf_disable(c->input_memblockq);
33453a5a1b3Sopenharmony_ci            return 0;
33553a5a1b3Sopenharmony_ci
33653a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
33753a5a1b3Sopenharmony_ci            pa_usec_t *r = userdata;
33853a5a1b3Sopenharmony_ci
33953a5a1b3Sopenharmony_ci            /* The default handler will add in the extra latency added by the resampler.*/
34053a5a1b3Sopenharmony_ci            *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
34153a5a1b3Sopenharmony_ci        }
34253a5a1b3Sopenharmony_ci        /* Fall through. */
34353a5a1b3Sopenharmony_ci
34453a5a1b3Sopenharmony_ci        default:
34553a5a1b3Sopenharmony_ci            return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
34653a5a1b3Sopenharmony_ci    }
34753a5a1b3Sopenharmony_ci}
34853a5a1b3Sopenharmony_ci
34953a5a1b3Sopenharmony_ci/* Called from thread context */
35053a5a1b3Sopenharmony_cistatic int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
35153a5a1b3Sopenharmony_ci    connection *c;
35253a5a1b3Sopenharmony_ci
35353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
35453a5a1b3Sopenharmony_ci    c = CONNECTION(i->userdata);
35553a5a1b3Sopenharmony_ci    connection_assert_ref(c);
35653a5a1b3Sopenharmony_ci    pa_assert(chunk);
35753a5a1b3Sopenharmony_ci
35853a5a1b3Sopenharmony_ci    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
35953a5a1b3Sopenharmony_ci
36053a5a1b3Sopenharmony_ci        c->playback.underrun = true;
36153a5a1b3Sopenharmony_ci
36253a5a1b3Sopenharmony_ci        if (c->dead && pa_sink_input_safe_to_remove(i))
36353a5a1b3Sopenharmony_ci            pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL);
36453a5a1b3Sopenharmony_ci
36553a5a1b3Sopenharmony_ci        return -1;
36653a5a1b3Sopenharmony_ci    } else {
36753a5a1b3Sopenharmony_ci        size_t m;
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci        chunk->length = PA_MIN(length, chunk->length);
37053a5a1b3Sopenharmony_ci
37153a5a1b3Sopenharmony_ci        c->playback.underrun = false;
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_ci        pa_memblockq_drop(c->input_memblockq, chunk->length);
37453a5a1b3Sopenharmony_ci        m = pa_memblockq_pop_missing(c->input_memblockq);
37553a5a1b3Sopenharmony_ci
37653a5a1b3Sopenharmony_ci        if (m > 0)
37753a5a1b3Sopenharmony_ci            if (pa_atomic_add(&c->playback.missing, (int) m) <= 0)
37853a5a1b3Sopenharmony_ci                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
37953a5a1b3Sopenharmony_ci
38053a5a1b3Sopenharmony_ci        return 0;
38153a5a1b3Sopenharmony_ci    }
38253a5a1b3Sopenharmony_ci}
38353a5a1b3Sopenharmony_ci
38453a5a1b3Sopenharmony_ci/* Called from thread context */
38553a5a1b3Sopenharmony_cistatic void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
38653a5a1b3Sopenharmony_ci    connection *c;
38753a5a1b3Sopenharmony_ci
38853a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
38953a5a1b3Sopenharmony_ci    c = CONNECTION(i->userdata);
39053a5a1b3Sopenharmony_ci    connection_assert_ref(c);
39153a5a1b3Sopenharmony_ci
39253a5a1b3Sopenharmony_ci    /* If we are in an underrun, then we don't rewind */
39353a5a1b3Sopenharmony_ci    if (i->thread_info.underrun_for > 0)
39453a5a1b3Sopenharmony_ci        return;
39553a5a1b3Sopenharmony_ci
39653a5a1b3Sopenharmony_ci    pa_memblockq_rewind(c->input_memblockq, nbytes);
39753a5a1b3Sopenharmony_ci}
39853a5a1b3Sopenharmony_ci
39953a5a1b3Sopenharmony_ci/* Called from thread context */
40053a5a1b3Sopenharmony_cistatic void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
40153a5a1b3Sopenharmony_ci    connection *c;
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
40453a5a1b3Sopenharmony_ci    c = CONNECTION(i->userdata);
40553a5a1b3Sopenharmony_ci    connection_assert_ref(c);
40653a5a1b3Sopenharmony_ci
40753a5a1b3Sopenharmony_ci    pa_memblockq_set_maxrewind(c->input_memblockq, nbytes);
40853a5a1b3Sopenharmony_ci}
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci/* Called from main context */
41153a5a1b3Sopenharmony_cistatic void sink_input_kill_cb(pa_sink_input *i) {
41253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
41353a5a1b3Sopenharmony_ci
41453a5a1b3Sopenharmony_ci    connection_unlink(CONNECTION(i->userdata));
41553a5a1b3Sopenharmony_ci}
41653a5a1b3Sopenharmony_ci
41753a5a1b3Sopenharmony_ci/*** source_output callbacks ***/
41853a5a1b3Sopenharmony_ci
41953a5a1b3Sopenharmony_ci/* Called from thread context */
42053a5a1b3Sopenharmony_cistatic void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
42153a5a1b3Sopenharmony_ci    connection *c;
42253a5a1b3Sopenharmony_ci
42353a5a1b3Sopenharmony_ci    pa_source_output_assert_ref(o);
42453a5a1b3Sopenharmony_ci    c = CONNECTION(o->userdata);
42553a5a1b3Sopenharmony_ci    pa_assert(c);
42653a5a1b3Sopenharmony_ci    pa_assert(chunk);
42753a5a1b3Sopenharmony_ci
42853a5a1b3Sopenharmony_ci    pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
42953a5a1b3Sopenharmony_ci}
43053a5a1b3Sopenharmony_ci
43153a5a1b3Sopenharmony_ci/* Called from main context */
43253a5a1b3Sopenharmony_cistatic void source_output_kill_cb(pa_source_output *o) {
43353a5a1b3Sopenharmony_ci    pa_source_output_assert_ref(o);
43453a5a1b3Sopenharmony_ci
43553a5a1b3Sopenharmony_ci    connection_unlink(CONNECTION(o->userdata));
43653a5a1b3Sopenharmony_ci}
43753a5a1b3Sopenharmony_ci
43853a5a1b3Sopenharmony_ci/* Called from main context */
43953a5a1b3Sopenharmony_cistatic pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
44053a5a1b3Sopenharmony_ci    connection*c;
44153a5a1b3Sopenharmony_ci
44253a5a1b3Sopenharmony_ci    pa_source_output_assert_ref(o);
44353a5a1b3Sopenharmony_ci    c = CONNECTION(o->userdata);
44453a5a1b3Sopenharmony_ci    pa_assert(c);
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci    return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
44753a5a1b3Sopenharmony_ci}
44853a5a1b3Sopenharmony_ci
44953a5a1b3Sopenharmony_ci/*** client callbacks ***/
45053a5a1b3Sopenharmony_ci
45153a5a1b3Sopenharmony_cistatic void client_kill_cb(pa_client *client) {
45253a5a1b3Sopenharmony_ci    connection*c;
45353a5a1b3Sopenharmony_ci
45453a5a1b3Sopenharmony_ci    pa_assert(client);
45553a5a1b3Sopenharmony_ci    c = CONNECTION(client->userdata);
45653a5a1b3Sopenharmony_ci    pa_assert(c);
45753a5a1b3Sopenharmony_ci
45853a5a1b3Sopenharmony_ci    connection_unlink(c);
45953a5a1b3Sopenharmony_ci}
46053a5a1b3Sopenharmony_ci
46153a5a1b3Sopenharmony_ci/*** pa_iochannel callbacks ***/
46253a5a1b3Sopenharmony_ci
46353a5a1b3Sopenharmony_cistatic void io_callback(pa_iochannel*io, void *userdata) {
46453a5a1b3Sopenharmony_ci    connection *c = CONNECTION(userdata);
46553a5a1b3Sopenharmony_ci
46653a5a1b3Sopenharmony_ci    connection_assert_ref(c);
46753a5a1b3Sopenharmony_ci    pa_assert(io);
46853a5a1b3Sopenharmony_ci
46953a5a1b3Sopenharmony_ci    do_work(c);
47053a5a1b3Sopenharmony_ci}
47153a5a1b3Sopenharmony_ci
47253a5a1b3Sopenharmony_ci/*** socket_server callbacks ***/
47353a5a1b3Sopenharmony_ci
47453a5a1b3Sopenharmony_civoid pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simple_options *o) {
47553a5a1b3Sopenharmony_ci    connection *c = NULL;
47653a5a1b3Sopenharmony_ci    char pname[128];
47753a5a1b3Sopenharmony_ci    pa_client_new_data client_data;
47853a5a1b3Sopenharmony_ci
47953a5a1b3Sopenharmony_ci    pa_assert(p);
48053a5a1b3Sopenharmony_ci    pa_assert(io);
48153a5a1b3Sopenharmony_ci    pa_assert(o);
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_ci    if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) {
48453a5a1b3Sopenharmony_ci        pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS);
48553a5a1b3Sopenharmony_ci        pa_iochannel_free(io);
48653a5a1b3Sopenharmony_ci        return;
48753a5a1b3Sopenharmony_ci    }
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_ci    c = pa_msgobject_new(connection);
49053a5a1b3Sopenharmony_ci    c->parent.parent.free = connection_free;
49153a5a1b3Sopenharmony_ci    c->parent.process_msg = connection_process_msg;
49253a5a1b3Sopenharmony_ci    c->io = io;
49353a5a1b3Sopenharmony_ci    pa_iochannel_set_callback(c->io, io_callback, c);
49453a5a1b3Sopenharmony_ci
49553a5a1b3Sopenharmony_ci    c->sink_input = NULL;
49653a5a1b3Sopenharmony_ci    c->source_output = NULL;
49753a5a1b3Sopenharmony_ci    c->input_memblockq = c->output_memblockq = NULL;
49853a5a1b3Sopenharmony_ci    c->protocol = p;
49953a5a1b3Sopenharmony_ci    c->options = pa_simple_options_ref(o);
50053a5a1b3Sopenharmony_ci    c->playback.current_memblock = NULL;
50153a5a1b3Sopenharmony_ci    c->playback.memblock_index = 0;
50253a5a1b3Sopenharmony_ci    c->dead = false;
50353a5a1b3Sopenharmony_ci    c->playback.underrun = true;
50453a5a1b3Sopenharmony_ci    pa_atomic_store(&c->playback.missing, 0);
50553a5a1b3Sopenharmony_ci
50653a5a1b3Sopenharmony_ci    pa_client_new_data_init(&client_data);
50753a5a1b3Sopenharmony_ci    client_data.module = o->module;
50853a5a1b3Sopenharmony_ci    client_data.driver = __FILE__;
50953a5a1b3Sopenharmony_ci    pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
51053a5a1b3Sopenharmony_ci    pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "Simple client (%s)", pname);
51153a5a1b3Sopenharmony_ci    pa_proplist_sets(client_data.proplist, "simple-protocol.peer", pname);
51253a5a1b3Sopenharmony_ci    c->client = pa_client_new(p->core, &client_data);
51353a5a1b3Sopenharmony_ci    pa_client_new_data_done(&client_data);
51453a5a1b3Sopenharmony_ci
51553a5a1b3Sopenharmony_ci    if (!c->client)
51653a5a1b3Sopenharmony_ci        goto fail;
51753a5a1b3Sopenharmony_ci
51853a5a1b3Sopenharmony_ci    c->client->kill = client_kill_cb;
51953a5a1b3Sopenharmony_ci    c->client->userdata = c;
52053a5a1b3Sopenharmony_ci
52153a5a1b3Sopenharmony_ci    if (o->playback) {
52253a5a1b3Sopenharmony_ci        pa_sink_input_new_data data;
52353a5a1b3Sopenharmony_ci        pa_memchunk silence;
52453a5a1b3Sopenharmony_ci        size_t l;
52553a5a1b3Sopenharmony_ci        pa_sink *sink;
52653a5a1b3Sopenharmony_ci
52753a5a1b3Sopenharmony_ci        if (!(sink = pa_namereg_get(c->protocol->core, o->default_sink, PA_NAMEREG_SINK))) {
52853a5a1b3Sopenharmony_ci            pa_log("Failed to get sink.");
52953a5a1b3Sopenharmony_ci            goto fail;
53053a5a1b3Sopenharmony_ci        }
53153a5a1b3Sopenharmony_ci
53253a5a1b3Sopenharmony_ci        pa_sink_input_new_data_init(&data);
53353a5a1b3Sopenharmony_ci        data.driver = __FILE__;
53453a5a1b3Sopenharmony_ci        data.module = o->module;
53553a5a1b3Sopenharmony_ci        data.client = c->client;
53653a5a1b3Sopenharmony_ci        pa_sink_input_new_data_set_sink(&data, sink, false, true);
53753a5a1b3Sopenharmony_ci        pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
53853a5a1b3Sopenharmony_ci        pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec);
53953a5a1b3Sopenharmony_ci
54053a5a1b3Sopenharmony_ci        pa_sink_input_new(&c->sink_input, p->core, &data);
54153a5a1b3Sopenharmony_ci        pa_sink_input_new_data_done(&data);
54253a5a1b3Sopenharmony_ci
54353a5a1b3Sopenharmony_ci        if (!c->sink_input) {
54453a5a1b3Sopenharmony_ci            pa_log("Failed to create sink input.");
54553a5a1b3Sopenharmony_ci            goto fail;
54653a5a1b3Sopenharmony_ci        }
54753a5a1b3Sopenharmony_ci
54853a5a1b3Sopenharmony_ci        c->sink_input->parent.process_msg = sink_input_process_msg;
54953a5a1b3Sopenharmony_ci        c->sink_input->pop = sink_input_pop_cb;
55053a5a1b3Sopenharmony_ci        c->sink_input->process_rewind = sink_input_process_rewind_cb;
55153a5a1b3Sopenharmony_ci        c->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
55253a5a1b3Sopenharmony_ci        c->sink_input->kill = sink_input_kill_cb;
55353a5a1b3Sopenharmony_ci        c->sink_input->userdata = c;
55453a5a1b3Sopenharmony_ci
55553a5a1b3Sopenharmony_ci        pa_sink_input_set_requested_latency(c->sink_input, DEFAULT_SINK_LATENCY);
55653a5a1b3Sopenharmony_ci
55753a5a1b3Sopenharmony_ci        l = (size_t) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
55853a5a1b3Sopenharmony_ci        pa_sink_input_get_silence(c->sink_input, &silence);
55953a5a1b3Sopenharmony_ci        c->input_memblockq = pa_memblockq_new(
56053a5a1b3Sopenharmony_ci                "simple protocol connection input_memblockq",
56153a5a1b3Sopenharmony_ci                0,
56253a5a1b3Sopenharmony_ci                l,
56353a5a1b3Sopenharmony_ci                l,
56453a5a1b3Sopenharmony_ci                &o->sample_spec,
56553a5a1b3Sopenharmony_ci                (size_t) -1,
56653a5a1b3Sopenharmony_ci                l/PLAYBACK_BUFFER_FRAGMENTS,
56753a5a1b3Sopenharmony_ci                0,
56853a5a1b3Sopenharmony_ci                &silence);
56953a5a1b3Sopenharmony_ci        pa_memblock_unref(silence.memblock);
57053a5a1b3Sopenharmony_ci
57153a5a1b3Sopenharmony_ci        pa_iochannel_socket_set_rcvbuf(io, l);
57253a5a1b3Sopenharmony_ci
57353a5a1b3Sopenharmony_ci        pa_atomic_store(&c->playback.missing, (int) pa_memblockq_pop_missing(c->input_memblockq));
57453a5a1b3Sopenharmony_ci
57553a5a1b3Sopenharmony_ci        pa_sink_input_put(c->sink_input);
57653a5a1b3Sopenharmony_ci    }
57753a5a1b3Sopenharmony_ci
57853a5a1b3Sopenharmony_ci    if (o->record) {
57953a5a1b3Sopenharmony_ci        pa_source_output_new_data data;
58053a5a1b3Sopenharmony_ci        size_t l;
58153a5a1b3Sopenharmony_ci        pa_source *source;
58253a5a1b3Sopenharmony_ci
58353a5a1b3Sopenharmony_ci        if (!(source = pa_namereg_get(c->protocol->core, o->default_source, PA_NAMEREG_SOURCE))) {
58453a5a1b3Sopenharmony_ci            pa_log("Failed to get source.");
58553a5a1b3Sopenharmony_ci            goto fail;
58653a5a1b3Sopenharmony_ci        }
58753a5a1b3Sopenharmony_ci
58853a5a1b3Sopenharmony_ci        pa_source_output_new_data_init(&data);
58953a5a1b3Sopenharmony_ci        data.driver = __FILE__;
59053a5a1b3Sopenharmony_ci        data.module = o->module;
59153a5a1b3Sopenharmony_ci        data.client = c->client;
59253a5a1b3Sopenharmony_ci        pa_source_output_new_data_set_source(&data, source, false, true);
59353a5a1b3Sopenharmony_ci        pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
59453a5a1b3Sopenharmony_ci        pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec);
59553a5a1b3Sopenharmony_ci
59653a5a1b3Sopenharmony_ci        pa_source_output_new(&c->source_output, p->core, &data);
59753a5a1b3Sopenharmony_ci        pa_source_output_new_data_done(&data);
59853a5a1b3Sopenharmony_ci
59953a5a1b3Sopenharmony_ci        if (!c->source_output) {
60053a5a1b3Sopenharmony_ci            pa_log("Failed to create source output.");
60153a5a1b3Sopenharmony_ci            goto fail;
60253a5a1b3Sopenharmony_ci        }
60353a5a1b3Sopenharmony_ci        c->source_output->push = source_output_push_cb;
60453a5a1b3Sopenharmony_ci        c->source_output->kill = source_output_kill_cb;
60553a5a1b3Sopenharmony_ci        c->source_output->get_latency = source_output_get_latency_cb;
60653a5a1b3Sopenharmony_ci        c->source_output->userdata = c;
60753a5a1b3Sopenharmony_ci
60853a5a1b3Sopenharmony_ci        pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY);
60953a5a1b3Sopenharmony_ci
61053a5a1b3Sopenharmony_ci        l = (size_t) (pa_bytes_per_second(&o->sample_spec)*RECORD_BUFFER_SECONDS);
61153a5a1b3Sopenharmony_ci        c->output_memblockq = pa_memblockq_new(
61253a5a1b3Sopenharmony_ci                "simple protocol connection output_memblockq",
61353a5a1b3Sopenharmony_ci                0,
61453a5a1b3Sopenharmony_ci                l,
61553a5a1b3Sopenharmony_ci                0,
61653a5a1b3Sopenharmony_ci                &o->sample_spec,
61753a5a1b3Sopenharmony_ci                1,
61853a5a1b3Sopenharmony_ci                0,
61953a5a1b3Sopenharmony_ci                0,
62053a5a1b3Sopenharmony_ci                NULL);
62153a5a1b3Sopenharmony_ci        pa_iochannel_socket_set_sndbuf(io, l);
62253a5a1b3Sopenharmony_ci
62353a5a1b3Sopenharmony_ci        pa_source_output_put(c->source_output);
62453a5a1b3Sopenharmony_ci    }
62553a5a1b3Sopenharmony_ci
62653a5a1b3Sopenharmony_ci    pa_idxset_put(p->connections, c, NULL);
62753a5a1b3Sopenharmony_ci
62853a5a1b3Sopenharmony_ci    return;
62953a5a1b3Sopenharmony_ci
63053a5a1b3Sopenharmony_cifail:
63153a5a1b3Sopenharmony_ci    connection_unlink(c);
63253a5a1b3Sopenharmony_ci}
63353a5a1b3Sopenharmony_ci
63453a5a1b3Sopenharmony_civoid pa_simple_protocol_disconnect(pa_simple_protocol *p, pa_module *m) {
63553a5a1b3Sopenharmony_ci    connection *c;
63653a5a1b3Sopenharmony_ci    void *state = NULL;
63753a5a1b3Sopenharmony_ci
63853a5a1b3Sopenharmony_ci    pa_assert(p);
63953a5a1b3Sopenharmony_ci    pa_assert(m);
64053a5a1b3Sopenharmony_ci
64153a5a1b3Sopenharmony_ci    while ((c = pa_idxset_iterate(p->connections, &state, NULL)))
64253a5a1b3Sopenharmony_ci        if (c->options->module == m)
64353a5a1b3Sopenharmony_ci            connection_unlink(c);
64453a5a1b3Sopenharmony_ci}
64553a5a1b3Sopenharmony_ci
64653a5a1b3Sopenharmony_cistatic pa_simple_protocol* simple_protocol_new(pa_core *c) {
64753a5a1b3Sopenharmony_ci    pa_simple_protocol *p;
64853a5a1b3Sopenharmony_ci
64953a5a1b3Sopenharmony_ci    pa_assert(c);
65053a5a1b3Sopenharmony_ci
65153a5a1b3Sopenharmony_ci    p = pa_xnew(pa_simple_protocol, 1);
65253a5a1b3Sopenharmony_ci    PA_REFCNT_INIT(p);
65353a5a1b3Sopenharmony_ci    p->core = c;
65453a5a1b3Sopenharmony_ci    p->connections = pa_idxset_new(NULL, NULL);
65553a5a1b3Sopenharmony_ci
65653a5a1b3Sopenharmony_ci    pa_assert_se(pa_shared_set(c, "simple-protocol", p) >= 0);
65753a5a1b3Sopenharmony_ci
65853a5a1b3Sopenharmony_ci    return p;
65953a5a1b3Sopenharmony_ci}
66053a5a1b3Sopenharmony_ci
66153a5a1b3Sopenharmony_cipa_simple_protocol* pa_simple_protocol_get(pa_core *c) {
66253a5a1b3Sopenharmony_ci    pa_simple_protocol *p;
66353a5a1b3Sopenharmony_ci
66453a5a1b3Sopenharmony_ci    if ((p = pa_shared_get(c, "simple-protocol")))
66553a5a1b3Sopenharmony_ci        return pa_simple_protocol_ref(p);
66653a5a1b3Sopenharmony_ci
66753a5a1b3Sopenharmony_ci    return simple_protocol_new(c);
66853a5a1b3Sopenharmony_ci}
66953a5a1b3Sopenharmony_ci
67053a5a1b3Sopenharmony_cipa_simple_protocol* pa_simple_protocol_ref(pa_simple_protocol *p) {
67153a5a1b3Sopenharmony_ci    pa_assert(p);
67253a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(p) >= 1);
67353a5a1b3Sopenharmony_ci
67453a5a1b3Sopenharmony_ci    PA_REFCNT_INC(p);
67553a5a1b3Sopenharmony_ci
67653a5a1b3Sopenharmony_ci    return p;
67753a5a1b3Sopenharmony_ci}
67853a5a1b3Sopenharmony_ci
67953a5a1b3Sopenharmony_civoid pa_simple_protocol_unref(pa_simple_protocol *p) {
68053a5a1b3Sopenharmony_ci    connection *c;
68153a5a1b3Sopenharmony_ci    pa_assert(p);
68253a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(p) >= 1);
68353a5a1b3Sopenharmony_ci
68453a5a1b3Sopenharmony_ci    if (PA_REFCNT_DEC(p) > 0)
68553a5a1b3Sopenharmony_ci        return;
68653a5a1b3Sopenharmony_ci
68753a5a1b3Sopenharmony_ci    while ((c = pa_idxset_first(p->connections, NULL)))
68853a5a1b3Sopenharmony_ci        connection_unlink(c);
68953a5a1b3Sopenharmony_ci
69053a5a1b3Sopenharmony_ci    pa_idxset_free(p->connections, NULL);
69153a5a1b3Sopenharmony_ci
69253a5a1b3Sopenharmony_ci    pa_assert_se(pa_shared_remove(p->core, "simple-protocol") >= 0);
69353a5a1b3Sopenharmony_ci
69453a5a1b3Sopenharmony_ci    pa_xfree(p);
69553a5a1b3Sopenharmony_ci}
69653a5a1b3Sopenharmony_ci
69753a5a1b3Sopenharmony_cipa_simple_options* pa_simple_options_new(void) {
69853a5a1b3Sopenharmony_ci    pa_simple_options *o;
69953a5a1b3Sopenharmony_ci
70053a5a1b3Sopenharmony_ci    o = pa_xnew0(pa_simple_options, 1);
70153a5a1b3Sopenharmony_ci    PA_REFCNT_INIT(o);
70253a5a1b3Sopenharmony_ci
70353a5a1b3Sopenharmony_ci    o->record = false;
70453a5a1b3Sopenharmony_ci    o->playback = true;
70553a5a1b3Sopenharmony_ci
70653a5a1b3Sopenharmony_ci    return o;
70753a5a1b3Sopenharmony_ci}
70853a5a1b3Sopenharmony_ci
70953a5a1b3Sopenharmony_cipa_simple_options* pa_simple_options_ref(pa_simple_options *o) {
71053a5a1b3Sopenharmony_ci    pa_assert(o);
71153a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
71253a5a1b3Sopenharmony_ci
71353a5a1b3Sopenharmony_ci    PA_REFCNT_INC(o);
71453a5a1b3Sopenharmony_ci
71553a5a1b3Sopenharmony_ci    return o;
71653a5a1b3Sopenharmony_ci}
71753a5a1b3Sopenharmony_ci
71853a5a1b3Sopenharmony_civoid pa_simple_options_unref(pa_simple_options *o) {
71953a5a1b3Sopenharmony_ci    pa_assert(o);
72053a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
72153a5a1b3Sopenharmony_ci
72253a5a1b3Sopenharmony_ci    if (PA_REFCNT_DEC(o) > 0)
72353a5a1b3Sopenharmony_ci        return;
72453a5a1b3Sopenharmony_ci
72553a5a1b3Sopenharmony_ci    pa_xfree(o->default_sink);
72653a5a1b3Sopenharmony_ci    pa_xfree(o->default_source);
72753a5a1b3Sopenharmony_ci
72853a5a1b3Sopenharmony_ci    pa_xfree(o);
72953a5a1b3Sopenharmony_ci}
73053a5a1b3Sopenharmony_ci
73153a5a1b3Sopenharmony_ciint pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma) {
73253a5a1b3Sopenharmony_ci    bool enabled;
73353a5a1b3Sopenharmony_ci
73453a5a1b3Sopenharmony_ci    pa_assert(o);
73553a5a1b3Sopenharmony_ci    pa_assert(PA_REFCNT_VALUE(o) >= 1);
73653a5a1b3Sopenharmony_ci    pa_assert(ma);
73753a5a1b3Sopenharmony_ci
73853a5a1b3Sopenharmony_ci    o->sample_spec = c->default_sample_spec;
73953a5a1b3Sopenharmony_ci    if (pa_modargs_get_sample_spec_and_channel_map(ma, &o->sample_spec, &o->channel_map, PA_CHANNEL_MAP_DEFAULT) < 0) {
74053a5a1b3Sopenharmony_ci        pa_log("Failed to parse sample type specification.");
74153a5a1b3Sopenharmony_ci        return -1;
74253a5a1b3Sopenharmony_ci    }
74353a5a1b3Sopenharmony_ci
74453a5a1b3Sopenharmony_ci    pa_xfree(o->default_source);
74553a5a1b3Sopenharmony_ci    o->default_source = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
74653a5a1b3Sopenharmony_ci
74753a5a1b3Sopenharmony_ci    pa_xfree(o->default_sink);
74853a5a1b3Sopenharmony_ci    o->default_sink = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
74953a5a1b3Sopenharmony_ci
75053a5a1b3Sopenharmony_ci    enabled = o->record;
75153a5a1b3Sopenharmony_ci    if (pa_modargs_get_value_boolean(ma, "record", &enabled) < 0) {
75253a5a1b3Sopenharmony_ci        pa_log("record= expects a boolean argument.");
75353a5a1b3Sopenharmony_ci        return -1;
75453a5a1b3Sopenharmony_ci    }
75553a5a1b3Sopenharmony_ci    o->record = enabled;
75653a5a1b3Sopenharmony_ci
75753a5a1b3Sopenharmony_ci    enabled = o->playback;
75853a5a1b3Sopenharmony_ci    if (pa_modargs_get_value_boolean(ma, "playback", &enabled) < 0) {
75953a5a1b3Sopenharmony_ci        pa_log("playback= expects a boolean argument.");
76053a5a1b3Sopenharmony_ci        return -1;
76153a5a1b3Sopenharmony_ci    }
76253a5a1b3Sopenharmony_ci    o->playback = enabled;
76353a5a1b3Sopenharmony_ci
76453a5a1b3Sopenharmony_ci    if (!o->playback && !o->record) {
76553a5a1b3Sopenharmony_ci        pa_log("neither playback nor recording enabled for protocol.");
76653a5a1b3Sopenharmony_ci        return -1;
76753a5a1b3Sopenharmony_ci    }
76853a5a1b3Sopenharmony_ci
76953a5a1b3Sopenharmony_ci    return 0;
77053a5a1b3Sopenharmony_ci}
771