X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/c17545108b33162fb186f797b8a408511e9252f4..fa499dad06ba6558111cdef64c18f2401e803cff:/polyp/protocol-esound.c diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index fb639b7f..4da7e388 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + 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. @@ -13,7 +13,7 @@ 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 General Public License + You should have received a copy of the GNU Lesser General Public License along with polypaudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. @@ -45,6 +45,7 @@ #include "debug.h" #include "namereg.h" #include "xmalloc.h" +#include "log.h" #define DEFAULT_COOKIE_FILE ".esd_auth" @@ -61,6 +62,7 @@ struct connection { uint32_t index; + int dead; struct pa_protocol_esound *protocol; struct pa_iochannel *io; struct pa_client *client; @@ -75,14 +77,17 @@ struct connection { struct pa_source_output *source_output; struct pa_memblockq *input_memblockq, *output_memblockq; struct pa_defer_event *defer_event; + struct { struct pa_memblock *current_memblock; size_t memblock_index, fragment_size; } playback; - struct pa_memchunk scache_memchunk; - char *scache_name; - struct pa_sample_spec scache_sample_spec; + struct { + struct pa_memchunk memchunk; + char *name; + struct pa_sample_spec sample_spec; + } scache; }; struct pa_protocol_esound { @@ -102,10 +107,11 @@ typedef struct proto_handler { const char *description; } esd_proto_handler_info_t; -static void sink_input_drop_cb(struct pa_sink_input *i, size_t length); +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length); static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk); static void sink_input_kill_cb(struct pa_sink_input *i); -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i); +static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i); +static pa_usec_t source_output_get_latency_cb(struct pa_source_output *o); static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk); static void source_output_kill_cb(struct pa_source_output *o); @@ -120,6 +126,7 @@ static int esd_proto_stream_pan(struct connection *c, esd_proto_t request, const 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] = { @@ -131,17 +138,17 @@ static struct proto_handler proto_map[ESD_PROTO_MAX] = { { 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" }, + { 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" }, + { 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), NULL, "standby" }, - { ESD_KEY_LEN + sizeof(int), NULL, "resume" }, + { 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" }, + { 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" }, @@ -166,10 +173,16 @@ static void connection_free(struct connection *c) { pa_client_free(c->client); - if (c->sink_input) - pa_sink_input_free(c->sink_input); - if (c->source_output) - pa_source_output_free(c->source_output); + 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) @@ -180,15 +193,16 @@ static void connection_free(struct connection *c) { pa_xfree(c->read_data); pa_xfree(c->write_data); - - pa_iochannel_free(c->io); + + 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->scache.memchunk.memblock) + pa_memblock_unref(c->scache.memchunk.memblock); + pa_xfree(c->scache.name); pa_xfree(c); } @@ -210,7 +224,7 @@ static void* connection_write(struct connection *c, size_t length) { i = c->write_data_length; c->write_data_length += length; - return c->write_data+i; + return (uint8_t*) c->write_data+i; } static void format_esd2native(int format, struct pa_sample_spec *ss) { @@ -238,20 +252,20 @@ static int esd_proto_connect(struct connection *c, esd_proto_t request, const vo if (!c->authorized) { if (memcmp(data, c->protocol->esd_key, ESD_KEY_LEN) != 0) { - fprintf(stderr, __FILE__": kicked client with invalid authorization key.\n"); + pa_log(__FILE__": kicked client with invalid authorization key.\n"); return -1; } c->authorized = 1; } - ekey = *(uint32_t*)(data+ESD_KEY_LEN); + ekey = *(uint32_t*)((uint8_t*) data+ESD_KEY_LEN); if (ekey == ESD_ENDIAN_KEY) c->swap_byte_order = 0; else if (ekey == ESD_SWAP_ENDIAN_KEY) c->swap_byte_order = 1; else { - fprintf(stderr, __FILE__": client sent invalid endian key\n"); + pa_log(__FILE__": client sent invalid endian key\n"); return -1; } @@ -279,25 +293,25 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons return -1; if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) { - fprintf(stderr, __FILE__": No output sink\n"); + pa_log(__FILE__": No output sink\n"); return -1; } - strncpy(name, data + sizeof(int)*2, sizeof(name)); + strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; - pa_client_rename(c->client, name); + pa_client_set_name(c->client, name); assert(!c->input_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*PLAYBACK_BUFFER_SECONDS); - c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS); + c->input_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), l/2, l/PLAYBACK_BUFFER_FRAGMENTS, c->protocol->core->memblock_stat); assert(c->input_memblockq); pa_iochannel_socket_set_rcvbuf(c->io, l/PLAYBACK_BUFFER_FRAGMENTS*2); c->playback.fragment_size = l/10; assert(!c->sink_input); - c->sink_input = pa_sink_input_new(sink, name, &ss); + c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1); assert(c->sink_input); c->sink_input->owner = c->protocol->module; @@ -347,26 +361,27 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co return -1; } - strncpy(name, data + sizeof(int)*2, sizeof(name)); + strncpy(name, (char*) data + sizeof(int)*2, sizeof(name)); name[sizeof(name)-1] = 0; - pa_client_rename(c->client, name); + pa_client_set_name(c->client, name); assert(!c->output_memblockq); l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS); - c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0); + c->output_memblockq = pa_memblockq_new(l, 0, pa_frame_size(&ss), 0, 0, c->protocol->core->memblock_stat); assert(c->output_memblockq); pa_iochannel_socket_set_sndbuf(c->io, l/RECORD_BUFFER_FRAGMENTS*2); assert(!c->source_output); - c->source_output = pa_source_output_new(source, name, &ss); + c->source_output = pa_source_output_new(source, name, &ss, -1); assert(c->source_output); 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; @@ -384,7 +399,7 @@ static int esd_proto_get_latency(struct connection *c, esd_proto_t request, cons if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) latency = 0; else { - float usec = pa_sink_get_latency(sink); + double usec = pa_sink_get_latency(sink); usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */ latency = (int) ((usec*44100)/1000000); } @@ -415,7 +430,7 @@ static int esd_proto_server_info(struct connection *c, esd_proto_t request, cons } static int esd_proto_all_info(struct connection *c, esd_proto_t request, const void *data, size_t length) { - void *response; + uint8_t *response; size_t t, k, s; struct connection *conn; size_t index = PA_IDXSET_INVALID; @@ -427,7 +442,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v k = sizeof(int)*5+ESD_NAME_MAX; s = sizeof(int)*6+ESD_NAME_MAX; - nsamples = c->protocol->core->scache_idxset ? pa_idxset_ncontents(c->protocol->core->scache_idxset) : 0; + nsamples = c->protocol->core->scache ? pa_idxset_ncontents(c->protocol->core->scache) : 0; response = connection_write(c, (t = s*(nsamples+1) + k*(c->protocol->n_player+1))); assert(k); @@ -451,7 +466,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* name */ assert(conn->client); - strncpy(response, conn->client->name, ESD_NAME_MAX); + strncpy((char*) response, conn->client->name, ESD_NAME_MAX); response += ESD_NAME_MAX; /* rate */ @@ -482,7 +497,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v struct pa_scache_entry *ce; index = PA_IDXSET_INVALID; - for (ce = pa_idxset_first(c->protocol->core->scache_idxset, &index); ce; ce = pa_idxset_next(c->protocol->core->scache_idxset, &index)) { + for (ce = pa_idxset_first(c->protocol->core->scache, &index); ce; ce = pa_idxset_next(c->protocol->core->scache, &index)) { assert(t >= s*2); /* id */ @@ -491,9 +506,9 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v /* name */ if (strncmp(ce->name, SCACHE_PREFIX, sizeof(SCACHE_PREFIX)-1) == 0) - strncpy(response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); + strncpy((char*) response, ce->name+sizeof(SCACHE_PREFIX)-1, ESD_NAME_MAX); else - snprintf(response, ESD_NAME_MAX, "native.%s", ce->name); + snprintf((char*) response, ESD_NAME_MAX, "native.%s", ce->name); response += ESD_NAME_MAX; /* rate */ @@ -570,20 +585,20 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con return -1; strcpy(name, SCACHE_PREFIX); - strncpy(name+sizeof(SCACHE_PREFIX)-1, data+3*sizeof(int), ESD_NAME_MAX); + strncpy(name+sizeof(SCACHE_PREFIX)-1, (char*) data+3*sizeof(int), ESD_NAME_MAX); name[sizeof(name)-1] = 0; - assert(!c->scache_memchunk.memblock); - c->scache_memchunk.memblock = pa_memblock_new(sc_length); - 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); + 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, &index); + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &index); ok = connection_write(c, sizeof(int)); assert(ok); @@ -645,6 +660,15 @@ 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, esd_proto_t request, const void *data, size_t length) { + int *ok; + ok = connection_write(c, sizeof(int)*2); + assert(ok); + ok[0] = 1; + ok[1] = 1; + return 0; +} + /*** client callbacks ***/ static void client_kill_cb(struct pa_client *c) { @@ -657,12 +681,14 @@ static void client_kill_cb(struct pa_client *c) { static int do_read(struct connection *c) { assert(c && c->io); +/* pa_log("READ\n"); */ + if (c->state == ESD_NEXT_REQUEST) { ssize_t r; assert(c->read_data_length < sizeof(c->request)); - if ((r = pa_iochannel_read(c->io, ((void*) &c->request) + c->read_data_length, sizeof(c->request) - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + 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(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -673,14 +699,16 @@ static int do_read(struct connection *c) { c->request = swap_endian_32(c->request); if (c->request < ESD_PROTO_CONNECT || c->request > ESD_PROTO_MAX) { - fprintf(stderr, "protocol-esound.c: recieved invalid request.\n"); + pa_log(__FILE__": recieved invalid request.\n"); return -1; } handler = proto_map+c->request; +/* pa_log(__FILE__": executing request #%u\n", c->request); */ + if (!handler->proc) { - fprintf(stderr, "protocol-sound.c: recieved unimplemented request.\n"); + pa_log(__FILE__": recieved unimplemented request #%u.\n", c->request); return -1; } @@ -708,8 +736,8 @@ 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, c->read_data + c->read_data_length, handler->data_length - c->read_data_length)) <= 0) { - fprintf(stderr, "protocol-esound.c: read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + 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(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } @@ -726,29 +754,29 @@ static int do_read(struct connection *c) { } 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); + assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); - if ((r = pa_iochannel_read(c->io, c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + 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(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } - c->scache_memchunk.index += r; - assert(c->scache_memchunk.index <= c->scache_memchunk.length); + c->scache.memchunk.index += r; + assert(c->scache.memchunk.index <= c->scache.memchunk.length); - if (c->scache_memchunk.index == c->scache_memchunk.length) { + if (c->scache.memchunk.index == c->scache.memchunk.length) { uint32_t index; int *ok; - c->scache_memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); + c->scache.memchunk.index = 0; + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &index); - pa_memblock_unref(c->scache_memchunk.memblock); - c->scache_memchunk.memblock = NULL; - c->scache_memchunk.index = c->scache_memchunk.length = 0; + 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; + pa_xfree(c->scache.name); + c->scache.name = NULL; c->state = ESD_NEXT_REQUEST; @@ -764,6 +792,8 @@ static int do_read(struct connection *c) { assert(c->input_memblockq); +/* pa_log("STREAMING_DATA\n"); */ + if (!(l = pa_memblockq_missing(c->input_memblockq))) return 0; @@ -778,15 +808,17 @@ 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->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, c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { - fprintf(stderr, __FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); + if ((r = pa_iochannel_read(c->io, (uint8_t*) c->playback.current_memblock->data+c->playback.memblock_index, l)) <= 0) { + pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno)); return -1; } + +/* pa_log(__FILE__": read %u\n", r); */ chunk.memblock = c->playback.current_memblock; chunk.index = c->playback.memblock_index; @@ -807,12 +839,14 @@ static int do_read(struct connection *c) { static int do_write(struct connection *c) { assert(c && c->io); +/* pa_log("WRITE\n"); */ + if (c->write_data_length) { ssize_t r; assert(c->write_data_index < c->write_data_length); - if ((r = pa_iochannel_write(c->io, c->write_data+c->write_data_index, c->write_data_length-c->write_data_index)) < 0) { - fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno)); + 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() failed: %s\n", strerror(errno)); return -1; } @@ -829,13 +863,13 @@ static int do_write(struct connection *c) { assert(chunk.memblock && chunk.length); - if ((r = pa_iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) { + if ((r = pa_iochannel_write(c->io, (uint8_t*) chunk.memblock->data+chunk.index, chunk.length)) < 0) { pa_memblock_unref(chunk.memblock); - fprintf(stderr, __FILE__": write(): %s\n", strerror(errno)); + pa_log(__FILE__": write(): %s\n", strerror(errno)); return -1; } - pa_memblockq_drop(c->output_memblockq, r); + pa_memblockq_drop(c->output_memblockq, &chunk, r); pa_memblock_unref(chunk.memblock); } @@ -848,27 +882,40 @@ static void do_work(struct connection *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 (pa_iochannel_is_hungup(c->io)) - goto fail; - - if (pa_iochannel_is_writable(c->io)) - if (do_write(c) < 0) - goto fail; +/* pa_log("DOWORK\n"); */ + + if (c->dead || !c->io) + return; if (pa_iochannel_is_readable(c->io)) if (do_read(c) < 0) goto fail; - + + if (pa_iochannel_is_writable(c->io)) + if (do_write(c) < 0) + goto fail; + return; fail: - connection_free(c); + + if (c->state == ESD_STREAMING_DATA && c->sink_input) { + c->dead = 1; + pa_memblockq_prebuf_disable(c->input_memblockq); + + pa_iochannel_free(c->io); + c->io = NULL; + + } else + connection_free(c); } static void io_callback(struct pa_iochannel*io, void *userdata) { struct connection *c = userdata; assert(io && c && c->io == io); +/* pa_log("IO\n"); */ + do_work(c); } @@ -878,6 +925,8 @@ static void defer_callback(struct pa_mainloop_api*a, struct pa_defer_event *e, v struct connection *c = userdata; assert(a && c && c->defer_event == e); +/* pa_log("DEFER\n"); */ + do_work(c); } @@ -888,21 +937,32 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk assert(i && i->userdata && chunk); c = i->userdata; - if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) + 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(struct pa_sink_input *i, size_t length) { +static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length) { struct connection*c = i->userdata; assert(i && c && length); - pa_memblockq_drop(c->input_memblockq, length); +/* pa_log("DROP\n"); */ + + 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); - c->protocol->core->mainloop->defer_enable(c->defer_event, 1); + + 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(struct pa_sink_input *i) { @@ -910,8 +970,7 @@ static void sink_input_kill_cb(struct pa_sink_input *i) { connection_free((struct connection *) i->userdata); } - -static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) { +static pa_usec_t sink_input_get_latency_cb(struct 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); @@ -927,7 +986,9 @@ static void source_output_push_cb(struct pa_source_output *o, const struct pa_me /* do something */ 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); + + if (!c->dead) + c->protocol->core->mainloop->defer_enable(c->defer_event, 1); } static void source_output_kill_cb(struct pa_source_output *o) { @@ -935,6 +996,12 @@ static void source_output_kill_cb(struct pa_source_output *o) { connection_free((struct connection *) o->userdata); } +static pa_usec_t source_output_get_latency_cb(struct 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 on_connection(struct pa_socket_server*s, struct pa_iochannel *io, void *userdata) { @@ -957,6 +1024,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo c->authorized = c->protocol->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); @@ -977,9 +1045,9 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo 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->scache.memchunk.length = c->scache.memchunk.index = 0; + c->scache.memchunk.memblock = NULL; + c->scache.name = NULL; c->defer_event = c->protocol->core->mainloop->defer_new(c->protocol->core->mainloop, defer_callback, c); assert(c->defer_event); @@ -992,17 +1060,23 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo struct pa_protocol_esound* pa_protocol_esound_new(struct pa_core*core, struct pa_socket_server *server, struct pa_module *m, struct pa_modargs *ma) { struct pa_protocol_esound *p; + int public; assert(core && server && ma); p = pa_xmalloc(sizeof(struct pa_protocol_esound)); + if (pa_modargs_get_value_boolean(ma, "public", &public) < 0) { + pa_log(__FILE__": public= expects a boolean argument.\n"); + 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 = 0; + p->public = public; p->server = server; pa_socket_server_set_callback(p->server, on_connection, p); p->core = core;