From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 1253 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 1253 insertions(+) create mode 100644 src/pulsecore/protocol-esound.c (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c new file mode 100644 index 00000000..6b9112bf --- /dev/null +++ b/src/pulsecore/protocol-esound.c @@ -0,0 +1,1253 @@ +/* $Id$ */ + +/*** + This file is part of PulseAudio. + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "endianmacros.h" + +#include "protocol-esound.h" + +/* Don't accept more connection than this */ +#define MAX_CONNECTIONS 10 + +/* Kick a client if it doesn't authenticate within this time */ +#define AUTH_TIMEOUT 5 + +#define DEFAULT_COOKIE_FILE ".esd_auth" + +#define PLAYBACK_BUFFER_SECONDS (.25) +#define PLAYBACK_BUFFER_FRAGMENTS (10) +#define RECORD_BUFFER_SECONDS (5) +#define RECORD_BUFFER_FRAGMENTS (100) + +#define MAX_CACHE_SAMPLE_SIZE (1024000) + +#define SCACHE_PREFIX "esound." + +/* This is heavily based on esound's code */ + +struct connection { + uint32_t index; + int dead; + pa_protocol_esound *protocol; + pa_iochannel *io; + pa_client *client; + int authorized, swap_byte_order; + void *write_data; + size_t write_data_alloc, write_data_index, write_data_length; + void *read_data; + size_t read_data_alloc, read_data_length; + esd_proto_t request; + esd_client_state_t state; + pa_sink_input *sink_input; + pa_source_output *source_output; + pa_memblockq *input_memblockq, *output_memblockq; + pa_defer_event *defer_event; + + char *original_name; + + struct { + pa_memblock *current_memblock; + size_t memblock_index, fragment_size; + } playback; + + struct { + pa_memchunk memchunk; + char *name; + pa_sample_spec sample_spec; + } scache; + + pa_time_event *auth_timeout_event; +}; + +struct pa_protocol_esound { + int public; + pa_module *module; + pa_core *core; + pa_socket_server *server; + pa_idxset *connections; + char *sink_name, *source_name; + unsigned n_player; + uint8_t esd_key[ESD_KEY_LEN]; +}; + +typedef struct proto_handler { + size_t data_length; + int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + const char *description; +} esd_proto_handler_info_t; + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_kill_cb(pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(pa_source_output *o); + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); +static void source_output_kill_cb(pa_source_output *o); + +static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); + +/* the big map of protocol handler info */ +static struct proto_handler proto_map[ESD_PROTO_MAX] = { + { ESD_KEY_LEN + sizeof(int), esd_proto_connect, "connect" }, + { ESD_KEY_LEN + sizeof(int), NULL, "lock" }, + { ESD_KEY_LEN + sizeof(int), NULL, "unlock" }, + + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_play, "stream play" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream rec" }, + { ESD_NAME_MAX + 2 * sizeof(int), esd_proto_stream_record, "stream mon" }, + + { ESD_NAME_MAX + 3 * sizeof(int), esd_proto_sample_cache, "sample cache" }, /* 6 */ + { sizeof(int), esd_proto_sample_free_or_play, "sample free" }, + { sizeof(int), esd_proto_sample_free_or_play, "sample play" }, /* 8 */ + { sizeof(int), NULL, "sample loop" }, + { sizeof(int), NULL, "sample stop" }, + { -1, NULL, "TODO: sample kill" }, + + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "standby" }, /* NOOP! */ + { ESD_KEY_LEN + sizeof(int), esd_proto_standby_or_resume, "resume" }, /* NOOP! */ /* 13 */ + + { ESD_NAME_MAX, esd_proto_sample_get_id, "sample getid" }, /* 14 */ + { ESD_NAME_MAX + 2 * sizeof(int), NULL, "stream filter" }, + + { sizeof(int), esd_proto_server_info, "server info" }, + { sizeof(int), esd_proto_all_info, "all info" }, + { -1, NULL, "TODO: subscribe" }, + { -1, NULL, "TODO: unsubscribe" }, + + { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, + { 3 * sizeof(int), NULL, "sample pan" }, + + { sizeof(int), NULL, "standby mode" }, + { 0, esd_proto_get_latency, "get latency" } +}; + +static void connection_free(struct connection *c) { + assert(c); + pa_idxset_remove_by_data(c->protocol->connections, c, NULL); + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + pa_client_free(c->client); + + if (c->sink_input) { + pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unref(c->sink_input); + } + + if (c->source_output) { + pa_source_output_disconnect(c->source_output); + pa_source_output_unref(c->source_output); + } + + if (c->input_memblockq) + pa_memblockq_free(c->input_memblockq); + if (c->output_memblockq) + pa_memblockq_free(c->output_memblockq); + + if (c->playback.current_memblock) + pa_memblock_unref(c->playback.current_memblock); + + pa_xfree(c->read_data); + pa_xfree(c->write_data); + + if (c->io) + pa_iochannel_free(c->io); + + if (c->defer_event) + c->protocol->core->mainloop->defer_free(c->defer_event); + + if (c->scache.memchunk.memblock) + pa_memblock_unref(c->scache.memchunk.memblock); + pa_xfree(c->scache.name); + + if (c->auth_timeout_event) + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + + pa_xfree(c->original_name); + pa_xfree(c); +} + +static void connection_write_prepare(struct connection *c, size_t length) { + size_t t; + assert(c); + + t = c->write_data_length+length; + + if (c->write_data_alloc < t) + c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); + + assert(c->write_data); +} + +static void connection_write(struct connection *c, const void *data, size_t length) { + size_t i; + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + connection_write_prepare(c, length); + + assert(c->write_data); + + i = c->write_data_length; + c->write_data_length += length; + + memcpy((char*)c->write_data + i, data, length); +} + +static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { + assert(ss); + + ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; + if ((format & ESD_MASK_BITS) == ESD_BITS16) + ss->format = swap_bytes ? PA_SAMPLE_S16RE : PA_SAMPLE_S16NE; + else + ss->format = PA_SAMPLE_U8; +} + +static int format_native2esd(pa_sample_spec *ss) { + int format = 0; + + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; + format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; + + return format; +} + +#define CHECK_VALIDITY(expression, string) do { \ + if (!(expression)) { \ + pa_log_warn(__FILE__ ": " string); \ + return -1; \ + } \ +} while(0); + +/*** esound commands ***/ + +static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + uint32_t ekey; + int ok; + + assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + + if (!c->authorized) { + if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { + pa_log(__FILE__": kicked client with invalid authorization key."); + return -1; + } + + c->authorized = 1; + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + } + + data = (const char*)data + ESD_KEY_LEN; + + memcpy(&ekey, data, sizeof(uint32_t)); + if (ekey == ESD_ENDIAN_KEY) + c->swap_byte_order = 0; + else if (ekey == ESD_SWAP_ENDIAN_KEY) + c->swap_byte_order = 1; + else { + pa_log(__FILE__": client sent invalid endian key"); + return -1; + } + + ok = 1; + connection_write(c, &ok, sizeof(int)); + return 0; +} + +static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX], *utf8_name; + int32_t format, rate; + pa_sink *sink; + pa_sample_spec ss; + size_t l; + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); + sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); + CHECK_VALIDITY(sink, "No such sink"); + + strncpy(name, data, sizeof(name)); + name[sizeof(name)-1] = 0; + utf8_name = pa_utf8_filter(name); + + pa_client_set_name(c->client, utf8_name); + c->original_name = pa_xstrdup(name); + + assert(!c->sink_input && !c->input_memblockq); + + c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); + + pa_xfree(utf8_name); + + CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); + + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + c->input_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + (size_t) -1, + l/PLAYBACK_BUFFER_FRAGMENTS, + NULL, + c->protocol->core->memblock_stat); + pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); + c->playback.fragment_size = l/10; + + c->sink_input->owner = c->protocol->module; + c->sink_input->client = c->client; + c->sink_input->peek = sink_input_peek_cb; + c->sink_input->drop = sink_input_drop_cb; + c->sink_input->kill = sink_input_kill_cb; + c->sink_input->get_latency = sink_input_get_latency_cb; + c->sink_input->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { + char name[ESD_NAME_MAX], *utf8_name; + int32_t format, rate; + pa_source *source; + pa_sample_spec ss; + size_t l; + + assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); + + if (request == ESD_PROTO_STREAM_MON) { + pa_sink* sink; + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + pa_log(__FILE__": no such sink."); + return -1; + } + + if (!(source = sink->monitor_source)) { + pa_log(__FILE__": no such monitor source."); + return -1; + } + } else { + assert(request == ESD_PROTO_STREAM_REC); + + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log(__FILE__": no such source."); + return -1; + } + } + + strncpy(name, data, sizeof(name)); + name[sizeof(name)-1] = 0; + + utf8_name = pa_utf8_filter(name); + pa_client_set_name(c->client, utf8_name); + pa_xfree(utf8_name); + + c->original_name = pa_xstrdup(name); + + assert(!c->output_memblockq && !c->source_output); + + if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { + pa_log(__FILE__": failed to create source output"); + return -1; + } + + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + c->output_memblockq = pa_memblockq_new( + 0, + l, + 0, + pa_frame_size(&ss), + 1, + 0, + NULL, + c->protocol->core->memblock_stat); + pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); + + c->source_output->owner = c->protocol->module; + c->source_output->client = c->client; + c->source_output->push = source_output_push_cb; + c->source_output->kill = source_output_kill_cb; + c->source_output->get_latency = source_output_get_latency_cb; + c->source_output->userdata = c; + + c->state = ESD_STREAMING_DATA; + + c->protocol->n_player++; + + return 0; +} + +static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sink *sink; + int32_t latency; + + assert(c && !data && length == 0); + + if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + latency = 0; + else { + double usec = pa_sink_get_latency(sink); + latency = (int) ((usec*44100)/1000000); + } + + latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + connection_write(c, &latency, sizeof(int32_t)); + return 0; +} + +static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; + int32_t response; + pa_sink *sink; + + assert(c && data && length == sizeof(int32_t)); + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { + rate = sink->sample_spec.rate; + format = format_native2esd(&sink->sample_spec); + } + + connection_write_prepare(c, sizeof(int32_t) * 3); + + response = 0; + connection_write(c, &response, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { + size_t t, k, s; + struct connection *conn; + uint32_t idx = PA_IDXSET_INVALID; + unsigned nsamples; + char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; + + assert(c && data && length == sizeof(int32_t)); + + if (esd_proto_server_info(c, request, data, length) < 0) + return -1; + + k = sizeof(int32_t)*5+ESD_NAME_MAX; + s = sizeof(int32_t)*6+ESD_NAME_MAX; + nsamples = c->protocol->core->scache ? pa_idxset_size(c->protocol->core->scache) : 0; + t = s*(nsamples+1) + k*(c->protocol->n_player+1); + + connection_write_prepare(c, t); + + memset(terminator, 0, sizeof(terminator)); + + for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { + int32_t id, format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = ESD_VOLUME_BASE, rvolume = ESD_VOLUME_BASE; + char name[ESD_NAME_MAX]; + + if (conn->state != ESD_STREAMING_DATA) + continue; + + assert(t >= k*2+s); + + if (conn->sink_input) { + pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); + rate = conn->sink_input->sample_spec.rate; + lvolume = (volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; + format = format_native2esd(&conn->sink_input->sample_spec); + } + + /* id */ + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); + connection_write(c, &id, sizeof(int32_t)); + + /* name */ + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ + if (conn->original_name) + strncpy(name, conn->original_name, ESD_NAME_MAX); + else if (conn->client && conn->client->name) + strncpy(name, conn->client->name, ESD_NAME_MAX); + connection_write(c, name, ESD_NAME_MAX); + + /* rate */ + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + connection_write(c, &rate, sizeof(int32_t)); + + /* left */ + lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + connection_write(c, &lvolume, sizeof(int32_t)); + + /*right*/ + rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + connection_write(c, &rvolume, sizeof(int32_t)); + + /*format*/ + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + connection_write(c, &format, sizeof(int32_t)); + + t -= k; + } + + assert(t == s*(nsamples+1)+k); + t -= k; + + connection_write(c, terminator, k); + + if (nsamples) { + pa_scache_entry *ce; + + idx = PA_IDXSET_INVALID; + for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { + int32_t id, rate, lvolume, rvolume, format, len; + char name[ESD_NAME_MAX]; + + assert(t >= s*2); + + /* id */ + id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + connection_write(c, &id, sizeof(int32_t)); + + /* name */ + memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ + if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) + strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + else + snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); + connection_write(c, name, ESD_NAME_MAX); + + /* rate */ + rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + connection_write(c, &rate, sizeof(int32_t)); + + /* left */ + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &lvolume, sizeof(int32_t)); + + /*right*/ + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + connection_write(c, &rvolume, sizeof(int32_t)); + + /*format*/ + format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + connection_write(c, &format, sizeof(int32_t)); + + /*length*/ + len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + connection_write(c, &len, sizeof(int32_t)); + + t -= s; + } + } + + assert(t == s); + + connection_write(c, terminator, s); + + return 0; +} + +static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t ok; + uint32_t idx, lvolume, rvolume; + struct connection *conn; + + assert(c && data && length == sizeof(int32_t)*3); + + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + data = (const char*)data + sizeof(uint32_t); + + memcpy(&lvolume, data, sizeof(uint32_t)); + lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); + data = (const char*)data + sizeof(uint32_t); + + memcpy(&rvolume, data, sizeof(uint32_t)); + rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); + data = (const char*)data + sizeof(uint32_t); + + if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { + pa_cvolume volume; + volume.values[0] = (lvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.values[1] = (rvolume*PA_VOLUME_NORM)/ESD_VOLUME_BASE; + volume.channels = 2; + pa_sink_input_set_volume(conn->sink_input, &volume); + ok = 1; + } else + ok = 0; + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + pa_sample_spec ss; + int32_t format, rate, sc_length; + uint32_t idx; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + + assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); + + memcpy(&format, data, sizeof(int32_t)); + format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*)data + sizeof(int32_t); + + memcpy(&rate, data, sizeof(int32_t)); + rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*)data + sizeof(int32_t); + + ss.rate = rate; + format_esd2native(format, c->swap_byte_order, &ss); + + CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); + + memcpy(&sc_length, data, sizeof(int32_t)); + sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); + data = (const char*)data + sizeof(int32_t); + + CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); + + assert(!c->scache.memchunk.memblock); + c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.index = 0; + c->scache.memchunk.length = sc_length; + c->scache.sample_spec = ss; + assert(!c->scache.name); + c->scache.name = pa_xstrdup(name); + + c->state = ESD_CACHING_SAMPLE; + + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); + + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); + + return 0; +} + +static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { + int32_t ok; + uint32_t idx; + char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; + + assert(c && data && length == ESD_NAME_MAX); + + strcpy(name, SCACHE_PREFIX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); + name[sizeof(name)-1] = 0; + + CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); + + ok = -1; + if ((idx = pa_scache_get_id_by_name(c->protocol->core, name)) != PA_IDXSET_INVALID) + ok = idx + 1; + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { + int32_t ok; + const char *name; + uint32_t idx; + + assert(c && data && length == sizeof(int32_t)); + + memcpy(&idx, data, sizeof(uint32_t)); + idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + + ok = 0; + + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { + if (request == ESD_PROTO_SAMPLE_PLAY) { + pa_sink *sink; + + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) + if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) + ok = idx + 1; + } else { + assert(request == ESD_PROTO_SAMPLE_FREE); + + if (pa_scache_remove_item(c->protocol->core, name) >= 0) + ok = idx + 1; + } + } + + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { + int32_t ok; + + connection_write_prepare(c, sizeof(int32_t) * 2); + + ok = 1; + connection_write(c, &ok, sizeof(int32_t)); + connection_write(c, &ok, sizeof(int32_t)); + + return 0; +} + +/*** client callbacks ***/ + +static void client_kill_cb(pa_client *c) { + assert(c && c->userdata); + connection_free(c->userdata); +} + +/*** pa_iochannel callbacks ***/ + +static int do_read(struct connection *c) { + assert(c && c->io); + +/* pa_log("READ"); */ + + if (c->state == ESD_NEXT_REQUEST) { + ssize_t r; + assert(c->read_data_length < sizeof(c->request)); + + if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + if ((c->read_data_length+= r) >= sizeof(c->request)) { + struct proto_handler *handler; + + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); + + if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { + pa_log(__FILE__": recieved invalid request."); + return -1; + } + + handler = proto_map+c->request; + +/* pa_log(__FILE__": executing request #%u", c->request); */ + + if (!handler->proc) { + pa_log(__FILE__": recieved unimplemented request #%u.", c->request); + return -1; + } + + if (handler->data_length == 0) { + c->read_data_length = 0; + + if (handler->proc(c, c->request, NULL, 0) < 0) + return -1; + + } else { + if (c->read_data_alloc < handler->data_length) + c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); + assert(c->read_data); + + c->state = ESD_NEEDS_REQDATA; + c->read_data_length = 0; + } + } + + } else if (c->state == ESD_NEEDS_REQDATA) { + ssize_t r; + struct proto_handler *handler = proto_map+c->request; + + assert(handler->proc); + + assert(c->read_data && c->read_data_length < handler->data_length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + if ((c->read_data_length += r) >= handler->data_length) { + size_t l = c->read_data_length; + assert(handler->proc); + + c->state = ESD_NEXT_REQUEST; + c->read_data_length = 0; + + if (handler->proc(c, c->request, c->read_data, l) < 0) + return -1; + } + } else if (c->state == ESD_CACHING_SAMPLE) { + ssize_t r; + + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + c->scache.memchunk.index += r; + assert(c->scache.memchunk.index <= c->scache.memchunk.length); + + if (c->scache.memchunk.index == c->scache.memchunk.length) { + uint32_t idx; + + c->scache.memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); + + pa_memblock_unref(c->scache.memchunk.memblock); + c->scache.memchunk.memblock = NULL; + c->scache.memchunk.index = c->scache.memchunk.length = 0; + + pa_xfree(c->scache.name); + c->scache.name = NULL; + + c->state = ESD_NEXT_REQUEST; + + idx += 1; + connection_write(c, &idx, sizeof(uint32_t)); + } + + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { + pa_memchunk chunk; + ssize_t r; + size_t l; + + assert(c->input_memblockq); + +/* pa_log("STREAMING_DATA"); */ + + if (!(l = pa_memblockq_missing(c->input_memblockq))) + return 0; + + if (l > c->playback.fragment_size) + l = c->playback.fragment_size; + + if (c->playback.current_memblock) + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + pa_memblock_unref(c->playback.current_memblock); + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + } + + if (!c->playback.current_memblock) { + c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + c->playback.memblock_index = 0; + } + + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + return -1; + } + + chunk.memblock = c->playback.current_memblock; + chunk.index = c->playback.memblock_index; + chunk.length = r; + assert(chunk.memblock); + + c->playback.memblock_index += r; + + assert(c->input_memblockq); + pa_memblockq_push_align(c->input_memblockq, &chunk); + assert(c->sink_input); + pa_sink_notify(c->sink_input->sink); + } + + return 0; +} + +static int do_write(struct connection *c) { + assert(c && c->io); + +/* pa_log("WRITE"); */ + + if (c->write_data_length) { + ssize_t r; + + assert(c->write_data_index < c->write_data_length); + if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + return -1; + } + + if ((c->write_data_index +=r) >= c->write_data_length) + c->write_data_length = c->write_data_index = 0; + + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { + pa_memchunk chunk; + ssize_t r; + + assert(c->output_memblockq); + if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) + return 0; + + assert(chunk.memblock && chunk.length); + + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + pa_memblock_unref(chunk.memblock); + pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + return -1; + } + + pa_memblockq_drop(c->output_memblockq, &chunk, r); + pa_memblock_unref(chunk.memblock); + + pa_source_notify(c->source_output->source); + } + + return 0; +} + +static void do_work(struct connection *c) { + assert(c); + + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + c->protocol->core->mainloop->defer_enable(c->defer_event, 0); + + if (c->dead) + return; + + if (pa_iochannel_is_readable(c->io)) { + if (do_read(c) < 0) + goto fail; + } + + if (c->state == ESD_STREAMING_DATA && c->source_output && pa_iochannel_is_hungup(c->io)) + /* In case we are in capture mode we will never call read() + * on the socket, hence we need to detect the hangup manually + * here, instead of simply waiting for read() to return 0. */ + goto fail; + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + + return; + +fail: + + if (c->state == ESD_STREAMING_DATA && c->sink_input) { + c->dead = 1; + + pa_iochannel_free(c->io); + c->io = NULL; + + pa_memblockq_prebuf_disable(c->input_memblockq); + pa_sink_notify(c->sink_input->sink); + } else + connection_free(c); +} + +static void io_callback(pa_iochannel*io, void *userdata) { + struct connection *c = userdata; + assert(io && c && c->io == io); + + do_work(c); +} + +/*** defer callback ***/ + +static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { + struct connection *c = userdata; + assert(a && c && c->defer_event == e); + +/* pa_log("DEFER"); */ + + do_work(c); +} + +/*** sink_input callbacks ***/ + +static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { + struct connection*c; + assert(i && i->userdata && chunk); + c = i->userdata; + + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + + if (c->dead) + connection_free(c); + + return -1; + } + + return 0; +} + +static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { + struct connection*c = i->userdata; + assert(i && c && length); + +/* pa_log("DROP"); */ + + pa_memblockq_drop(c->input_memblockq, chunk, length); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + +/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ +} + +static void sink_input_kill_cb(pa_sink_input *i) { + assert(i && i->userdata); + connection_free((struct connection *) i->userdata); +} + +static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { + struct connection*c = i->userdata; + assert(i && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +} + +/*** source_output callbacks ***/ + +static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { + struct connection *c = o->userdata; + assert(o && c && chunk); + + pa_memblockq_push(c->output_memblockq, chunk); + + /* do something */ + assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); +} + +static void source_output_kill_cb(pa_source_output *o) { + assert(o && o->userdata); + connection_free((struct connection *) o->userdata); +} + +static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { + struct connection*c = o->userdata; + assert(o && c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); +} + +/*** socket server callback ***/ + +static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { + struct connection *c = userdata; + assert(m && tv && c && c->auth_timeout_event == e); + + if (!c->authorized) + connection_free(c); +} + +static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { + struct connection *c; + pa_protocol_esound *p = userdata; + char cname[256], pname[128]; + assert(s && io && p); + + if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { + pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_iochannel_free(io); + return; + } + + c = pa_xnew(struct connection, 1); + c->protocol = p; + c->io = io; + pa_iochannel_set_callback(c->io, io_callback, c); + + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); + assert(p->core); + c->client = pa_client_new(p->core, __FILE__, cname); + assert(c->client); + c->client->owner = p->module; + c->client->kill = client_kill_cb; + c->client->userdata = c; + + c->authorized = p->public; + c->swap_byte_order = 0; + c->dead = 0; + + c->read_data_length = 0; + c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); + + c->write_data_length = c->write_data_index = c->write_data_alloc = 0; + c->write_data = NULL; + + c->state = ESD_NEEDS_REQDATA; + c->request = ESD_PROTO_CONNECT; + + c->sink_input = NULL; + c->input_memblockq = NULL; + + c->source_output = NULL; + c->output_memblockq = NULL; + + c->playback.current_memblock = NULL; + c->playback.memblock_index = 0; + c->playback.fragment_size = 0; + + c->scache.memchunk.length = c->scache.memchunk.index = 0; + c->scache.memchunk.memblock = NULL; + c->scache.name = NULL; + + c->original_name = NULL; + + if (!c->authorized) { + struct timeval tv; + pa_gettimeofday(&tv); + tv.tv_sec += AUTH_TIMEOUT; + c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); + } else + c->auth_timeout_event = NULL; + + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); + assert(c->defer_event); + p->core->mainloop->defer_enable(c->defer_event, 0); + + pa_idxset_put(p->connections, c, &c->index); +} + +/*** entry points ***/ + +pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { + pa_protocol_esound *p; + int public = 0; + assert(core && server && ma); + + p = pa_xnew(pa_protocol_esound, 1); + + if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { + pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + return NULL; + } + + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { + pa_xfree(p); + return NULL; + } + + p->module = m; + p->public = public; + p->server = server; + pa_socket_server_set_callback(p->server, on_connection, p); + p->core = core; + p->connections = pa_idxset_new(NULL, NULL); + assert(p->connections); + + p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); + p->n_player = 0; + + return p; +} + +void pa_protocol_esound_free(pa_protocol_esound *p) { + struct connection *c; + assert(p); + + while ((c = pa_idxset_first(p->connections, NULL))) + connection_free(c); + + pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_unref(p->server); + pa_xfree(p); +} -- cgit From 18b8b84b7e3885165ef14cd7c25fa34f1ce36b61 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Jun 2006 16:36:58 +0000 Subject: increase the maxium number of concurrent esd and native connections git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1053 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 6b9112bf..5daa32fe 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -55,7 +55,7 @@ #include "protocol-esound.h" /* Don't accept more connection than this */ -#define MAX_CONNECTIONS 10 +#define MAX_CONNECTIONS 64 /* Kick a client if it doesn't authenticate within this time */ #define AUTH_TIMEOUT 5 -- cgit From 44beeaa648a1d434692721dd65a04ecb3f75dace Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 20 Jul 2006 18:43:20 +0000 Subject: implement "auth-ip-acl=" in the native and esound protocols git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1125 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 5daa32fe..0fa2c7f1 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "endianmacros.h" @@ -116,6 +117,7 @@ struct pa_protocol_esound { char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; + pa_ip_acl *auth_ip_acl; }; typedef struct proto_handler { @@ -1162,7 +1164,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->client->kill = client_kill_cb; c->client->userdata = c; - c->authorized = p->public; + c->authorized = !!p->public; c->swap_byte_order = 0; c->dead = 0; @@ -1191,6 +1193,11 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->original_name = NULL; + if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { + pa_log_info(__FILE__": Client authenticated by IP ACL."); + c->authorized = 1; + } + if (!c->authorized) { struct timeval tv; pa_gettimeofday(&tv); @@ -1211,20 +1218,32 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_esound *p; int public = 0; - assert(core && server && ma); + const char *acl; + + assert(core); + assert(server); + assert(m); + assert(ma); p = pa_xnew(pa_protocol_esound, 1); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log(__FILE__": auth-anonymous= expects a boolean argument."); - return NULL; + goto fail; } - if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) { - pa_xfree(p); - return NULL; - } + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) + goto fail; + if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { + + if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { + pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + goto fail; + } + } else + p->auth_ip_acl = NULL; + p->module = m; p->public = public; p->server = server; @@ -1238,6 +1257,10 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p->n_player = 0; return p; + +fail: + pa_xfree(p); + return NULL; } void pa_protocol_esound_free(pa_protocol_esound *p) { @@ -1249,5 +1272,9 @@ void pa_protocol_esound_free(pa_protocol_esound *p) { pa_idxset_free(p->connections, NULL, NULL); pa_socket_server_unref(p->server); + + if (p->auth_ip_acl) + pa_ip_acl_free(p->auth_ip_acl); + pa_xfree(p); } -- cgit From a621d9028548723d13df64df06a4f4538504e7a3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 16:19:56 +0000 Subject: allow hooking into the process of creating playback streams. To implement this I modified the pa_sink_input_new() signature to take a pa_sink_input_new_data structure instead of direct arguments. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1237 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 0fa2c7f1..724dccbc 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -325,9 +325,10 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; - pa_sink *sink; pa_sample_spec ss; size_t l; + pa_sink *sink; + pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -355,7 +356,15 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - c->sink_input = pa_sink_input_new(sink, __FILE__, utf8_name, &ss, NULL, NULL, 0, -1); + pa_sink_input_new_data_init(&sdata); + sdata.sink = sink; + sdata.driver = __FILE__; + sdata.name = utf8_name; + pa_sink_input_new_data_set_sample_spec(&sdata, &ss); + sdata.module = c->protocol->module; + sdata.client = c->client; + + c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); pa_xfree(utf8_name); @@ -374,8 +383,6 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; - c->sink_input->owner = c->protocol->module; - c->sink_input->client = c->client; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; -- cgit From a75e1ed9ef483c4c08f0fc963c0ea1a980f0c0e9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 13 Aug 2006 19:55:17 +0000 Subject: implement hook_source_ouput_new. For this I modified the pa_source_output_new constructor to take a struct similar to what I already did for pa_sink_input_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1250 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 724dccbc..f1a827bc 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -349,9 +349,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; + utf8_name = pa_utf8_filter(name); - pa_client_set_name(c->client, utf8_name); + pa_xfree(utf8_name); + c->original_name = pa_xstrdup(name); assert(!c->sink_input && !c->input_memblockq); @@ -359,15 +361,12 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data_init(&sdata); sdata.sink = sink; sdata.driver = __FILE__; - sdata.name = utf8_name; + sdata.name = c->client->name; pa_sink_input_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); - - pa_xfree(utf8_name); - CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); @@ -402,6 +401,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source *source; pa_sample_spec ss; size_t l; + pa_source_output_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -450,10 +450,16 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &ss, NULL, -1))) { - pa_log(__FILE__": failed to create source output"); - return -1; - } + pa_source_output_new_data_init(&sdata); + sdata.source = source; + sdata.driver = __FILE__; + sdata.name = c->client->name; + pa_source_output_new_data_set_sample_spec(&sdata, &ss); + sdata.module = c->protocol->module; + sdata.client = c->client; + + c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); + CHECK_VALIDITY(c->sink_input, "Failed to create source_output."); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( @@ -467,8 +473,6 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->protocol->core->memblock_stat); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - c->source_output->owner = c->protocol->module; - c->source_output->client = c->client; c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->get_latency = source_output_get_latency_cb; -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index f1a827bc..2fadeca3 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -377,8 +377,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_frame_size(&ss), (size_t) -1, l/PLAYBACK_BUFFER_FRAGMENTS, - NULL, - c->protocol->core->memblock_stat); + NULL); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; @@ -469,8 +468,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_frame_size(&ss), 1, 0, - NULL, - c->protocol->core->memblock_stat); + NULL); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); c->source_output->push = source_output_push_cb; @@ -722,7 +720,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); assert(!c->scache.memchunk.memblock); - c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); + c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; c->scache.memchunk.length = sc_length; c->scache.sample_spec = ss; @@ -941,7 +939,7 @@ static int do_read(struct connection *c) { } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->playback.fragment_size*2, c->protocol->core->memblock_stat); + c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 2fadeca3..c96a98b9 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -294,7 +294,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - pa_log(__FILE__": kicked client with invalid authorization key."); + pa_log("kicked client with invalid authorization key."); return -1; } @@ -313,7 +313,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - pa_log(__FILE__": client sent invalid endian key"); + pa_log("client sent invalid endian key"); return -1; } @@ -421,19 +421,19 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_sink* sink; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - pa_log(__FILE__": no such sink."); + pa_log("no such sink."); return -1; } if (!(source = sink->monitor_source)) { - pa_log(__FILE__": no such monitor source."); + pa_log("no such monitor source."); return -1; } } else { assert(request == ESD_PROTO_STREAM_REC); if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log(__FILE__": no such source."); + pa_log("no such source."); return -1; } } @@ -822,7 +822,7 @@ static int do_read(struct connection *c) { assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -832,16 +832,16 @@ static int do_read(struct connection *c) { c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - pa_log(__FILE__": recieved invalid request."); + pa_log("recieved invalid request."); return -1; } handler = proto_map+c->request; -/* pa_log(__FILE__": executing request #%u", c->request); */ +/* pa_log("executing request #%u", c->request); */ if (!handler->proc) { - pa_log(__FILE__": recieved unimplemented request #%u.", c->request); + pa_log("recieved unimplemented request #%u.", c->request); return -1; } @@ -870,7 +870,7 @@ static int do_read(struct connection *c) { assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -890,7 +890,7 @@ static int do_read(struct connection *c) { assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -945,7 +945,7 @@ static int do_read(struct connection *c) { } if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - pa_log_debug(__FILE__": read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -975,7 +975,7 @@ static int do_write(struct connection *c) { assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -994,7 +994,7 @@ static int do_write(struct connection *c) { if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - pa_log(__FILE__": write(): %s", pa_cstrerror(errno)); + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -1154,7 +1154,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) assert(s && io && p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { - pa_log(__FILE__": Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); + pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); pa_iochannel_free(io); return; } @@ -1203,7 +1203,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->original_name = NULL; if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { - pa_log_info(__FILE__": Client authenticated by IP ACL."); + pa_log_info("Client authenticated by IP ACL."); c->authorized = 1; } @@ -1237,7 +1237,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve p = pa_xnew(pa_protocol_esound, 1); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { - pa_log(__FILE__": auth-anonymous= expects a boolean argument."); + pa_log("auth-anonymous= expects a boolean argument."); goto fail; } @@ -1247,7 +1247,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { if (!(p->auth_ip_acl = pa_ip_acl_new(acl))) { - pa_log(__FILE__": Failed to parse IP ACL '%s'", acl); + pa_log("Failed to parse IP ACL '%s'", acl); goto fail; } } else -- cgit From bffde5da05806ed1801b29b0440e9f542b3a6017 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 19 Aug 2006 23:06:45 +0000 Subject: If a client leaves the sink/source for a stream unspecified by passing NULL as sink/source name sink/source we should pass NULL to pa_sink_input_new()/pa_source_output_new() as too. This allows hooks to change the sink/source device only if it is left unspecified by the client git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1303 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index c96a98b9..80aeb27b 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -327,7 +327,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t int32_t format, rate; pa_sample_spec ss; size_t l; - pa_sink *sink; + pa_sink *sink = NULL; pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); @@ -344,8 +344,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t format_esd2native(format, c->swap_byte_order, &ss); CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification"); - sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY(sink, "No such sink"); + + if (c->protocol->sink_name) { + sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); + CHECK_VALIDITY(sink, "No such sink"); + } strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; @@ -397,7 +400,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; - pa_source *source; + pa_source *source = NULL; pa_sample_spec ss; size_t l; pa_source_output_new_data sdata; @@ -431,10 +434,12 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } else { assert(request == ESD_PROTO_STREAM_REC); - - if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { - pa_log("no such source."); - return -1; + + if (c->protocol->source_name) { + if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { + pa_log("no such source."); + return -1; + } } } -- cgit From d210ebbb09daddb2c8c8e8e77243e088b0b19c4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:50:56 +0000 Subject: rework memory block management to be thread-safe and mostly lock-free. pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 80aeb27b..65b93eb4 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -891,14 +891,22 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; + void *p; - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + assert(c->scache.memchunk.memblock); + assert(c->scache.name); + assert(c->scache.memchunk.index < c->scache.memchunk.length); + + p = pa_memblock_acquire(c->scache.memchunk.memblock); - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { + pa_memblock_release(c->scache.memchunk.memblock); pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } + pa_memblock_release(c->scache.memchunk.memblock); + c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); @@ -925,6 +933,7 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; assert(c->input_memblockq); @@ -937,7 +946,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -945,15 +954,21 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + assert(c->playback.current_memblock); + assert(pa_memblock_get_length(c->playback.current_memblock) >= l); c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + p = pa_memblock_acquire(c->playback.current_memblock); + + if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l)) <= 0) { + pa_memblock_release(c->playback.current_memblock); pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - + + pa_memblock_release(c->playback.current_memblock); + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -990,19 +1005,26 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; + void *p; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock && chunk.length); + assert(chunk.memblock); + assert(chunk.length); + + p = pa_memblock_acquire(chunk.memblock); - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { + pa_memblock_release(chunk.memblock); pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } + pa_memblock_release(chunk.memblock); + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); -- cgit From 8dc62142765249addf131b058c27f931ede1776b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:06:01 +0000 Subject: Revert r1404 and keep it on a development branch until it is fully tested. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1409 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 65b93eb4..80aeb27b 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -891,22 +891,14 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; - void *p; - assert(c->scache.memchunk.memblock); - assert(c->scache.name); - assert(c->scache.memchunk.index < c->scache.memchunk.length); - - p = pa_memblock_acquire(c->scache.memchunk.memblock); + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { - pa_memblock_release(c->scache.memchunk.memblock); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - pa_memblock_release(c->scache.memchunk.memblock); - c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); @@ -933,7 +925,6 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; - void *p; assert(c->input_memblockq); @@ -946,7 +937,7 @@ static int do_read(struct connection *c) { l = c->playback.fragment_size; if (c->playback.current_memblock) - if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { + if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; @@ -954,21 +945,15 @@ static int do_read(struct connection *c) { if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock); - assert(pa_memblock_get_length(c->playback.current_memblock) >= l); + assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); c->playback.memblock_index = 0; } - p = pa_memblock_acquire(c->playback.current_memblock); - - if ((r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l)) <= 0) { - pa_memblock_release(c->playback.current_memblock); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - - pa_memblock_release(c->playback.current_memblock); - + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; @@ -1005,26 +990,19 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; - void *p; assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock); - assert(chunk.length); - - p = pa_memblock_acquire(chunk.memblock); + assert(chunk.memblock && chunk.length); - if ((r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length)) < 0) { - pa_memblock_release(chunk.memblock); + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - pa_memblock_release(chunk.memblock); - pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); -- cgit From 55c25c657e907178de36e5b06b44cae66174d922 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 8 Nov 2006 12:56:26 +0000 Subject: Check correct variable for return value. Closes #37. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1411 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 80aeb27b..c36f8201 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -463,7 +463,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co sdata.client = c->client; c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); - CHECK_VALIDITY(c->sink_input, "Failed to create source_output."); + CHECK_VALIDITY(c->source_output, "Failed to create source_output."); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 152 ++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 76 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index c36f8201..2984676d 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -93,7 +93,7 @@ struct connection { pa_defer_event *defer_event; char *original_name; - + struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; @@ -177,7 +177,7 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 3 * sizeof(int), esd_proto_stream_pan, "stream pan"}, { 3 * sizeof(int), NULL, "sample pan" }, - + { sizeof(int), NULL, "standby mode" }, { 0, esd_proto_get_latency, "get latency" } }; @@ -188,19 +188,19 @@ static void connection_free(struct connection *c) { if (c->state == ESD_STREAMING_DATA) c->protocol->n_player--; - + pa_client_free(c->client); if (c->sink_input) { pa_sink_input_disconnect(c->sink_input); pa_sink_input_unref(c->sink_input); } - + if (c->source_output) { pa_source_output_disconnect(c->source_output); pa_source_output_unref(c->source_output); } - + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) @@ -208,13 +208,13 @@ static void connection_free(struct connection *c) { if (c->playback.current_memblock) pa_memblock_unref(c->playback.current_memblock); - + pa_xfree(c->read_data); pa_xfree(c->write_data); if (c->io) pa_iochannel_free(c->io); - + if (c->defer_event) c->protocol->core->mainloop->defer_free(c->defer_event); @@ -254,7 +254,7 @@ static void connection_write(struct connection *c, const void *data, size_t leng i = c->write_data_length; c->write_data_length += length; - + memcpy((char*)c->write_data + i, data, length); } @@ -270,7 +270,7 @@ static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { static int format_native2esd(pa_sample_spec *ss) { int format = 0; - + format = (ss->format == PA_SAMPLE_U8) ? ESD_BITS8 : ESD_BITS16; format |= (ss->channels >= 2) ? ESD_STEREO : ESD_MONO; @@ -331,7 +331,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - + memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); @@ -356,7 +356,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t utf8_name = pa_utf8_filter(name); pa_client_set_name(c->client, utf8_name); pa_xfree(utf8_name); - + c->original_name = pa_xstrdup(name); assert(!c->sink_input && !c->input_memblockq); @@ -368,11 +368,11 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink_input_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; - + c->sink_input = pa_sink_input_new(c->protocol->core, &sdata, 0); CHECK_VALIDITY(c->sink_input, "Failed to create sink input."); - l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); + l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); c->input_memblockq = pa_memblockq_new( 0, l, @@ -393,7 +393,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t c->state = ESD_STREAMING_DATA; c->protocol->n_player++; - + return 0; } @@ -406,7 +406,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source_output_new_data sdata; assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); - + memcpy(&format, data, sizeof(int32_t)); format = MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); @@ -442,14 +442,14 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co } } } - + strncpy(name, data, sizeof(name)); name[sizeof(name)-1] = 0; utf8_name = pa_utf8_filter(name); pa_client_set_name(c->client, utf8_name); pa_xfree(utf8_name); - + c->original_name = pa_xstrdup(name); assert(!c->output_memblockq && !c->source_output); @@ -461,11 +461,11 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co pa_source_output_new_data_set_sample_spec(&sdata, &ss); sdata.module = c->protocol->module; sdata.client = c->client; - + c->source_output = pa_source_output_new(c->protocol->core, &sdata, 9); CHECK_VALIDITY(c->source_output, "Failed to create source_output."); - l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); + l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); c->output_memblockq = pa_memblockq_new( 0, l, @@ -475,7 +475,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co 0, NULL); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); - + c->source_output->push = source_output_push_cb; c->source_output->kill = source_output_kill_cb; c->source_output->get_latency = source_output_get_latency_cb; @@ -484,7 +484,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->state = ESD_STREAMING_DATA; c->protocol->n_player++; - + return 0; } @@ -500,7 +500,7 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t double usec = pa_sink_get_latency(sink); latency = (int) ((usec*44100)/1000000); } - + latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); connection_write(c, &latency, sizeof(int32_t)); return 0; @@ -538,7 +538,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; assert(c && data && length == sizeof(int32_t)); - + if (esd_proto_server_info(c, request, data, length) < 0) return -1; @@ -559,7 +559,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v continue; assert(t >= k*2+s); - + if (conn->sink_input) { pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); rate = conn->sink_input->sample_spec.rate; @@ -567,7 +567,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v rvolume = (volume.values[1]*ESD_VOLUME_BASE)/PA_VOLUME_NORM; format = format_native2esd(&conn->sink_input->sample_spec); } - + /* id */ id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); connection_write(c, &id, sizeof(int32_t)); @@ -606,7 +606,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (nsamples) { pa_scache_entry *ce; - + idx = PA_IDXSET_INVALID; for (ce = pa_idxset_first(c->protocol->core->scache, &idx); ce; ce = pa_idxset_next(c->protocol->core->scache, &idx)) { int32_t id, rate, lvolume, rvolume, format, len; @@ -617,7 +617,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* id */ id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); connection_write(c, &id, sizeof(int32_t)); - + /* name */ memset(name, 0, ESD_NAME_MAX); /* don't leak old data */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) @@ -625,19 +625,19 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v else snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); connection_write(c, name, ESD_NAME_MAX); - + /* rate */ rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); connection_write(c, &rate, sizeof(int32_t)); - + /* left */ lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &lvolume, sizeof(int32_t)); - + /*right*/ rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &rvolume, sizeof(int32_t)); - + /*format*/ format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); connection_write(c, &format, sizeof(int32_t)); @@ -663,7 +663,7 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t struct connection *conn; assert(c && data && length == sizeof(int32_t)*3); - + memcpy(&idx, data, sizeof(uint32_t)); idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; data = (const char*)data + sizeof(uint32_t); @@ -687,7 +687,7 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t ok = 0; connection_write(c, &ok, sizeof(int32_t)); - + return 0; } @@ -706,7 +706,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ memcpy(&rate, data, sizeof(int32_t)); rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); - + ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -723,7 +723,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ name[sizeof(name)-1] = 0; CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - + assert(!c->scache.memchunk.memblock); c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; @@ -731,14 +731,14 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ c->scache.sample_spec = ss; assert(!c->scache.name); c->scache.name = pa_xstrdup(name); - + c->state = ESD_CACHING_SAMPLE; pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); idx += 1; connection_write(c, &idx, sizeof(uint32_t)); - + return 0; } @@ -775,11 +775,11 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; ok = 0; - + if ((name = pa_scache_get_name_by_id(c->protocol->core, idx))) { if (request == ESD_PROTO_SAMPLE_PLAY) { pa_sink *sink; - + if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) ok = idx + 1; @@ -790,7 +790,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque ok = idx + 1; } } - + connection_write(c, &ok, sizeof(int32_t)); return 0; @@ -821,7 +821,7 @@ static int do_read(struct connection *c) { assert(c && c->io); /* pa_log("READ"); */ - + if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); @@ -833,7 +833,7 @@ static int do_read(struct connection *c) { if ((c->read_data_length+= r) >= sizeof(c->request)) { struct proto_handler *handler; - + c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { @@ -849,18 +849,18 @@ static int do_read(struct connection *c) { pa_log("recieved unimplemented request #%u.", c->request); return -1; } - + if (handler->data_length == 0) { c->read_data_length = 0; if (handler->proc(c, c->request, NULL, 0) < 0) return -1; - + } else { if (c->read_data_alloc < handler->data_length) c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); assert(c->read_data); - + c->state = ESD_NEEDS_REQDATA; c->read_data_length = 0; } @@ -871,7 +871,7 @@ static int do_read(struct connection *c) { struct proto_handler *handler = proto_map+c->request; assert(handler->proc); - + assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { @@ -885,7 +885,7 @@ static int do_read(struct connection *c) { c->state = ESD_NEXT_REQUEST; c->read_data_length = 0; - + if (handler->proc(c, c->request, c->read_data, l) < 0) return -1; } @@ -893,7 +893,7 @@ static int do_read(struct connection *c) { ssize_t r; assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; @@ -901,10 +901,10 @@ static int do_read(struct connection *c) { c->scache.memchunk.index += r; assert(c->scache.memchunk.index <= c->scache.memchunk.length); - + if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t idx; - + c->scache.memchunk.index = 0; pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); @@ -920,7 +920,7 @@ static int do_read(struct connection *c) { idx += 1; connection_write(c, &idx, sizeof(uint32_t)); } - + } else if (c->state == ESD_STREAMING_DATA && c->sink_input) { pa_memchunk chunk; ssize_t r; @@ -936,13 +936,13 @@ static int do_read(struct connection *c) { if (l > c->playback.fragment_size) l = c->playback.fragment_size; - if (c->playback.current_memblock) + if (c->playback.current_memblock) if (c->playback.current_memblock->length - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } - + if (!c->playback.current_memblock) { c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); @@ -953,20 +953,20 @@ static int do_read(struct connection *c) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } - + chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; assert(chunk.memblock); c->playback.memblock_index += r; - + assert(c->input_memblockq); pa_memblockq_push_align(c->input_memblockq, &chunk); assert(c->sink_input); pa_sink_notify(c->sink_input->sink); } - + return 0; } @@ -974,19 +974,19 @@ static int do_write(struct connection *c) { assert(c && c->io); /* pa_log("WRITE"); */ - + if (c->write_data_length) { ssize_t r; - + assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - + if ((c->write_data_index +=r) >= c->write_data_length) c->write_data_length = c->write_data_index = 0; - + } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; @@ -994,9 +994,9 @@ static int do_write(struct connection *c) { assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - + assert(chunk.memblock && chunk.length); - + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); @@ -1008,7 +1008,7 @@ static int do_write(struct connection *c) { pa_source_notify(c->source_output->source); } - + return 0; } @@ -1035,7 +1035,7 @@ static void do_work(struct connection *c) { if (pa_iochannel_is_writable(c->io)) if (do_write(c) < 0) goto fail; - + return; fail: @@ -1066,7 +1066,7 @@ static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) assert(a && c && c->defer_event == e); /* pa_log("DEFER"); */ - + do_work(c); } @@ -1076,12 +1076,12 @@ static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { struct connection*c; assert(i && i->userdata && chunk); c = i->userdata; - + if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { if (c->dead) connection_free(c); - + return -1; } @@ -1093,7 +1093,7 @@ static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_ assert(i && c && length); /* pa_log("DROP"); */ - + pa_memblockq_drop(c->input_memblockq, chunk, length); /* do something */ @@ -1163,7 +1163,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_iochannel_free(io); return; } - + c = pa_xnew(struct connection, 1); c->protocol = p; c->io = io; @@ -1177,7 +1177,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; - + c->authorized = !!p->public; c->swap_byte_order = 0; c->dead = 0; @@ -1219,7 +1219,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c); } else c->auth_timeout_event = NULL; - + c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); assert(c->defer_event); p->core->mainloop->defer_enable(c->defer_event, 0); @@ -1233,7 +1233,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve pa_protocol_esound *p; int public = 0; const char *acl; - + assert(core); assert(server); assert(m); @@ -1257,7 +1257,7 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve } } else p->auth_ip_acl = NULL; - + p->module = m; p->public = public; p->server = server; -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 2984676d..ae6612ae 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit From 8bf7943e8e03922de8c4a0990057a6fbf07935c6 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 14 Feb 2007 09:27:19 +0000 Subject: Allow a formatted string in the validation warning. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1428 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index ae6612ae..49a78d41 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -280,9 +280,9 @@ static int format_native2esd(pa_sample_spec *ss) { return format; } -#define CHECK_VALIDITY(expression, string) do { \ +#define CHECK_VALIDITY(expression, ...) do { \ if (!(expression)) { \ - pa_log_warn(__FILE__ ": " string); \ + pa_log_warn(__FILE__ ": " __VA_ARGS__); \ return -1; \ } \ } while(0); @@ -350,7 +350,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t if (c->protocol->sink_name) { sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1); - CHECK_VALIDITY(sink, "No such sink"); + CHECK_VALIDITY(sink, "No such sink: %s", c->protocol->sink_name); } strncpy(name, data, sizeof(name)); @@ -719,7 +719,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); data = (const char*)data + sizeof(int32_t); - CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large."); + CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large (%d bytes).", (int)sc_length); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 640 +++++++++++++++++++++++++--------------- 1 file changed, 407 insertions(+), 233 deletions(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 49a78d41..76ba9dd0 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -53,6 +52,8 @@ #include #include #include +#include +#include #include "endianmacros.h" @@ -77,13 +78,15 @@ /* This is heavily based on esound's code */ -struct connection { +typedef struct connection { + pa_msgobject parent; + uint32_t index; - int dead; + pa_bool_t dead; pa_protocol_esound *protocol; pa_iochannel *io; pa_client *client; - int authorized, swap_byte_order; + pa_bool_t authorized, swap_byte_order; void *write_data; size_t write_data_alloc, write_data_index, write_data_length; void *read_data; @@ -100,6 +103,7 @@ struct connection { struct { pa_memblock *current_memblock; size_t memblock_index, fragment_size; + pa_atomic_t missing; } playback; struct { @@ -109,46 +113,62 @@ struct connection { } scache; pa_time_event *auth_timeout_event; -}; +} connection; + +PA_DECLARE_CLASS(connection); +#define CONNECTION(o) (connection_cast(o)) +static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject); struct pa_protocol_esound { - int public; pa_module *module; pa_core *core; + int public; pa_socket_server *server; pa_idxset *connections; + char *sink_name, *source_name; unsigned n_player; uint8_t esd_key[ESD_KEY_LEN]; pa_ip_acl *auth_ip_acl; }; +enum { + SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX, /* data from main loop to sink input */ + SINK_INPUT_MESSAGE_DISABLE_PREBUF +}; + +enum { + CONNECTION_MESSAGE_REQUEST_DATA, + CONNECTION_MESSAGE_POST_DATA, + CONNECTION_MESSAGE_UNLINK_CONNECTION +}; + typedef struct proto_handler { size_t data_length; - int (*proc)(struct connection *c, esd_proto_t request, const void *data, size_t length); + int (*proc)(connection *c, esd_proto_t request, const void *data, size_t length); const char *description; } esd_proto_handler_info_t; -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk); +static void sink_input_drop_cb(pa_sink_input *i, size_t length); +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); static void sink_input_kill_cb(pa_sink_input *i); -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i); +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); static pa_usec_t source_output_get_latency_cb(pa_source_output *o); static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); static void source_output_kill_cb(pa_source_output *o); -static int esd_proto_connect(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_get_latency(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_server_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_sample_get_id(struct connection *c, esd_proto_t request, const void *data, size_t length); -static int esd_proto_standby_or_resume(struct connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_connect(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_play(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_get_latency(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_server_info(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_stream_pan(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_cache(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_sample_get_id(connection *c, esd_proto_t request, const void *data, size_t length); +static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const void *data, size_t length); /* the big map of protocol handler info */ static struct proto_handler proto_map[ESD_PROTO_MAX] = { @@ -185,25 +205,56 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 0, esd_proto_get_latency, "get latency" } }; -static void connection_free(struct connection *c) { - assert(c); - pa_idxset_remove_by_data(c->protocol->connections, c, NULL); +static void connection_unlink(connection *c) { + pa_assert(c); - if (c->state == ESD_STREAMING_DATA) - c->protocol->n_player--; - - pa_client_free(c->client); + if (!c->protocol) + return; if (c->sink_input) { - pa_sink_input_disconnect(c->sink_input); + pa_sink_input_unlink(c->sink_input); pa_sink_input_unref(c->sink_input); + c->sink_input = NULL; } if (c->source_output) { - pa_source_output_disconnect(c->source_output); + pa_source_output_unlink(c->source_output); pa_source_output_unref(c->source_output); + c->source_output = NULL; } + if (c->client) { + pa_client_free(c->client); + c->client = NULL; + } + + if (c->state == ESD_STREAMING_DATA) + c->protocol->n_player--; + + if (c->io) { + pa_iochannel_free(c->io); + c->io = NULL; + } + + if (c->defer_event) { + c->protocol->core->mainloop->defer_free(c->defer_event); + c->defer_event = NULL; + } + + if (c->auth_timeout_event) { + c->protocol->core->mainloop->time_free(c->auth_timeout_event); + c->auth_timeout_event = NULL; + } + + pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c); + c->protocol = NULL; + connection_unref(c); +} + +static void connection_free(pa_object *obj) { + connection *c = CONNECTION(obj); + pa_assert(c); + if (c->input_memblockq) pa_memblockq_free(c->input_memblockq); if (c->output_memblockq) @@ -215,54 +266,44 @@ static void connection_free(struct connection *c) { pa_xfree(c->read_data); pa_xfree(c->write_data); - if (c->io) - pa_iochannel_free(c->io); - - if (c->defer_event) - c->protocol->core->mainloop->defer_free(c->defer_event); - if (c->scache.memchunk.memblock) pa_memblock_unref(c->scache.memchunk.memblock); pa_xfree(c->scache.name); - if (c->auth_timeout_event) - c->protocol->core->mainloop->time_free(c->auth_timeout_event); - pa_xfree(c->original_name); pa_xfree(c); } -static void connection_write_prepare(struct connection *c, size_t length) { +static void connection_write_prepare(connection *c, size_t length) { size_t t; - assert(c); + pa_assert(c); t = c->write_data_length+length; if (c->write_data_alloc < t) c->write_data = pa_xrealloc(c->write_data, c->write_data_alloc = t); - assert(c->write_data); + pa_assert(c->write_data); } -static void connection_write(struct connection *c, const void *data, size_t length) { +static void connection_write(connection *c, const void *data, size_t length) { size_t i; - assert(c); + pa_assert(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 1); connection_write_prepare(c, length); - assert(c->write_data); + pa_assert(c->write_data); i = c->write_data_length; c->write_data_length += length; - memcpy((char*)c->write_data + i, data, length); + memcpy((uint8_t*) c->write_data + i, data, length); } -static void format_esd2native(int format, int swap_bytes, pa_sample_spec *ss) { - assert(ss); +static void format_esd2native(int format, pa_bool_t swap_bytes, pa_sample_spec *ss) { + pa_assert(ss); ss->channels = ((format & ESD_MASK_CHAN) == ESD_STEREO) ? 2 : 1; if ((format & ESD_MASK_BITS) == ESD_BITS16) @@ -289,11 +330,13 @@ static int format_native2esd(pa_sample_spec *ss) { /*** esound commands ***/ -static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_connect(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { uint32_t ekey; int ok; - assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (ESD_KEY_LEN + sizeof(uint32_t))); if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { @@ -301,7 +344,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req return -1; } - c->authorized = 1; + c->authorized = TRUE; if (c->auth_timeout_event) { c->protocol->core->mainloop->time_free(c->auth_timeout_event); c->auth_timeout_event = NULL; @@ -312,11 +355,11 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req memcpy(&ekey, data, sizeof(uint32_t)); if (ekey == ESD_ENDIAN_KEY) - c->swap_byte_order = 0; + c->swap_byte_order = FALSE; else if (ekey == ESD_SWAP_ENDIAN_KEY) - c->swap_byte_order = 1; + c->swap_byte_order = TRUE; else { - pa_log("client sent invalid endian key"); + pa_log_warn("Client sent invalid endian key"); return -1; } @@ -325,7 +368,7 @@ static int esd_proto_connect(struct connection *c, PA_GCC_UNUSED esd_proto_t req return 0; } -static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_play(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_sample_spec ss; @@ -333,15 +376,17 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t pa_sink *sink = NULL; pa_sink_input_new_data sdata; - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX)); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*) data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*) data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -362,7 +407,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t c->original_name = pa_xstrdup(name); - assert(!c->sink_input && !c->input_memblockq); + pa_assert(!c->sink_input && !c->input_memblockq); pa_sink_input_new_data_init(&sdata); sdata.sink = sink; @@ -385,22 +430,26 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t l/PLAYBACK_BUFFER_FRAGMENTS, NULL); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); - c->playback.fragment_size = l/10; + c->playback.fragment_size = l/PLAYBACK_BUFFER_FRAGMENTS; + c->sink_input->parent.process_msg = sink_input_process_msg; c->sink_input->peek = sink_input_peek_cb; c->sink_input->drop = sink_input_drop_cb; c->sink_input->kill = sink_input_kill_cb; - c->sink_input->get_latency = sink_input_get_latency_cb; c->sink_input->userdata = c; c->state = ESD_STREAMING_DATA; c->protocol->n_player++; + pa_atomic_store(&c->playback.missing, pa_memblockq_missing(c->input_memblockq)); + + pa_sink_input_put(c->sink_input); + return 0; } -static int esd_proto_stream_record(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_record(connection *c, esd_proto_t request, const void *data, size_t length) { char name[ESD_NAME_MAX], *utf8_name; int32_t format, rate; pa_source *source = NULL; @@ -408,15 +457,17 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co size_t l; pa_source_output_new_data sdata; - assert(c && length == (sizeof(int32_t)*2+ESD_NAME_MAX)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (sizeof(int32_t)*2+ESD_NAME_MAX)); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); - data = (const char*)data + sizeof(int32_t); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); + data = (const char*) data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); - data = (const char*)data + sizeof(int32_t); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); + data = (const char*) data + sizeof(int32_t); ss.rate = rate; format_esd2native(format, c->swap_byte_order, &ss); @@ -436,7 +487,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co return -1; } } else { - assert(request == ESD_PROTO_STREAM_REC); + pa_assert(request == ESD_PROTO_STREAM_REC); if (c->protocol->source_name) { if (!(source = pa_namereg_get(c->protocol->core, c->protocol->source_name, PA_NAMEREG_SOURCE, 1))) { @@ -455,7 +506,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->original_name = pa_xstrdup(name); - assert(!c->output_memblockq && !c->source_output); + pa_assert(!c->output_memblockq && !c->source_output); pa_source_output_new_data_init(&sdata); sdata.source = source; @@ -488,14 +539,18 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co c->protocol->n_player++; + pa_source_output_put(c->source_output); + return 0; } -static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_get_latency(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sink *sink; int32_t latency; - assert(c && !data && length == 0); + connection_ref(c); + pa_assert(!data); + pa_assert(length == 0); if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; @@ -504,17 +559,19 @@ static int esd_proto_get_latency(struct connection *c, PA_GCC_UNUSED esd_proto_t latency = (int) ((usec*44100)/1000000); } - latency = MAYBE_INT32_SWAP(c->swap_byte_order, latency); + latency = PA_MAYBE_INT32_SWAP(c->swap_byte_order, latency); connection_write(c, &latency, sizeof(int32_t)); return 0; } -static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_server_info(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t rate = 44100, format = ESD_STEREO|ESD_BITS16; int32_t response; pa_sink *sink; - assert(c && data && length == sizeof(int32_t)); + connection_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { rate = sink->sample_spec.rate; @@ -525,22 +582,24 @@ static int esd_proto_server_info(struct connection *c, PA_GCC_UNUSED esd_proto_t response = 0; connection_write(c, &response, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); connection_write(c, &rate, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); connection_write(c, &format, sizeof(int32_t)); return 0; } -static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_all_info(connection *c, esd_proto_t request, const void *data, size_t length) { size_t t, k, s; - struct connection *conn; + connection *conn; uint32_t idx = PA_IDXSET_INVALID; unsigned nsamples; char terminator[sizeof(int32_t)*6+ESD_NAME_MAX]; - assert(c && data && length == sizeof(int32_t)); + connection_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); if (esd_proto_server_info(c, request, data, length) < 0) return -1; @@ -561,7 +620,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->state != ESD_STREAMING_DATA) continue; - assert(t >= k*2+s); + pa_assert(t >= k*2+s); if (conn->sink_input) { pa_cvolume volume = *pa_sink_input_get_volume(conn->sink_input); @@ -572,7 +631,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v } /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); + id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int32_t) (conn->index+1)); connection_write(c, &id, sizeof(int32_t)); /* name */ @@ -584,25 +643,25 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v connection_write(c, name, ESD_NAME_MAX); /* rate */ - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); connection_write(c, &rate, sizeof(int32_t)); /* left */ - lvolume = MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); + lvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, lvolume); connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - rvolume = MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); + rvolume = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rvolume); connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); connection_write(c, &format, sizeof(int32_t)); t -= k; } - assert(t == s*(nsamples+1)+k); + pa_assert(t == s*(nsamples+1)+k); t -= k; connection_write(c, terminator, k); @@ -615,10 +674,10 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v int32_t id, rate, lvolume, rvolume, format, len; char name[ESD_NAME_MAX]; - assert(t >= s*2); + pa_assert(t >= s*2); /* id */ - id = MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); + id = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) (ce->index+1)); connection_write(c, &id, sizeof(int32_t)); /* name */ @@ -626,57 +685,59 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) strncpy(name, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else - snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); + pa_snprintf(name, ESD_NAME_MAX, "native.%s", ce->name); connection_write(c, name, ESD_NAME_MAX); /* rate */ - rate = MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); + rate = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, ce->sample_spec.rate); connection_write(c, &rate, sizeof(int32_t)); /* left */ - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &lvolume, sizeof(int32_t)); /*right*/ - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); + rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, (ce->volume.values[0]*ESD_VOLUME_BASE)/PA_VOLUME_NORM); connection_write(c, &rvolume, sizeof(int32_t)); /*format*/ - format = MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format_native2esd(&ce->sample_spec)); connection_write(c, &format, sizeof(int32_t)); /*length*/ - len = MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); + len = PA_MAYBE_INT32_SWAP(c->swap_byte_order, (int) ce->memchunk.length); connection_write(c, &len, sizeof(int32_t)); t -= s; } } - assert(t == s); + pa_assert(t == s); connection_write(c, terminator, s); return 0; } -static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_stream_pan(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx, lvolume, rvolume; - struct connection *conn; + connection *conn; - assert(c && data && length == sizeof(int32_t)*3); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)*3); memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; data = (const char*)data + sizeof(uint32_t); memcpy(&lvolume, data, sizeof(uint32_t)); - lvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); + lvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, lvolume); data = (const char*)data + sizeof(uint32_t); memcpy(&rvolume, data, sizeof(uint32_t)); - rvolume = MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); + rvolume = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, rvolume); data = (const char*)data + sizeof(uint32_t); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx)) && conn->sink_input) { @@ -694,20 +755,22 @@ static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t return 0; } -static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_cache(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { pa_sample_spec ss; int32_t format, rate, sc_length; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == (ESD_NAME_MAX+3*sizeof(int32_t))); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == (ESD_NAME_MAX+3*sizeof(int32_t))); memcpy(&format, data, sizeof(int32_t)); - format = MAYBE_INT32_SWAP(c->swap_byte_order, format); + format = PA_MAYBE_INT32_SWAP(c->swap_byte_order, format); data = (const char*)data + sizeof(int32_t); memcpy(&rate, data, sizeof(int32_t)); - rate = MAYBE_INT32_SWAP(c->swap_byte_order, rate); + rate = PA_MAYBE_INT32_SWAP(c->swap_byte_order, rate); data = (const char*)data + sizeof(int32_t); ss.rate = rate; @@ -716,7 +779,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_sample_spec_valid(&ss), "Invalid sample specification."); memcpy(&sc_length, data, sizeof(int32_t)); - sc_length = MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); + sc_length = PA_MAYBE_INT32_SWAP(c->swap_byte_order, sc_length); data = (const char*)data + sizeof(int32_t); CHECK_VALIDITY(sc_length <= MAX_CACHE_SAMPLE_SIZE, "Sample too large (%d bytes).", (int)sc_length); @@ -727,12 +790,12 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ CHECK_VALIDITY(pa_utf8_valid(name), "Invalid UTF8 in sample name."); - assert(!c->scache.memchunk.memblock); + pa_assert(!c->scache.memchunk.memblock); c->scache.memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, sc_length); c->scache.memchunk.index = 0; c->scache.memchunk.length = sc_length; c->scache.sample_spec = ss; - assert(!c->scache.name); + pa_assert(!c->scache.name); c->scache.name = pa_xstrdup(name); c->state = ESD_CACHING_SAMPLE; @@ -745,12 +808,14 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ return 0; } -static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_get_id(connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int32_t ok; uint32_t idx; char name[ESD_NAME_MAX+sizeof(SCACHE_PREFIX)-1]; - assert(c && data && length == ESD_NAME_MAX); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == ESD_NAME_MAX); strcpy(name, SCACHE_PREFIX); strncpy(name+sizeof(SCACHE_PREFIX)-1, data, ESD_NAME_MAX); @@ -767,15 +832,17 @@ static int esd_proto_sample_get_id(struct connection *c, PA_GCC_UNUSED esd_proto return 0; } -static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t request, const void *data, size_t length) { +static int esd_proto_sample_free_or_play(connection *c, esd_proto_t request, const void *data, size_t length) { int32_t ok; const char *name; uint32_t idx; - assert(c && data && length == sizeof(int32_t)); + connection_assert_ref(c); + pa_assert(data); + pa_assert(length == sizeof(int32_t)); memcpy(&idx, data, sizeof(uint32_t)); - idx = MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; + idx = PA_MAYBE_UINT32_SWAP(c->swap_byte_order, idx) - 1; ok = 0; @@ -787,7 +854,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) ok = idx + 1; } else { - assert(request == ESD_PROTO_SAMPLE_FREE); + pa_assert(request == ESD_PROTO_SAMPLE_FREE); if (pa_scache_remove_item(c->protocol->core, name) >= 0) ok = idx + 1; @@ -799,9 +866,11 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque return 0; } -static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { +static int esd_proto_standby_or_resume(connection *c, PA_GCC_UNUSED esd_proto_t request, PA_GCC_UNUSED const void *data, PA_GCC_UNUSED size_t length) { int32_t ok; + connection_assert_ref(c); + connection_write_prepare(c, sizeof(int32_t) * 2); ok = 1; @@ -814,20 +883,21 @@ static int esd_proto_standby_or_resume(struct connection *c, PA_GCC_UNUSED esd_p /*** client callbacks ***/ static void client_kill_cb(pa_client *c) { - assert(c && c->userdata); - connection_free(c->userdata); + pa_assert(c); + + connection_unlink(CONNECTION(c->userdata)); } /*** pa_iochannel callbacks ***/ -static int do_read(struct connection *c) { - assert(c && c->io); +static int do_read(connection *c) { + connection_assert_ref(c); -/* pa_log("READ"); */ +/* pa_log("READ"); */ if (c->state == ESD_NEXT_REQUEST) { ssize_t r; - assert(c->read_data_length < sizeof(c->request)); + pa_assert(c->read_data_length < sizeof(c->request)); if ((r = pa_iochannel_read(c->io, ((uint8_t*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); @@ -837,7 +907,7 @@ static int do_read(struct connection *c) { if ((c->read_data_length+= r) >= sizeof(c->request)) { struct proto_handler *handler; - c->request = MAYBE_INT32_SWAP(c->swap_byte_order, c->request); + c->request = PA_MAYBE_INT32_SWAP(c->swap_byte_order, c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { pa_log("recieved invalid request."); @@ -862,7 +932,7 @@ static int do_read(struct connection *c) { } else { if (c->read_data_alloc < handler->data_length) c->read_data = pa_xrealloc(c->read_data, c->read_data_alloc = handler->data_length); - assert(c->read_data); + pa_assert(c->read_data); c->state = ESD_NEEDS_REQDATA; c->read_data_length = 0; @@ -873,18 +943,21 @@ static int do_read(struct connection *c) { ssize_t r; struct proto_handler *handler = proto_map+c->request; - assert(handler->proc); + pa_assert(handler->proc); - assert(c->read_data && c->read_data_length < handler->data_length); + pa_assert(c->read_data && c->read_data_length < handler->data_length); if ((r = pa_iochannel_read(c->io, (uint8_t*) c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } if ((c->read_data_length += r) >= handler->data_length) { size_t l = c->read_data_length; - assert(handler->proc); + pa_assert(handler->proc); c->state = ESD_NEXT_REQUEST; c->read_data_length = 0; @@ -894,16 +967,26 @@ static int do_read(struct connection *c) { } } else if (c->state == ESD_CACHING_SAMPLE) { ssize_t r; + void *p; - assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); + pa_assert(c->scache.memchunk.memblock); + pa_assert(c->scache.name); + pa_assert(c->scache.memchunk.index < c->scache.memchunk.length); + + p = pa_memblock_acquire(c->scache.memchunk.memblock); + r = pa_iochannel_read(c->io, (uint8_t*) p+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index); + pa_memblock_release(c->scache.memchunk.memblock); + + if (r <= 0) { + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) { pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } c->scache.memchunk.index += r; - assert(c->scache.memchunk.index <= c->scache.memchunk.length); + pa_assert(c->scache.memchunk.index <= c->scache.memchunk.length); if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t idx; @@ -928,31 +1011,39 @@ static int do_read(struct connection *c) { pa_memchunk chunk; ssize_t r; size_t l; + void *p; - assert(c->input_memblockq); + pa_assert(c->input_memblockq); /* pa_log("STREAMING_DATA"); */ - if (!(l = pa_memblockq_missing(c->input_memblockq))) + if (!(l = pa_atomic_load(&c->playback.missing))) return 0; if (l > c->playback.fragment_size) l = c->playback.fragment_size; if (c->playback.current_memblock) - if (c->playback.current_memblock->length - c->playback.memblock_index < l) { + if (pa_memblock_get_length(c->playback.current_memblock) - c->playback.memblock_index < l) { pa_memblock_unref(c->playback.current_memblock); c->playback.current_memblock = NULL; c->playback.memblock_index = 0; } if (!c->playback.current_memblock) { - c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2); - assert(c->playback.current_memblock && c->playback.current_memblock->length >= l); + pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, c->playback.fragment_size*2)); c->playback.memblock_index = 0; } - if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + p = pa_memblock_acquire(c->playback.current_memblock); + r = pa_iochannel_read(c->io, (uint8_t*) p+c->playback.memblock_index, l); + pa_memblock_release(c->playback.current_memblock); + + if (r <= 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log_debug("read(): %s", r < 0 ? pa_cstrerror(errno) : "EOF"); return -1; } @@ -960,29 +1051,30 @@ static int do_read(struct connection *c) { chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; chunk.length = r; - assert(chunk.memblock); c->playback.memblock_index += r; - assert(c->input_memblockq); - pa_memblockq_push_align(c->input_memblockq, &chunk); - assert(c->sink_input); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, &chunk, NULL); + pa_atomic_sub(&c->playback.missing, r); } return 0; } -static int do_write(struct connection *c) { - assert(c && c->io); +static int do_write(connection *c) { + connection_assert_ref(c); /* pa_log("WRITE"); */ if (c->write_data_length) { ssize_t r; - assert(c->write_data_index < c->write_data_length); + pa_assert(c->write_data_index < c->write_data_length); if ((r = pa_iochannel_write(c->io, (uint8_t*) c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + pa_log("write(): %s", pa_cstrerror(errno)); return -1; } @@ -993,32 +1085,38 @@ static int do_write(struct connection *c) { } else if (c->state == ESD_STREAMING_DATA && c->source_output) { pa_memchunk chunk; ssize_t r; + void *p; - assert(c->output_memblockq); if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0) return 0; - assert(chunk.memblock && chunk.length); + pa_assert(chunk.memblock); + pa_assert(chunk.length); + + p = pa_memblock_acquire(chunk.memblock); + r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length); + pa_memblock_release(chunk.memblock); + + pa_memblock_unref(chunk.memblock); + + if (r < 0) { + + if (r < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; - if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { - pa_memblock_unref(chunk.memblock); pa_log("write(): %s", pa_cstrerror(errno)); return -1; } - pa_memblockq_drop(c->output_memblockq, &chunk, r); - pa_memblock_unref(chunk.memblock); - - pa_source_notify(c->source_output->source); + pa_memblockq_drop(c->output_memblockq, r); } return 0; } -static void do_work(struct connection *c) { - assert(c); +static void do_work(connection *c) { + connection_assert_ref(c); - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); c->protocol->core->mainloop->defer_enable(c->defer_event, 0); if (c->dead) @@ -1044,122 +1142,196 @@ static void do_work(struct connection *c) { fail: if (c->state == ESD_STREAMING_DATA && c->sink_input) { - c->dead = 1; + c->dead = TRUE; pa_iochannel_free(c->io); c->io = NULL; - pa_memblockq_prebuf_disable(c->input_memblockq); - pa_sink_notify(c->sink_input->sink); + pa_asyncmsgq_post(c->sink_input->sink->asyncmsgq, PA_MSGOBJECT(c->sink_input), SINK_INPUT_MESSAGE_DISABLE_PREBUF, NULL, 0, NULL, NULL); } else - connection_free(c); + connection_unlink(c); } static void io_callback(pa_iochannel*io, void *userdata) { - struct connection *c = userdata; - assert(io && c && c->io == io); + connection *c = CONNECTION(userdata); + + connection_assert_ref(c); + pa_assert(io); do_work(c); } -/*** defer callback ***/ - static void defer_callback(pa_mainloop_api*a, pa_defer_event *e, void *userdata) { - struct connection *c = userdata; - assert(a && c && c->defer_event == e); + connection *c = CONNECTION(userdata); -/* pa_log("DEFER"); */ + connection_assert_ref(c); + pa_assert(e); do_work(c); } -/*** sink_input callbacks ***/ +static int connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { + connection *c = CONNECTION(o); + connection_assert_ref(c); -static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) { - struct connection*c; - assert(i && i->userdata && chunk); - c = i->userdata; + switch (code) { + case CONNECTION_MESSAGE_REQUEST_DATA: + do_work(c); + break; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + case CONNECTION_MESSAGE_POST_DATA: +/* pa_log("got data %u", chunk->length); */ + pa_memblockq_push_align(c->output_memblockq, chunk); + do_work(c); + break; - if (c->dead) - connection_free(c); - - return -1; + case CONNECTION_MESSAGE_UNLINK_CONNECTION: + connection_unlink(c); + break; } return 0; } -static void sink_input_drop_cb(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - struct connection*c = i->userdata; - assert(i && c && length); +/*** sink_input callbacks ***/ + +/* Called from thread context */ +static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { + pa_sink_input *i = PA_SINK_INPUT(o); + connection*c; + + pa_sink_input_assert_ref(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + + switch (code) { + + case SINK_INPUT_MESSAGE_POST_DATA: { + pa_assert(chunk); + + /* New data from the main loop */ + pa_memblockq_push_align(c->input_memblockq, chunk); + +/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */ + + return 0; + } -/* pa_log("DROP"); */ + case SINK_INPUT_MESSAGE_DISABLE_PREBUF: { + pa_memblockq_prebuf_disable(c->input_memblockq); + return 0; + } - pa_memblockq_drop(c->input_memblockq, chunk, length); + case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { + pa_usec_t *r = userdata; - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + *r = pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + /* Fall through, the default handler will add in the extra + * latency added by the resampler */ + } -/* assert(pa_memblockq_get_length(c->input_memblockq) > 2048); */ + default: + return pa_sink_input_process_msg(o, code, userdata, offset, chunk); + } } -static void sink_input_kill_cb(pa_sink_input *i) { - assert(i && i->userdata); - connection_free((struct connection *) i->userdata); +/* Called from thread context */ +static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) { + connection*c; + int r; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(chunk); + + if ((r = pa_memblockq_peek(c->input_memblockq, chunk)) < 0 && c->dead) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL); + + return r; +} + +/* Called from thread context */ +static void sink_input_drop_cb(pa_sink_input *i, size_t length) { + connection*c; + size_t old, new; + + pa_assert(i); + c = CONNECTION(i->userdata); + connection_assert_ref(c); + pa_assert(length); + + /* pa_log("DROP"); */ + + old = pa_memblockq_missing(c->input_memblockq); + pa_memblockq_drop(c->input_memblockq, length); + new = pa_memblockq_missing(c->input_memblockq); + + if (new > old) { + if (pa_atomic_add(&c->playback.missing, new - old) <= 0) + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL); + } } -static pa_usec_t sink_input_get_latency_cb(pa_sink_input *i) { - struct connection*c = i->userdata; - assert(i && c); - return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec); +static void sink_input_kill_cb(pa_sink_input *i) { + pa_sink_input_assert_ref(i); + + connection_unlink(CONNECTION(i->userdata)); } /*** source_output callbacks ***/ +/* Called from thread context */ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { - struct connection *c = o->userdata; - assert(o && c && chunk); - - pa_memblockq_push(c->output_memblockq, chunk); + connection *c; - /* do something */ - assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable); + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + pa_assert(chunk); - if (!c->dead) - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); } static void source_output_kill_cb(pa_source_output *o) { - assert(o && o->userdata); - connection_free((struct connection *) o->userdata); + pa_source_output_assert_ref(o); + + connection_unlink(CONNECTION(o->userdata)); } static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { - struct connection*c = o->userdata; - assert(o && c); + connection*c; + + pa_assert(o); + c = CONNECTION(o->userdata); + pa_assert(c); + return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec); } /*** socket server callback ***/ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { - struct connection *c = userdata; - assert(m && tv && c && c->auth_timeout_event == e); + connection *c = CONNECTION(userdata); + + pa_assert(m); + pa_assert(tv); + connection_assert_ref(c); + pa_assert(c->auth_timeout_event == e); if (!c->authorized) - connection_free(c); + connection_unlink(c); } static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) { - struct connection *c; + connection *c; pa_protocol_esound *p = userdata; char cname[256], pname[128]; - assert(s && io && p); + + pa_assert(s); + pa_assert(io); + pa_assert(p); if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { pa_log("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); @@ -1167,23 +1339,23 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) return; } - c = pa_xnew(struct connection, 1); + c = pa_msgobject_new(connection); + c->parent.parent.free = connection_free; + c->parent.process_msg = connection_process_msg; c->protocol = p; c->io = io; pa_iochannel_set_callback(c->io, io_callback, c); pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); - assert(p->core); + pa_snprintf(cname, sizeof(cname), "EsounD client (%s)", pname); c->client = pa_client_new(p->core, __FILE__, cname); - assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; c->client->userdata = c; c->authorized = !!p->public; - c->swap_byte_order = 0; - c->dead = 0; + c->swap_byte_order = FALSE; + c->dead = FALSE; c->read_data_length = 0; c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); @@ -1203,6 +1375,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.current_memblock = NULL; c->playback.memblock_index = 0; c->playback.fragment_size = 0; + pa_atomic_store(&c->playback.missing, 0); c->scache.memchunk.length = c->scache.memchunk.index = 0; c->scache.memchunk.memblock = NULL; @@ -1212,7 +1385,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) if (!c->authorized && p->auth_ip_acl && pa_ip_acl_check(p->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { pa_log_info("Client authenticated by IP ACL."); - c->authorized = 1; + c->authorized = TRUE; } if (!c->authorized) { @@ -1224,7 +1397,6 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->auth_timeout_event = NULL; c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c); - assert(c->defer_event); p->core->mainloop->defer_enable(c->defer_event, 0); pa_idxset_put(p->connections, c, &c->index); @@ -1233,22 +1405,22 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) /*** entry points ***/ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { - pa_protocol_esound *p; + pa_protocol_esound *p = NULL; int public = 0; const char *acl; - assert(core); - assert(server); - assert(m); - assert(ma); - - p = pa_xnew(pa_protocol_esound, 1); + pa_assert(core); + pa_assert(server); + pa_assert(m); + pa_assert(ma); if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &public) < 0) { pa_log("auth-anonymous= expects a boolean argument."); goto fail; } + p = pa_xnew(pa_protocol_esound, 1); + if (pa_authkey_load_auto(pa_modargs_get_value(ma, "cookie", DEFAULT_COOKIE_FILE), p->esd_key, sizeof(p->esd_key)) < 0) goto fail; @@ -1261,13 +1433,12 @@ pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *serve } else p->auth_ip_acl = NULL; + p->core = core; p->module = m; p->public = public; p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); - p->core = core; p->connections = pa_idxset_new(NULL, NULL); - assert(p->connections); p->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); p->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL)); @@ -1281,17 +1452,20 @@ fail: } void pa_protocol_esound_free(pa_protocol_esound *p) { - struct connection *c; - assert(p); + connection *c; + pa_assert(p); while ((c = pa_idxset_first(p->connections, NULL))) - connection_free(c); - + connection_unlink(c); pa_idxset_free(p->connections, NULL, NULL); + pa_socket_server_unref(p->server); if (p->auth_ip_acl) pa_ip_acl_free(p->auth_ip_acl); + pa_xfree(p->sink_name); + pa_xfree(p->source_name); + pa_xfree(p); } -- cgit From d17bb53d3ebfbd7046719400264bd87830c140d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:37:44 +0000 Subject: Completely rework ALSA device selection code: choose the device to open depending on the requested number of channels and channel map. In most cases it will now suffice to set default-channels=6 to enable 5.1 sound for all devices that support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2050 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pulsecore/protocol-esound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/pulsecore/protocol-esound.c') diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c index 76ba9dd0..004e535e 100644 --- a/src/pulsecore/protocol-esound.c +++ b/src/pulsecore/protocol-esound.c @@ -1406,7 +1406,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_protocol_esound* pa_protocol_esound_new(pa_core*core, pa_socket_server *server, pa_module *m, pa_modargs *ma) { pa_protocol_esound *p = NULL; - int public = 0; + pa_bool_t public = FALSE; const char *acl; pa_assert(core); -- cgit