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