From e205b25d65ccb380fa158711e24d55b6de5d9bc1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 16 Feb 2006 19:19:58 +0000 Subject: Reorganised the source tree. We now have src/ with a couple of subdirs: * daemon/ - Contains the files specific to the polypaudio daemon. * modules/ - All loadable modules. * polyp/ - Files that are part of the public, application interface or are only used in libpolyp. * polypcore/ - All other shared files. * tests/ - Test programs. * utils/ - Utility programs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@487 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 688 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 src/modules/module-tunnel.c (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c new file mode 100644 index 00000000..5ee10fda --- /dev/null +++ b/src/modules/module-tunnel.c @@ -0,0 +1,688 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio 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. + + polypaudio 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 polypaudio; 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 + +#ifdef TUNNEL_SINK +#include "module-tunnel-sink-symdef.h" +PA_MODULE_DESCRIPTION("Tunnel module for sinks") +PA_MODULE_USAGE("server=
sink= cookie= format= channels= rate= sink_name=") +#else +#include "module-tunnel-source-symdef.h" +PA_MODULE_DESCRIPTION("Tunnel module for sources") +PA_MODULE_USAGE("server=
source= cookie= format= channels= rate= source_name=") +#endif + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_VERSION(PACKAGE_VERSION) + +#define DEFAULT_SINK_NAME "tunnel" +#define DEFAULT_SOURCE_NAME "tunnel" + +#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) +#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) +#define DEFAULT_MINREQ 512 +#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) +#define DEFAULT_FRAGSIZE 1024 + +#define DEFAULT_TIMEOUT 5 + +#define LATENCY_INTERVAL 10 + +static const char* const valid_modargs[] = { + "server", + "cookie", + "format", + "channels", + "rate", +#ifdef TUNNEL_SINK + "sink_name", + "sink", +#else + "source_name", + "source", +#endif + NULL, +}; + +static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); + +#ifdef TUNNEL_SINK +static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +#endif + +static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +#ifdef TUNNEL_SINK + [PA_COMMAND_REQUEST] = command_request, +#endif + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed +}; + +struct userdata { + pa_socket_client *client; + pa_pstream *pstream; + pa_pdispatch *pdispatch; + + char *server_name; +#ifdef TUNNEL_SINK + char *sink_name; + pa_sink *sink; + uint32_t requested_bytes; +#else + char *source_name; + pa_source *source; +#endif + + pa_module *module; + pa_core *core; + + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + + uint32_t ctag; + uint32_t device_index; + uint32_t channel; + + pa_usec_t host_latency; + + pa_time_event *time_event; + + int auth_cookie_in_property; +}; + +static void close_stuff(struct userdata *u) { + assert(u); + + if (u->pstream) { + pa_pstream_close(u->pstream); + pa_pstream_unref(u->pstream); + u->pstream = NULL; + } + + if (u->pdispatch) { + pa_pdispatch_unref(u->pdispatch); + u->pdispatch = NULL; + } + + if (u->client) { + pa_socket_client_unref(u->client); + u->client = NULL; + } + +#ifdef TUNNEL_SINK + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } +#else + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } +#endif + + if (u->time_event) { + u->core->mainloop->time_free(u->time_event); + u->time_event = NULL; + } +} + +static void die(struct userdata *u) { + assert(u); + close_stuff(u); + pa_module_unload_request(u->module); +} + +static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && t && u && u->pdispatch == pd); + + pa_log(__FILE__": stream killed\n"); + die(u); +} + +#ifdef TUNNEL_SINK +static void send_prebuf_request(struct userdata *u) { + pa_tagstruct *t; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, u->ctag++); + pa_tagstruct_putu32(t, u->channel); + pa_pstream_send_tagstruct(u->pstream, t); +} + +static void send_bytes(struct userdata *u) { + assert(u); + + if (!u->pstream) + return; + + while (u->requested_bytes > 0) { + pa_memchunk chunk; + if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { + + + if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) + send_prebuf_request(u); + + return; + } + + pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); + pa_memblock_unref(chunk.memblock); + + if (chunk.length > u->requested_bytes) + u->requested_bytes = 0; + else + u->requested_bytes -= chunk.length; + } +} + +static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t bytes, channel; + assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); + + if (pa_tagstruct_getu32(t, &channel) < 0 || + pa_tagstruct_getu32(t, &bytes) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid protocol reply\n"); + die(u); + return; + } + + if (channel != u->channel) { + pa_log(__FILE__": recieved data for invalid channel\n"); + die(u); + return; + } + + u->requested_bytes += bytes; + send_bytes(u); +} + +#endif + +static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; + int playing; + uint32_t queue_length; + uint64_t counter; + struct timeval local, remote, now; + assert(pd && u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to get latency.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &sink_usec) < 0 || + pa_tagstruct_get_usec(t, &source_usec) < 0 || + pa_tagstruct_get_boolean(t, &playing) < 0 || + pa_tagstruct_getu32(t, &queue_length) < 0 || + pa_tagstruct_get_timeval(t, &local) < 0 || + pa_tagstruct_get_timeval(t, &remote) < 0 || + pa_tagstruct_getu64(t, &counter) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + pa_gettimeofday(&now); + + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { + /* local and remote seem to have synchronized clocks */ +#ifdef TUNNEL_SINK + transport_usec = pa_timeval_diff(&remote, &local); +#else + transport_usec = pa_timeval_diff(&now, &remote); +#endif + } else + transport_usec = pa_timeval_diff(&now, &local)/2; + +#ifdef TUNNEL_SINK + u->host_latency = sink_usec + transport_usec; +#else + u->host_latency = source_usec + transport_usec; + if (u->host_latency > sink_usec) + u->host_latency -= sink_usec; + else + u->host_latency = 0; +#endif + +/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ +} + +static void request_latency(struct userdata *u) { + pa_tagstruct *t; + struct timeval now; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); +#else + pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); +#endif + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->channel); + + pa_gettimeofday(&now); + pa_tagstruct_put_timeval(t, &now); + pa_tagstruct_putu64(t, 0); + + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); +} + +static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to create stream.\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } + + if (pa_tagstruct_getu32(t, &u->channel) < 0 || + pa_tagstruct_getu32(t, &u->device_index) < 0 || +#ifdef TUNNEL_SINK + pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || +#endif + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply.\n"); + die(u); + return; + } + + request_latency(u); +#ifdef TUNNEL_SINK + send_bytes(u); +#endif +} + +static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_tagstruct *reply; + char name[256], un[128], hn[128]; + assert(pd && u && u->pdispatch == pd); + + if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to authenticate\n"); + else + pa_log(__FILE__": protocol error.\n"); + die(u); + return; + } +#ifdef TUNNEL_SINK + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->sink->name); +#else + snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", + pa_get_host_name(hn, sizeof(hn)), + pa_get_user_name(un, sizeof(un)), + u->source->name); +#endif + + reply = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_pstream_send_tagstruct(u->pstream, reply); + /* We ignore the server's reply here */ + + reply = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->sink_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); + pa_tagstruct_putu32(reply, DEFAULT_PREBUF); + pa_tagstruct_putu32(reply, DEFAULT_MINREQ); + pa_tagstruct_putu32(reply, PA_VOLUME_NORM); +#else + pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(reply, tag = u->ctag++); + pa_tagstruct_puts(reply, name); + pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); + pa_tagstruct_putu32(reply, PA_INVALID_INDEX); + pa_tagstruct_puts(reply, u->source_name); + pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); +#endif + + pa_pstream_send_tagstruct(u->pstream, reply); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); +} + +static void pstream_die_callback(pa_pstream *p, void *userdata) { + struct userdata *u = userdata; + assert(p && u); + + pa_log(__FILE__": stream died.\n"); + die(u); +} + + +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { + struct userdata *u = userdata; + assert(p && packet && u); + + if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { + pa_log(__FILE__": invalid packet\n"); + die(u); + } +} + +#ifndef TUNNEL_SINK +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { + struct userdata *u = userdata; + assert(p && chunk && u); + + if (channel != u->channel) { + pa_log(__FILE__": recieved memory block on bad channel.\n"); + die(u); + return; + } + + pa_source_post(u->source, chunk); +} +#endif + +static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { + struct userdata *u = userdata; + pa_tagstruct *t; + uint32_t tag; + assert(sc && u && u->client == sc); + + pa_socket_client_unref(u->client); + u->client = NULL; + + if (!io) { + pa_log(__FILE__": connection failed.\n"); + pa_module_unload_request(u->module); + return; + } + + u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); + u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); + + pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); + pa_pstream_set_recieve_packet_callback(u->pstream, pstream_packet_callback, u); +#ifndef TUNNEL_SINK + pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); +#endif + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_AUTH); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); + +} + +#ifdef TUNNEL_SINK +static void sink_notify(pa_sink*sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + send_bytes(u); +} + +static pa_usec_t sink_get_latency(pa_sink *sink) { + struct userdata *u; + uint32_t l; + pa_usec_t usec = 0; + assert(sink && sink->userdata); + u = sink->userdata; + + l = DEFAULT_TLENGTH; + + if (l > u->requested_bytes) { + l -= u->requested_bytes; + usec += pa_bytes_to_usec(l, &u->sink->sample_spec); + } + + usec += u->host_latency; + + return usec; +} +#else +static pa_usec_t source_get_latency(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return u->host_latency; +} +#endif + +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + assert(m && e && u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + +static int load_key(struct userdata *u, const char*fn) { + assert(u); + + u->auth_cookie_in_property = 0; + + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { + pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + u->auth_cookie_in_property = 1; + return 0; + } + + if (!fn) + fn = PA_NATIVE_COOKIE_FILE; + + if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) + return -1; + + pa_log_debug(__FILE__": loading cookie from disk.\n"); + + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) + u->auth_cookie_in_property = 1; + + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + pa_modargs *ma = NULL; + struct userdata *u = NULL; + pa_sample_spec ss; + struct timeval ntv; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments\n"); + goto fail; + } + + u = pa_xmalloc(sizeof(struct userdata)); + m->userdata = u; + u->module = m; + u->core = c; + u->client = NULL; + u->pdispatch = NULL; + u->pstream = NULL; + u->server_name = NULL; +#ifdef TUNNEL_SINK + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; + u->sink = NULL; + u->requested_bytes = 0; +#else + u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; + u->source = NULL; +#endif + u->ctag = 1; + u->device_index = u->channel = PA_INVALID_INDEX; + u->host_latency = 0; + u->auth_cookie_in_property = 0; + u->time_event = NULL; + + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) + goto fail; + + if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { + pa_log(__FILE__": no server specified.\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": invalid sample format specification\n"); + goto fail; + } + + if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); + goto fail; + } + + if (!u->client) + goto fail; + + pa_socket_client_set_callback(u->client, on_connection, u); + +#ifdef TUNNEL_SINK + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create sink.\n"); + goto fail; + } + + u->sink->notify = sink_notify; + u->sink->get_latency = sink_get_latency; + u->sink->userdata = u; + u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + + pa_sink_set_owner(u->sink, m); +#else + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + pa_log(__FILE__": failed to create source.\n"); + goto fail; + } + + u->source->get_latency = source_get_latency; + u->source->userdata = u; + u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); + + pa_source_set_owner(u->source, m); +#endif + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(c, m); + + if (ma) + pa_modargs_free(ma); + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata* u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + close_stuff(u); + + if (u->auth_cookie_in_property) + pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + +#ifdef TUNNEL_SINK + pa_xfree(u->sink_name); +#else + pa_xfree(u->source_name); +#endif + pa_xfree(u->server_name); + + pa_xfree(u); +} + + -- cgit From 5ccf4145bcf1760d30962c32f0f4749047c6cae8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 23:13:27 +0000 Subject: * rename polypcore/subscribe.[ch] to polypcore/core-subscribe.[ch] to avoid confusion with polyp/subscribe.[ch] * same for scache.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@496 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ee10fda..61b9bb3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include -- cgit From 304449002cbc84fdcf235b5dfaec891278dd7085 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 04:05:16 +0000 Subject: 1) Add flexible seeking support (including absolute) for memory block queues and playback streams 2) Add support to synchronize multiple playback streams 3) add two tests for 1) and 2) 4) s/PA_ERROR/PA_ERR/ 5) s/PA_ERROR_OK/PA_OK/ 6) update simple API to deal properly with new peek/drop recording API 7) add beginnings of proper validity checking on API calls in client libs (needs to be extended) 8) report playback buffer overflows/underflows to the client 9) move client side recording mcalign stuff into the memblockq 10) create typedefs for a bunch of API callback prototypes 11) simplify handling of HUP poll() events Yes, i know, it's usually better to commit a lot of small patches instead of a single big one. In this case however, this would have contradicted the other rule: never commit broken or incomplete stuff. *** This stuff needs a lot of additional testing! *** git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@511 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 61b9bb3b..67236588 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -214,7 +214,7 @@ static void send_bytes(struct userdata *u) { return; } - pa_pstream_send_memblock(u->pstream, u->channel, 0, &chunk); + pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); pa_memblock_unref(chunk.memblock); if (chunk.length > u->requested_bytes) @@ -442,7 +442,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, uint32_t delta, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; assert(p && chunk && u); -- cgit From 4566d56e31c58211763ddbb4669c7f04152669d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 16:01:53 +0000 Subject: * Make typdefs for the pa_context callback prototypes * s/pa_context_notify_cb/pa_context_notify_cb_t/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@521 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 67236588..3ecca745 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -94,7 +94,7 @@ static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t t static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif -static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, #endif -- cgit From 71b3bff6816b857a6a9613cc45b06f0b9e5a65e1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Feb 2006 22:41:02 +0000 Subject: * modify pa_context_exit_daemon() to return a pa_operation object * add callback prototypes to all introspection functions in client lib * add proper validity checking and error handling to all functions in the client lib * other minor cleanups * todo update git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@531 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 3ecca745..136702fc 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -94,7 +94,7 @@ static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t t static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif -static const pa_pdispatch_callback_t command_table[PA_COMMAND_MAX] = { +static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, #endif -- cgit From 4a64b0d1167e980d81b798d813f35209895f0674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 02:27:19 +0000 Subject: change pa_log() and friends to not require a trailing \n on all logged strings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@574 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 48 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 136702fc..df9c51fb 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -182,7 +182,7 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma struct userdata *u = userdata; assert(pd && t && u && u->pdispatch == pd); - pa_log(__FILE__": stream killed\n"); + pa_log(__FILE__": stream killed"); die(u); } @@ -232,13 +232,13 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply\n"); + pa_log(__FILE__": invalid protocol reply"); die(u); return; } if (channel != u->channel) { - pa_log(__FILE__": recieved data for invalid channel\n"); + pa_log(__FILE__": recieved data for invalid channel"); die(u); return; } @@ -260,9 +260,9 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get latency.\n"); + pa_log(__FILE__": failed to get latency."); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -276,7 +276,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_getu64(t, &counter) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); + pa_log(__FILE__": invalid reply."); die(u); return; } @@ -303,7 +303,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log(__FILE__": estimated host latency: %0.0f usec\n", (double) u->host_latency); */ +/* pa_log(__FILE__": estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -335,9 +335,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to create stream.\n"); + pa_log(__FILE__": failed to create stream."); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -348,7 +348,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply.\n"); + pa_log(__FILE__": invalid reply."); die(u); return; } @@ -367,9 +367,9 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to authenticate\n"); + pa_log(__FILE__": failed to authenticate"); else - pa_log(__FILE__": protocol error.\n"); + pa_log(__FILE__": protocol error."); die(u); return; } @@ -426,7 +426,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; assert(p && u); - pa_log(__FILE__": stream died.\n"); + pa_log(__FILE__": stream died."); die(u); } @@ -436,7 +436,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *user assert(p && packet && u); if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { - pa_log(__FILE__": invalid packet\n"); + pa_log(__FILE__": invalid packet"); die(u); } } @@ -447,7 +447,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o assert(p && chunk && u); if (channel != u->channel) { - pa_log(__FILE__": recieved memory block on bad channel.\n"); + pa_log(__FILE__": recieved memory block on bad channel."); die(u); return; } @@ -466,7 +466,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed.\n"); + pa_log(__FILE__": connection failed."); pa_module_unload_request(u->module); return; } @@ -544,7 +544,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie.\n"); + pa_log_debug(__FILE__": using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -556,7 +556,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk.\n"); + pa_log_debug(__FILE__": loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -572,7 +572,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments"); goto fail; } @@ -602,18 +602,18 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log(__FILE__": no server specified.\n"); + pa_log(__FILE__": no server specified."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": invalid sample format specification\n"); + pa_log(__FILE__": invalid sample format specification"); goto fail; } if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server '%s'\n", u->server_name); + pa_log(__FILE__": failed to connect to server '%s'", u->server_name); goto fail; } @@ -624,7 +624,7 @@ int pa__init(pa_core *c, pa_module*m) { #ifdef TUNNEL_SINK if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create sink.\n"); + pa_log(__FILE__": failed to create sink."); goto fail; } @@ -636,7 +636,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { - pa_log(__FILE__": failed to create source.\n"); + pa_log(__FILE__": failed to create source."); goto fail; } -- cgit From 3f264b2c4acfaaf8dd9c6b05526708a1d7648db0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 24 Feb 2006 15:12:42 +0000 Subject: add support for authentication using SCM_CREDENTIALS git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@596 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index df9c51fb..70bded6c 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -431,11 +431,11 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void*creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); - if (pa_pdispatch_run(u->pdispatch, packet, u) < 0) { + if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { pa_log(__FILE__": invalid packet"); die(u); } -- cgit From dcd202f8eb94ef14981f2b80c7f28a5936ba35a2 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 4 Mar 2006 21:30:29 +0000 Subject: Update module-tunnel to the new protocol. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@625 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 70bded6c..ff1113cc 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -122,6 +124,7 @@ struct userdata { uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; + uint32_t version; uint32_t ctag; uint32_t device_index; uint32_t channel; @@ -254,7 +257,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; int playing; uint32_t queue_length; - uint64_t counter; + int64_t write_index, read_index; struct timeval local, remote, now; assert(pd && u); @@ -274,7 +277,8 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_getu32(t, &queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_getu64(t, &counter) < 0 || + pa_tagstruct_gets64(t, &write_index) < 0 || + pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { pa_log(__FILE__": invalid reply."); die(u); @@ -323,7 +327,6 @@ static void request_latency(struct userdata *u) { pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); - pa_tagstruct_putu64(t, 0); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); @@ -363,9 +366,14 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t struct userdata *u = userdata; pa_tagstruct *reply; char name[256], un[128], hn[128]; +#ifdef TUNNEL_SINK + pa_cvolume volume; +#endif assert(pd && u && u->pdispatch == pd); - if (command != PA_COMMAND_REPLY || !pa_tagstruct_eof(t)) { + if (command != PA_COMMAND_REPLY || + pa_tagstruct_getu32(t, &u->version) < 0 || + !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) pa_log(__FILE__": failed to authenticate"); else @@ -373,6 +381,14 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t die(u); return; } + + /* Minimum supported protocol version */ + if (u->version < 8) { + pa_log(__FILE__": incompatible protocol version"); + die(u); + return; + } + #ifdef TUNNEL_SINK snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", pa_get_host_name(hn, sizeof(hn)), @@ -398,6 +414,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); + pa_tagstruct_put_channel_map(reply, &u->sink->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); @@ -405,12 +422,15 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); pa_tagstruct_putu32(reply, DEFAULT_PREBUF); pa_tagstruct_putu32(reply, DEFAULT_MINREQ); - pa_tagstruct_putu32(reply, PA_VOLUME_NORM); + pa_tagstruct_putu32(reply, 0); + pa_cvolume_reset(&volume, u->sink->sample_spec.channels); + pa_tagstruct_put_cvolume(reply, &volume); #else pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); + pa_tagstruct_put_channel_map(reply, &u->source->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); @@ -483,6 +503,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); -- cgit From 738734244dc6b28d404953e9133f49c518f6a4e0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 5 Mar 2006 20:18:04 +0000 Subject: Volume support in tunnel module. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@629 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 261 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index ff1113cc..aa6b69f5 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -91,6 +91,7 @@ static const char* const valid_modargs[] = { }; static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -101,7 +102,8 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_REQUEST] = command_request, #endif [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed + [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { @@ -189,6 +191,35 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma die(u); } +static void request_info(struct userdata *u); + +static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_subscription_event_type_t e; + uint32_t idx; + + assert(pd && t && u); + assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid protocol reply"); + die(u); + return; + } + +#ifdef TUNNEL_SINK + if (e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; +#else + if (e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; +#endif + + request_info(u); +} + #ifdef TUNNEL_SINK static void send_prebuf_request(struct userdata *u) { pa_tagstruct *t; @@ -332,6 +363,115 @@ static void request_latency(struct userdata *u) { pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); } +static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t index, owner_module, monitor_source; + pa_usec_t latency; + const char *name, *description, *monitor_source_name, *driver; + int mute; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_cvolume volume; + assert(pd && u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log(__FILE__": failed to get info."); + else + pa_log(__FILE__": protocol error."); + die(u); + return; + } + + if (pa_tagstruct_getu32(t, &index) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || + pa_tagstruct_get_channel_map(t, &channel_map) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_source) < 0 || + pa_tagstruct_gets(t, &monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + !pa_tagstruct_eof(t)) { + pa_log(__FILE__": invalid reply."); + die(u); + return; + } + +#ifdef TUNNEL_SINK + assert(u->sink); + if ((!!mute == !!u->sink->hw_muted) && + pa_cvolume_equal(&volume, &u->sink->hw_volume)) + return; +#else + assert(u->source); + if ((!!mute == !!u->source->hw_muted) && + pa_cvolume_equal(&volume, &u->source->hw_volume)) + return; +#endif + +#ifdef TUNNEL_SINK + memcpy(&u->sink->hw_volume, &volume, sizeof(pa_cvolume)); + u->sink->hw_muted = !!mute; + + pa_subscription_post(u->sink->core, + PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, + u->sink->index); +#else + memcpy(&u->source->hw_volume, &volume, sizeof(pa_cvolume)); + u->source->hw_muted = !!mute; + + pa_subscription_post(u->source->core, + PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, + u->source->index); +#endif +} + +static void request_info(struct userdata *u) { + pa_tagstruct *t; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); +#else + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); +#endif + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); +#ifdef TUNNEL_SINK + pa_tagstruct_puts(t, u->sink_name); +#else + pa_tagstruct_puts(t, u->source_name); +#endif + + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u); +} + +static void start_subscribe(struct userdata *u) { + pa_tagstruct *t; + uint32_t tag; + assert(u); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); + pa_tagstruct_putu32(t, tag = u->ctag++); + +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK); +#else + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SOURCE); +#endif + + pa_pstream_send_tagstruct(u->pstream, t); +} + static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; assert(pd && u && u->pdispatch == pd); @@ -356,6 +496,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN return; } + start_subscribe(u); + request_info(u); + request_latency(u); #ifdef TUNNEL_SINK send_bytes(u); @@ -537,6 +680,60 @@ static pa_usec_t sink_get_latency(pa_sink *sink) { return usec; } + +static int sink_get_hw_volume(pa_sink *sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + return 0; +} + +static int sink_set_hw_volume(pa_sink *sink) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(sink && sink->userdata); + u = sink->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_tagstruct_put_cvolume(t, &sink->hw_volume); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} + +static int sink_get_hw_mute(pa_sink *sink) { + struct userdata *u; + assert(sink && sink->userdata); + u = sink->userdata; + + return 0; +} + +static int sink_set_hw_mute(pa_sink *sink) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(sink && sink->userdata); + u = sink->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_MUTE); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_tagstruct_put_boolean(t, !!sink->hw_muted); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} #else static pa_usec_t source_get_latency(pa_source *source) { struct userdata *u; @@ -545,6 +742,60 @@ static pa_usec_t source_get_latency(pa_source *source) { return u->host_latency; } + +static int source_get_hw_volume(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return 0; +} + +static int source_set_hw_volume(pa_source *source) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(source && source->userdata); + u = source->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_tagstruct_put_cvolume(t, &source->hw_volume); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} + +static int source_get_hw_mute(pa_source *source) { + struct userdata *u; + assert(source && source->userdata); + u = source->userdata; + + return 0; +} + +static int source_set_hw_mute(pa_source *source) { + struct userdata *u; + pa_tagstruct *t; + uint32_t tag; + assert(source && source->userdata); + u = source->userdata; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_MUTE); + pa_tagstruct_putu32(t, tag = u->ctag++); + + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_tagstruct_put_boolean(t, !!source->hw_muted); + pa_pstream_send_tagstruct(u->pstream, t); + + return 0; +} #endif static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { @@ -651,6 +902,10 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->notify = sink_notify; u->sink->get_latency = sink_get_latency; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->get_hw_mute = sink_get_hw_mute; + u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); @@ -662,6 +917,10 @@ int pa__init(pa_core *c, pa_module*m) { } u->source->get_latency = source_get_latency; + u->source->get_hw_volume = source_get_hw_volume; + u->source->set_hw_volume = source_set_hw_volume; + u->source->get_hw_mute = source_get_hw_mute; + u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); -- cgit From e872c751e1bde9dc996d967e32c457d9c8f0f0fc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 6 Apr 2006 23:28:56 +0000 Subject: s/index/idx/, to avoid gcc warning git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@644 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index aa6b69f5..8f5e66e6 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -365,7 +365,7 @@ static void request_latency(struct userdata *u) { static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - uint32_t index, owner_module, monitor_source; + uint32_t idx, owner_module, monitor_source; pa_usec_t latency; const char *name, *description, *monitor_source_name, *driver; int mute; @@ -383,7 +383,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ return; } - if (pa_tagstruct_getu32(t, &index) < 0 || + if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || pa_tagstruct_gets(t, &description) < 0 || pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || -- cgit From 7e8d46e2bbb59876e18d84d701bf499938115e37 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 13 Apr 2006 18:55:55 +0000 Subject: unbreak module-tunnel git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@707 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 8f5e66e6..70cc950c 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -240,7 +240,6 @@ static void send_bytes(struct userdata *u) { while (u->requested_bytes > 0) { pa_memchunk chunk; if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) send_prebuf_request(u); @@ -285,9 +284,8 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_usec_t buffer_usec, sink_usec, source_usec, transport_usec; + pa_usec_t sink_usec, source_usec, transport_usec; int playing; - uint32_t queue_length; int64_t write_index, read_index; struct timeval local, remote, now; assert(pd && u); @@ -301,17 +299,15 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G return; } - if (pa_tagstruct_get_usec(t, &buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &sink_usec) < 0 || + if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_get_usec(t, &source_usec) < 0 || pa_tagstruct_get_boolean(t, &playing) < 0 || - pa_tagstruct_getu32(t, &queue_length) < 0 || pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (latency)"); die(u); return; } @@ -369,6 +365,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_usec_t latency; const char *name, *description, *monitor_source_name, *driver; int mute; + uint32_t flags; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; @@ -395,8 +392,9 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_tagstruct_gets(t, &monitor_source_name) < 0 || pa_tagstruct_get_usec(t, &latency) < 0 || pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (get_info)"); die(u); return; } @@ -491,7 +489,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply."); + pa_log(__FILE__": invalid reply. (create stream)"); die(u); return; } -- cgit From 746adcfed5dc396bc4820724b2e951369fc63aeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:31:50 +0000 Subject: fix a couple of issues I found when compiling polypaudio with gcc 2.95 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@754 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 70cc950c..b68bc485 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -603,7 +603,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED int64_t offset, PA_GCC_UNUSED pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; assert(p && chunk && u); -- cgit From 820c118f9c57c7a7767765efc802502632ad8da2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 24 Apr 2006 19:29:15 +0000 Subject: * rework reference counting in the client libraries: now refcounting goes strictly "one-way" - the "bigger" object refcounts the "smaller" one, never the other way round. * when registering for a reply packet in pdispatch, specify a function that is called when the pdispatch object is destroyed but the reply hasn't yet been recieved. * move prototype of pa_free_cb from stream.h to def.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@794 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index b68bc485..abfa68a4 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -356,7 +356,7 @@ static void request_latency(struct userdata *u) { pa_tagstruct_put_timeval(t, &now); pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); } static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -449,7 +449,7 @@ static void request_info(struct userdata *u) { #endif pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u, NULL); } static void start_subscribe(struct userdata *u) { @@ -580,7 +580,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t #endif pa_pstream_send_tagstruct(u->pstream, reply); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); } static void pstream_die_callback(pa_pstream *p, void *userdata) { @@ -647,7 +647,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); } -- cgit From 185a57cadd7b4e8e85c7fbecc866d7c279704e12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:40:14 +0000 Subject: support new channel_map argument in sink/source modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@803 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index abfa68a4..bffcc7c0 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -51,11 +51,27 @@ #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sinks") -PA_MODULE_USAGE("server=
sink= cookie= format= channels= rate= sink_name=") +PA_MODULE_USAGE( + "server=
" + "sink= " + "cookie= " + "format= " + "channels= " + "rate= " + "sink_name= " + "channel_map=") #else #include "module-tunnel-source-symdef.h" PA_MODULE_DESCRIPTION("Tunnel module for sources") -PA_MODULE_USAGE("server=
source= cookie= format= channels= rate= source_name=") +PA_MODULE_USAGE( + "server=
" + "source= " + "cookie= " + "format= " + "channels= " + "rate= " + "source_name= " + "channel_map=") #endif PA_MODULE_AUTHOR("Lennart Poettering") @@ -87,6 +103,7 @@ static const char* const valid_modargs[] = { "source_name", "source", #endif + "channel_map", NULL, }; @@ -838,6 +855,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; pa_sample_spec ss; + pa_channel_map map; struct timeval ntv; assert(c && m); @@ -877,7 +895,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } @@ -893,7 +911,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create sink."); goto fail; } @@ -909,7 +927,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { pa_log(__FILE__": failed to create source."); goto fail; } -- cgit From 4b6ab291a787ff597c938842b569a35434ab11d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 23:47:38 +0000 Subject: * modify pa_channel_map_init_auto() to take an extra argument specifying the standard to use (ALSA, AIFF, ...) * add some more validity checks to pa_source_new(),pa_sink_new(),pa_sink_input_new(),pa_source_output_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@888 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bffcc7c0..2e04b120 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -895,7 +895,7 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log(__FILE__": invalid sample format specification"); goto fail; } -- cgit From d9cc2cfcb97c1b0449bcbfb6ab0301a58d77bd55 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 16:34:18 +0000 Subject: Move xmalloc to the public side (libpolyp). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@908 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 2e04b120..a2a1e33d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -32,13 +32,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include #include -- cgit From c47e937011f00eebab7230cedb58fd59f16487b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:09:57 +0000 Subject: split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@917 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index a2a1e33d..81c32287 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include -- cgit From 0796ead0db250f6a46a7531c9db471592ed6e129 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 06:45:43 +0000 Subject: Move timeval calculation functions into their own file. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@926 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 81c32287..758d1bd6 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -31,6 +31,7 @@ #include #include +#include #include #include -- cgit From 24a781992bad4d66bb7bc3a2d1deeba7e959dbb1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 18 May 2006 07:04:41 +0000 Subject: Don't include util.h from core-util.h as it is not needed by many users. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@929 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 758d1bd6..bf1fafb3 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -32,6 +32,7 @@ #include #include +#include #include #include -- cgit 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/modules/module-tunnel.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bf1fafb3..bf2627a7 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + 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. - polypaudio is distributed in the hope that it will be useful, but + 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 polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -31,24 +31,24 @@ #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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" -- cgit From 9c87a65ce91c38b60c19ae108a51a2e8ce46a85c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 17:44:19 +0000 Subject: * add new --system command line parameter to the daemon for running PulseAudio as system-wide instance * add PA_ prefixes to all global #defines * modify auth-by-creds: define a new group "pulse-access" which is used for authentication * add proper privilige dropping when running in --system mode * create runtime directory once on startup and not by each module seperately git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1105 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index bf2627a7..c018c520 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -611,7 +611,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void*creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); -- cgit From a382492204ad3588c0c837e120e5bc31578df72a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 19 Jul 2006 21:48:35 +0000 Subject: * add new function pa_check_in_group() * abstract credential APis a little bit by introducing HAVE_CREDS and a structure pa_creds * rework credential authentication * fix module-volume-restore and friends for usage in system-wide instance * remove loopback= argument from moulde-*-protocol-tcp since it is a superset of listen= and usually a bad idea anyway since the user shouldn't load the TCP module at all if he doesn't want remote access * rename a few variables in the jack modules to make sure they don't conflict with symbols defined in the system headers * add server address for system-wide daemons to the default server list for the the client libs * update todo git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1109 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c018c520..2fb34d12 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -611,7 +611,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { } -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const struct ucred *creds, void *userdata) { +static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); -- cgit From bfa6604b1ddc5e2c0f1aaa15330363724856359b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 23:58:55 +0000 Subject: don't set the sink/source descriptions manually, use the new functions pa_{sink,source}_set_description() instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1205 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 2fb34d12..9bb11c09 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -859,6 +859,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; struct timeval ntv; + char *t; + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -925,7 +927,8 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; - u->sink->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name)); + pa_xfree(t); pa_sink_set_owner(u->sink, m); #else @@ -940,7 +943,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_mute = source_get_hw_mute; u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; - u->source->description = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name); + + pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name)); + pa_xfree(t); pa_source_set_owner(u->source, m); #endif -- 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/modules/module-tunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 9bb11c09..53bffd3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -651,7 +651,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata return; } - u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->memblock_stat); + u->pstream = pa_pstream_new(u->core->mainloop, io, u->core->mempool); u->pdispatch = pa_pdispatch_new(u->core->mainloop, command_table, PA_COMMAND_MAX); pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); -- 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/modules/module-tunnel.c | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 53bffd3b..de1a12c9 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -206,7 +206,7 @@ static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t comma struct userdata *u = userdata; assert(pd && t && u && u->pdispatch == pd); - pa_log(__FILE__": stream killed"); + pa_log("stream killed"); die(u); } @@ -223,7 +223,7 @@ static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t com if (pa_tagstruct_getu32(t, &e) < 0 || pa_tagstruct_getu32(t, &idx) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply"); + pa_log("invalid protocol reply"); die(u); return; } @@ -284,13 +284,13 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid protocol reply"); + pa_log("invalid protocol reply"); die(u); return; } if (channel != u->channel) { - pa_log(__FILE__": recieved data for invalid channel"); + pa_log("recieved data for invalid channel"); die(u); return; } @@ -311,9 +311,9 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get latency."); + pa_log("failed to get latency."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -326,7 +326,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (latency)"); + pa_log("invalid reply. (latency)"); die(u); return; } @@ -353,7 +353,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log(__FILE__": estimated host latency: %0.0f usec", (double) u->host_latency); */ +/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -392,9 +392,9 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to get info."); + pa_log("failed to get info."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -413,7 +413,7 @@ static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_ pa_tagstruct_gets(t, &driver) < 0 || pa_tagstruct_getu32(t, &flags) < 0 || !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (get_info)"); + pa_log("invalid reply. (get_info)"); die(u); return; } @@ -495,9 +495,9 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to create stream."); + pa_log("failed to create stream."); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } @@ -508,7 +508,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || #endif !pa_tagstruct_eof(t)) { - pa_log(__FILE__": invalid reply. (create stream)"); + pa_log("invalid reply. (create stream)"); die(u); return; } @@ -535,16 +535,16 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_getu32(t, &u->version) < 0 || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log(__FILE__": failed to authenticate"); + pa_log("failed to authenticate"); else - pa_log(__FILE__": protocol error."); + pa_log("protocol error."); die(u); return; } /* Minimum supported protocol version */ if (u->version < 8) { - pa_log(__FILE__": incompatible protocol version"); + pa_log("incompatible protocol version"); die(u); return; } @@ -606,7 +606,7 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; assert(p && u); - pa_log(__FILE__": stream died."); + pa_log("stream died."); die(u); } @@ -616,7 +616,7 @@ static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_c assert(p && packet && u); if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { - pa_log(__FILE__": invalid packet"); + pa_log("invalid packet"); die(u); } } @@ -627,7 +627,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN assert(p && chunk && u); if (channel != u->channel) { - pa_log(__FILE__": recieved memory block on bad channel."); + pa_log("recieved memory block on bad channel."); die(u); return; } @@ -646,7 +646,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata u->client = NULL; if (!io) { - pa_log(__FILE__": connection failed."); + pa_log("connection failed."); pa_module_unload_request(u->module); return; } @@ -833,7 +833,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = 0; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug(__FILE__": using already loaded auth cookie."); + pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -845,7 +845,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug(__FILE__": loading cookie from disk."); + pa_log_debug("loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -864,7 +864,7 @@ int pa__init(pa_core *c, pa_module*m) { assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments"); + pa_log("failed to parse module arguments"); goto fail; } @@ -894,18 +894,18 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { - pa_log(__FILE__": no server specified."); + pa_log("no server specified."); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { - pa_log(__FILE__": invalid sample format specification"); + pa_log("invalid sample format specification"); goto fail; } if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { - pa_log(__FILE__": failed to connect to server '%s'", u->server_name); + pa_log("failed to connect to server '%s'", u->server_name); goto fail; } @@ -916,7 +916,7 @@ int pa__init(pa_core *c, pa_module*m) { #ifdef TUNNEL_SINK if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create sink."); + pa_log("failed to create sink."); goto fail; } @@ -933,7 +933,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { - pa_log(__FILE__": failed to create source."); + pa_log("failed to create source."); goto fail; } -- cgit From 93e005ad3767eb08cb9542b4bc50f8fab81f5c07 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 25 Aug 2006 22:52:59 +0000 Subject: update module-tunnel to latest protocol git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1332 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 67 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index de1a12c9..18c289a8 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -79,9 +79,6 @@ PA_MODULE_USAGE( PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define DEFAULT_SINK_NAME "tunnel" -#define DEFAULT_SOURCE_NAME "tunnel" - #define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) #define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) #define DEFAULT_MINREQ 512 @@ -503,15 +500,33 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN } if (pa_tagstruct_getu32(t, &u->channel) < 0 || - pa_tagstruct_getu32(t, &u->device_index) < 0 || + pa_tagstruct_getu32(t, &u->device_index) < 0 #ifdef TUNNEL_SINK - pa_tagstruct_getu32(t, &u->requested_bytes) < 0 || + || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 #endif - !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (create stream)"); - die(u); - return; + ) + goto parse_error; + + if (u->version >= 9) { +#ifdef TUNNEL_SINK + uint32_t maxlength, tlength, prebuf, minreq; + + if (pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &tlength) < 0 || + pa_tagstruct_getu32(t, &prebuf) < 0 || + pa_tagstruct_getu32(t, &minreq) < 0) + goto parse_error; +#else + uint32_t maxlength, fragsize; + + if (pa_tagstruct_getu32(t, &maxlength) < 0 || + pa_tagstruct_getu32(t, &fragsize) < 0) + goto parse_error; +#endif } + + if (!pa_tagstruct_eof(t)) + goto parse_error; start_subscribe(u); request_info(u); @@ -520,6 +535,12 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #ifdef TUNNEL_SINK send_bytes(u); #endif + + return; + +parse_error: + pa_log("invalid reply. (create stream)"); + die(u); } static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -550,12 +571,12 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', sink '%s'", + snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->sink->name); #else - snprintf(name, sizeof(name), "Tunnel from host '%s', user '%s', source '%s'", + snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->source->name); @@ -859,7 +880,8 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; struct timeval ntv; - char *t; + char *t, *dn = NULL; + assert(c && m); @@ -915,7 +937,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) { + + if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) + dn = pa_sprintf_malloc("tunnel.%s", u->server_name); + + if (!(u->sink = pa_sink_new(c, __FILE__, dn, 0, &ss, &map))) { pa_log("failed to create sink."); goto fail; } @@ -927,12 +953,16 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; u->sink->userdata = u; - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->sink_name ? u->sink_name : "", u->sink_name ? "@" : "", u->server_name)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) { + + if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) + dn = pa_sprintf_malloc("tunnel.%s", u->server_name); + + if (!(u->source = pa_source_new(c, __FILE__, dn, 0, &ss, &map))) { pa_log("failed to create source."); goto fail; } @@ -944,12 +974,14 @@ int pa__init(pa_core *c, pa_module*m) { u->source->set_hw_mute = source_set_hw_mute; u->source->userdata = u; - pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to '%s%s%s'", u->source_name ? u->source_name : "", u->source_name ? "@" : "", u->server_name)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); pa_source_set_owner(u->source, m); #endif + pa_xfree(dn); + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); @@ -963,6 +995,9 @@ fail: if (ma) pa_modargs_free(ma); + + pa_xfree(dn); + return -1; } -- cgit From b8ea488b7654f447fff49811129001334b2db3fa Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 26 Aug 2006 19:00:22 +0000 Subject: fix module-combine when used on top of a tunnel sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1333 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 18c289a8..18e1d97d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -266,6 +266,8 @@ static void send_bytes(struct userdata *u) { pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); pa_memblock_unref(chunk.memblock); +/* pa_log("sent %lu", (unsigned long) chunk.length); */ + if (chunk.length > u->requested_bytes) u->requested_bytes = 0; else @@ -330,6 +332,8 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_gettimeofday(&now); + /* FIXME! This could use some serious love. */ + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK @@ -350,7 +354,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G u->host_latency = 0; #endif -/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ +/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ } static void request_latency(struct userdata *u) { @@ -631,7 +635,6 @@ static void pstream_die_callback(pa_pstream *p, void *userdata) { die(u); } - static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; assert(p && packet && u); @@ -772,6 +775,7 @@ static int sink_set_hw_mute(pa_sink *sink) { return 0; } + #else static pa_usec_t source_get_latency(pa_source *source) { struct userdata *u; @@ -946,12 +950,12 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->sink->notify = sink_notify; u->sink->get_latency = sink_get_latency; u->sink->get_hw_volume = sink_get_hw_volume; u->sink->set_hw_volume = sink_set_hw_volume; u->sink->get_hw_mute = sink_get_hw_mute; u->sink->set_hw_mute = sink_set_hw_mute; + u->sink->notify = sink_notify; u->sink->userdata = u; pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); -- cgit From 97202d1b2d1638df147a369f4476060f608b568f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 1 Sep 2006 00:24:32 +0000 Subject: fix a race condition with stream connection vs. latency measuremtn (found by theBear) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1355 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 18e1d97d..a110c57e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -490,8 +490,21 @@ static void start_subscribe(struct userdata *u) { pa_pstream_send_tagstruct(u->pstream, t); } +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { + struct userdata *u = userdata; + struct timeval ntv; + assert(m && e && u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; + struct timeval ntv; assert(pd && u && u->pdispatch == pd); if (command != PA_COMMAND_REPLY) { @@ -535,6 +548,11 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN start_subscribe(u); request_info(u); + assert(!u->time_event); + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + u->time_event = u->core->mainloop->time_new(u->core->mainloop, &ntv, timeout_callback, u); + request_latency(u); #ifdef TUNNEL_SINK send_bytes(u); @@ -840,18 +858,6 @@ static int source_set_hw_mute(pa_source *source) { } #endif -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - assert(m && e && u); - - request_latency(u); - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - m->time_restart(e, &ntv); -} - static int load_key(struct userdata *u, const char*fn) { assert(u); @@ -883,10 +889,8 @@ int pa__init(pa_core *c, pa_module*m) { struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; - struct timeval ntv; char *t, *dn = NULL; - assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -986,9 +990,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_xfree(dn); - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - u->time_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, u); + u->time_event = NULL; pa_modargs_free(ma); -- 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/modules/module-tunnel.c | 86 ++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 43 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index a110c57e..f7420a67 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.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 @@ -116,10 +116,10 @@ static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, -#endif +#endif [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { @@ -136,7 +136,7 @@ struct userdata { char *source_name; pa_source *source; #endif - + pa_module *module; pa_core *core; @@ -146,7 +146,7 @@ struct userdata { uint32_t ctag; uint32_t device_index; uint32_t channel; - + pa_usec_t host_latency; pa_time_event *time_event; @@ -156,7 +156,7 @@ struct userdata { static void close_stuff(struct userdata *u) { assert(u); - + if (u->pstream) { pa_pstream_close(u->pstream); pa_pstream_unref(u->pstream); @@ -256,10 +256,10 @@ static void send_bytes(struct userdata *u) { while (u->requested_bytes > 0) { pa_memchunk chunk; if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { - - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) + + if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) send_prebuf_request(u); - + return; } @@ -293,7 +293,7 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui die(u); return; } - + u->requested_bytes += bytes; send_bytes(u); } @@ -316,7 +316,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G die(u); return; } - + if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_get_usec(t, &source_usec) < 0 || pa_tagstruct_get_boolean(t, &playing) < 0 || @@ -333,14 +333,14 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_gettimeofday(&now); /* FIXME! This could use some serious love. */ - + if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK transport_usec = pa_timeval_diff(&remote, &local); #else transport_usec = pa_timeval_diff(&now, &remote); -#endif +#endif } else transport_usec = pa_timeval_diff(&now, &local)/2; @@ -364,7 +364,7 @@ static void request_latency(struct userdata *u) { assert(u); t = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); #else pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); @@ -374,7 +374,7 @@ static void request_latency(struct userdata *u) { pa_gettimeofday(&now); pa_tagstruct_put_timeval(t, &now); - + pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); } @@ -496,7 +496,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED assert(m && e && u); request_latency(u); - + pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; m->time_restart(e, &ntv); @@ -518,16 +518,16 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (pa_tagstruct_getu32(t, &u->channel) < 0 || pa_tagstruct_getu32(t, &u->device_index) < 0 -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 -#endif +#endif ) goto parse_error; if (u->version >= 9) { #ifdef TUNNEL_SINK uint32_t maxlength, tlength, prebuf, minreq; - + if (pa_tagstruct_getu32(t, &maxlength) < 0 || pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || @@ -535,13 +535,13 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN goto parse_error; #else uint32_t maxlength, fragsize; - + if (pa_tagstruct_getu32(t, &maxlength) < 0 || - pa_tagstruct_getu32(t, &fragsize) < 0) + pa_tagstruct_getu32(t, &fragsize) < 0) goto parse_error; #endif } - + if (!pa_tagstruct_eof(t)) goto parse_error; @@ -559,7 +559,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #endif return; - + parse_error: pa_log("invalid reply. (create stream)"); die(u); @@ -603,7 +603,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_get_user_name(un, sizeof(un)), u->source->name); #endif - + reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(reply, tag = u->ctag++); @@ -612,7 +612,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* We ignore the server's reply here */ reply = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK +#ifdef TUNNEL_SINK pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); pa_tagstruct_puts(reply, name); @@ -640,7 +640,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_boolean(reply, 0); pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); #endif - + pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); } @@ -673,7 +673,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UN die(u); return; } - + pa_source_post(u->source, chunk); } #endif @@ -686,7 +686,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_socket_client_unref(u->client); u->client = NULL; - + if (!io) { pa_log("connection failed."); pa_module_unload_request(u->module); @@ -701,7 +701,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata #ifndef TUNNEL_SINK pa_pstream_set_recieve_memblock_callback(u->pstream, pstream_memblock_callback, u); #endif - + t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_AUTH); pa_tagstruct_putu32(t, tag = u->ctag++); @@ -709,7 +709,7 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); - + } #ifdef TUNNEL_SINK @@ -862,14 +862,14 @@ static int load_key(struct userdata *u, const char*fn) { assert(u); u->auth_cookie_in_property = 0; - + if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { pa_log_debug("using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; } - + if (!fn) fn = PA_NATIVE_COOKIE_FILE; @@ -877,7 +877,7 @@ static int load_key(struct userdata *u, const char*fn) { return -1; pa_log_debug("loading cookie from disk."); - + if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = 1; @@ -890,7 +890,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; char *t, *dn = NULL; - + assert(c && m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { @@ -919,10 +919,10 @@ int pa__init(pa_core *c, pa_module*m) { u->host_latency = 0; u->auth_cookie_in_property = 0; u->time_event = NULL; - + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; - + if (!(u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)))) { pa_log("no server specified."); goto fail; @@ -938,7 +938,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to connect to server '%s'", u->server_name); goto fail; } - + if (!u->client) goto fail; @@ -987,7 +987,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_source_set_owner(u->source, m); #endif - + pa_xfree(dn); u->time_event = NULL; @@ -995,7 +995,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_modargs_free(ma); return 0; - + fail: pa__done(c, m); @@ -1003,7 +1003,7 @@ fail: pa_modargs_free(ma); pa_xfree(dn); - + return -1; } @@ -1018,7 +1018,7 @@ void pa__done(pa_core *c, pa_module*m) { if (u->auth_cookie_in_property) pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); - + #ifdef TUNNEL_SINK pa_xfree(u->sink_name); #else -- 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/modules/module-tunnel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index f7420a67..288e049e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.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 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/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 288e049e..b96d46b3 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -596,12 +596,12 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", + pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->sink->name); #else - snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", + pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", pa_get_host_name(hn, sizeof(hn)), pa_get_user_name(un, sizeof(un)), u->source->name); -- cgit From ac8363144777ec60cba979666e7195205fe96c97 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 16:54:16 +0000 Subject: bring back module-tunnel, yay! git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1979 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 977 ++++++++++++++++++++++++++------------------ 1 file changed, 589 insertions(+), 388 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index b96d46b3..1682007a 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -27,7 +27,6 @@ #endif #include -#include #include #include #include @@ -52,6 +51,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" @@ -82,11 +86,10 @@ PA_MODULE_USAGE( PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define DEFAULT_TLENGTH (44100*2*2/10) //(10240*8) -#define DEFAULT_MAXLENGTH ((DEFAULT_TLENGTH*3)/2) -#define DEFAULT_MINREQ 512 -#define DEFAULT_PREBUF (DEFAULT_TLENGTH-DEFAULT_MINREQ) -#define DEFAULT_FRAGSIZE 1024 +#define DEFAULT_TLENGTH_MSEC 100 +#define DEFAULT_MINREQ_MSEC 10 +#define DEFAULT_MAXLENGTH_MSEC ((DEFAULT_TLENGTH_MSEC*3)/2) +#define DEFAULT_FRAGSIZE_MSEC 10 #define DEFAULT_TIMEOUT 5 @@ -109,23 +112,42 @@ static const char* const valid_modargs[] = { NULL, }; -static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +enum { + SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX +}; + +enum { + SINK_MESSAGE_REQUEST = PA_SINK_MESSAGE_MAX, + SINK_MESSAGE_POST +}; #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif +static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, #endif + [PA_COMMAND_OVERFLOW] = command_overflow, + [PA_COMMAND_UNDERFLOW] = command_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, }; struct userdata { + pa_core *core; + pa_module *module; + + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + pa_thread *thread; + pa_socket_client *client; pa_pstream *pstream; pa_pdispatch *pdispatch; @@ -140,9 +162,6 @@ struct userdata { pa_source *source; #endif - pa_module *module; - pa_core *core; - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; uint32_t version; @@ -150,174 +169,284 @@ struct userdata { uint32_t device_index; uint32_t channel; - pa_usec_t host_latency; + int64_t counter, counter_delta; pa_time_event *time_event; - int auth_cookie_in_property; -}; - -static void close_stuff(struct userdata *u) { - assert(u); - - if (u->pstream) { - pa_pstream_close(u->pstream); - pa_pstream_unref(u->pstream); - u->pstream = NULL; - } - - if (u->pdispatch) { - pa_pdispatch_unref(u->pdispatch); - u->pdispatch = NULL; - } + pa_bool_t auth_cookie_in_property; - if (u->client) { - pa_socket_client_unref(u->client); - u->client = NULL; - } + pa_smoother *smoother; + uint32_t maxlength; #ifdef TUNNEL_SINK - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } + uint32_t tlength; + uint32_t minreq; + uint32_t prebuf; #else - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + uint32_t fragsize; #endif +}; - if (u->time_event) { - u->core->mainloop->time_free(u->time_event); - u->time_event = NULL; - } -} +static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); -static void die(struct userdata *u) { - assert(u); - close_stuff(u); + pa_log_warn("Stream killed"); pa_module_unload_request(u->module); } -static void command_stream_killed(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_overflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - assert(pd && t && u && u->pdispatch == pd); - pa_log("stream killed"); - die(u); -} + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); -static void request_info(struct userdata *u); + pa_log_warn("Server signalled buffer overrun."); +} -static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_underflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_subscription_event_type_t e; - uint32_t idx; - - assert(pd && t && u); - assert(command == PA_COMMAND_SUBSCRIBE_EVENT); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_log("invalid protocol reply"); - die(u); - return; - } -#ifdef TUNNEL_SINK - if (e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE)) - return; -#else - if (e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE)) - return; -#endif + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); - request_info(u); + pa_log_warn("Server signalled buffer underrun."); } -#ifdef TUNNEL_SINK -static void send_prebuf_request(struct userdata *u) { +static void stream_cork(struct userdata *u, pa_bool_t cork) { pa_tagstruct *t; + pa_assert(u); + + if (cork) + pa_smoother_pause(u->smoother, pa_rtclock_usec()); + else + pa_smoother_resume(u->smoother, pa_rtclock_usec()); t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_PREBUF_PLAYBACK_STREAM); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); +#else + pa_tagstruct_putu32(t, PA_COMMAND_CORK_RECORD_STREAM); +#endif pa_tagstruct_putu32(t, u->ctag++); pa_tagstruct_putu32(t, u->channel); + pa_tagstruct_put_boolean(t, !!cork); pa_pstream_send_tagstruct(u->pstream, t); } -static void send_bytes(struct userdata *u) { - assert(u); +#ifdef TUNNEL_SINK - if (!u->pstream) - return; +static void send_data(struct userdata *u) { + pa_assert(u); while (u->requested_bytes > 0) { - pa_memchunk chunk; - if (pa_sink_render(u->sink, u->requested_bytes, &chunk) < 0) { + pa_memchunk memchunk; + pa_sink_render(u->sink, u->requested_bytes, &memchunk); + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_POST, NULL, 0, &memchunk, NULL); + pa_memblock_unref(memchunk.memblock); + u->requested_bytes -= memchunk.length; + } +} + +/* This function is called from IO context -- except when it is not. */ +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + + switch (code) { - if (u->requested_bytes >= DEFAULT_TLENGTH-DEFAULT_PREBUF) - send_prebuf_request(u); + case PA_SINK_MESSAGE_SET_STATE: { + int r; - return; + /* First, change the state, because otherwide pa_sink_render() would fail */ + if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0) + if (PA_SINK_OPENED((pa_sink_state_t) PA_PTR_TO_UINT(data))) + send_data(u); + + return r; } - pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, &chunk); - pa_memblock_unref(chunk.memblock); + case SINK_MESSAGE_REQUEST: -/* pa_log("sent %lu", (unsigned long) chunk.length); */ + pa_assert(offset > 0); + u->requested_bytes += (size_t) offset; - if (chunk.length > u->requested_bytes) - u->requested_bytes = 0; - else - u->requested_bytes -= chunk.length; + if (PA_SINK_OPENED(u->sink->thread_info.state)) + send_data(u); + + return 0; + + case SINK_MESSAGE_POST: + + /* OK, This might be a bit confusing. This message is + * delivered to us from the main context -- NOT from the + * IO thread context where the rest of the messages are + * dispatched. Yeah, ugly, but I am a lazy bastard. */ + + pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk); + u->counter += chunk->length; + u->counter_delta += chunk->length; + return 0; + } + + return pa_sink_process_msg(o, code, data, offset, chunk); +} + +static int sink_set_state(pa_sink *s, pa_sink_state_t state) { + struct userdata *u; + pa_sink_assert_ref(s); + u = s->userdata; + + switch ((pa_sink_state_t) state) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(s->state)); + stream_cork(u, TRUE); + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + if (s->state == PA_SINK_SUSPENDED) + stream_cork(u, FALSE); + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; } + + return 0; +} + +#else + +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + + switch (code) { + case SOURCE_MESSAGE_POST: + + if (PA_SOURCE_OPENED(u->source->thread_info.state)) + pa_source_post(u->source, chunk); + return 0; + } + + return pa_source_process_msg(o, code, data, offset, chunk); } +static int source_set_state(pa_source *s, pa_source_state_t state) { + struct userdata *u; + pa_source_assert_ref(s); + u = s->userdata; + + switch ((pa_source_state_t) state) { + + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(s->state)); + stream_cork(u, TRUE); + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + if (s->state == PA_SOURCE_SUSPENDED) + stream_cork(u, FALSE); + break; + + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + } + + return 0; +} + +#endif + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +#ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && u && u->pdispatch == pd); + + pa_assert(pd); + pa_assert(command == PA_COMMAND_REQUEST); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - pa_log("invalid protocol reply"); - die(u); - return; + pa_log("Invalid protocol reply"); + goto fail; } if (channel != u->channel) { - pa_log("recieved data for invalid channel"); - die(u); - return; + pa_log("Recieved data for invalid channel"); + goto fail; } - u->requested_bytes += bytes; - send_bytes(u); + pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL); + return; + +fail: + pa_module_unload_request(u->module); } #endif static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; - pa_usec_t sink_usec, source_usec, transport_usec; + pa_usec_t sink_usec, source_usec, transport_usec, host_usec, k; int playing; int64_t write_index, read_index; struct timeval local, remote, now; - assert(pd && u); + + pa_assert(pd); + pa_assert(u); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to get latency."); + pa_log("Failed to get latency."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || @@ -328,15 +457,12 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_gets64(t, &write_index) < 0 || pa_tagstruct_gets64(t, &read_index) < 0 || !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (latency)"); - die(u); - return; + pa_log("Invalid reply. (latency)"); + goto fail; } pa_gettimeofday(&now); - /* FIXME! This could use some serious love. */ - if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now)) { /* local and remote seem to have synchronized clocks */ #ifdef TUNNEL_SINK @@ -348,23 +474,40 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G transport_usec = pa_timeval_diff(&now, &local)/2; #ifdef TUNNEL_SINK - u->host_latency = sink_usec + transport_usec; + host_usec = sink_usec + transport_usec; #else - u->host_latency = source_usec + transport_usec; - if (u->host_latency > sink_usec) - u->host_latency -= sink_usec; + host_usec = source_usec + transport_usec; + if (host_usec > sink_usec) + host_usec -= sink_usec; + else + host_usec = 0; +#endif + +#ifdef TUNNEL_SINK + k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->sink->sample_spec); + + if (k > host_usec) + k -= host_usec; else - u->host_latency = 0; + k = 0; +#else + k = pa_bytes_to_usec(u->counter - u->counter_delta, &u->source->sample_spec); + k += host_usec; #endif -/* pa_log("estimated host latency: %0.0f usec", (double) u->host_latency); */ + pa_smoother_put(u->smoother, pa_rtclock_usec(), k); + + return; + +fail: + pa_module_unload_request(u->module); } static void request_latency(struct userdata *u) { pa_tagstruct *t; struct timeval now; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); #ifdef TUNNEL_SINK @@ -380,149 +523,183 @@ static void request_latency(struct userdata *u) { pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); + + u->counter_delta = 0; } -static void stream_get_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { +static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { struct userdata *u = userdata; - uint32_t idx, owner_module, monitor_source; - pa_usec_t latency; - const char *name, *description, *monitor_source_name, *driver; + struct timeval ntv; + + pa_assert(m); + pa_assert(e); + pa_assert(u); + + request_latency(u); + + pa_gettimeofday(&ntv); + ntv.tv_sec += LATENCY_INTERVAL; + m->time_restart(e, &ntv); +} + +#ifdef TUNNEL_SINK +static pa_usec_t sink_get_latency(pa_sink *s) { + pa_usec_t t, c; + struct userdata *u = s->userdata; + + pa_sink_assert_ref(s); + + c = pa_bytes_to_usec(u->counter, &s->sample_spec); + t = pa_smoother_get(u->smoother, pa_rtclock_usec()); + + return c > t ? c - t : 0; +} +#else +static pa_usec_t source_get_latency(pa_source *s) { + pa_usec_t t, c; + struct userdata *u = s->userdata; + + pa_source_assert_ref(s); + + c = pa_bytes_to_usec(u->counter, &s->sample_spec); + t = pa_smoother_get(u->smoother, pa_rtclock_usec()); + + return t > c ? t - c : 0; +} +#endif + +#ifdef TUNNEL_SINK + +static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, client, sink; + pa_usec_t buffer_usec, sink_usec; + const char *name, *driver, *resample_method; int mute; - uint32_t flags; pa_sample_spec sample_spec; pa_channel_map channel_map; pa_cvolume volume; - assert(pd && u); + + pa_assert(pd); + pa_assert(u); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to get info."); + pa_log("Failed to get info."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_getu32(t, &client) < 0 || + pa_tagstruct_getu32(t, &sink) < 0 || pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || pa_tagstruct_get_channel_map(t, &channel_map) < 0 || - pa_tagstruct_getu32(t, &owner_module) < 0 || pa_tagstruct_get_cvolume(t, &volume) < 0 || - pa_tagstruct_get_boolean(t, &mute) < 0 || - pa_tagstruct_getu32(t, &monitor_source) < 0 || - pa_tagstruct_gets(t, &monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_get_usec(t, &buffer_usec) < 0 || + pa_tagstruct_get_usec(t, &sink_usec) < 0 || + pa_tagstruct_gets(t, &resample_method) < 0 || pa_tagstruct_gets(t, &driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0 || + (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) || !pa_tagstruct_eof(t)) { - pa_log("invalid reply. (get_info)"); - die(u); - return; + pa_log("Invalid reply. (get_info)"); + goto fail; } -#ifdef TUNNEL_SINK - assert(u->sink); - if ((!!mute == !!u->sink->hw_muted) && - pa_cvolume_equal(&volume, &u->sink->hw_volume)) - return; -#else - assert(u->source); - if ((!!mute == !!u->source->hw_muted) && - pa_cvolume_equal(&volume, &u->source->hw_volume)) + pa_assert(u->sink); + + if ((u->version < 11 || !!mute == !!u->sink->muted) && + pa_cvolume_equal(&volume, &u->sink->volume)) return; -#endif -#ifdef TUNNEL_SINK - memcpy(&u->sink->hw_volume, &volume, sizeof(pa_cvolume)); - u->sink->hw_muted = !!mute; + memcpy(&u->sink->volume, &volume, sizeof(pa_cvolume)); - pa_subscription_post(u->sink->core, - PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, - u->sink->index); -#else - memcpy(&u->source->hw_volume, &volume, sizeof(pa_cvolume)); - u->source->hw_muted = !!mute; + if (u->version >= 11) + u->sink->muted = !!mute; - pa_subscription_post(u->source->core, - PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, - u->source->index); -#endif + pa_subscription_post(u->sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, u->sink->index); + return; + +fail: + pa_module_unload_request(u->module); } static void request_info(struct userdata *u) { pa_tagstruct *t; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); -#else - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); -#endif + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, u->device_index); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL); +} - pa_tagstruct_putu32(t, PA_INVALID_INDEX); -#ifdef TUNNEL_SINK - pa_tagstruct_puts(t, u->sink_name); -#else - pa_tagstruct_puts(t, u->source_name); -#endif +static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_subscription_event_type_t e; + uint32_t idx; - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_info_callback, u, NULL); + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); + + if (pa_tagstruct_getu32(t, &e) < 0 || + pa_tagstruct_getu32(t, &idx) < 0 || + !pa_tagstruct_eof(t)) { + pa_log("Invalid protocol reply"); + pa_module_unload_request(u->module); + return; + } + + if (e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + return; + + request_info(u); } static void start_subscribe(struct userdata *u) { pa_tagstruct *t; uint32_t tag; - assert(u); + pa_assert(u); t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = u->ctag++); - -#ifdef TUNNEL_SINK - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK); -#else - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SOURCE); -#endif - + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK_INPUT); pa_pstream_send_tagstruct(u->pstream, t); } - -static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - struct userdata *u = userdata; - struct timeval ntv; - assert(m && e && u); - - request_latency(u); - - pa_gettimeofday(&ntv); - ntv.tv_sec += LATENCY_INTERVAL; - m->time_restart(e, &ntv); -} +#endif static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; struct timeval ntv; - assert(pd && u && u->pdispatch == pd); +#ifdef TUNNEL_SINK + uint32_t bytes; +#endif + + pa_assert(pd); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY) { if (command == PA_COMMAND_ERROR) - pa_log("failed to create stream."); + pa_log("Failed to create stream."); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + goto fail; } if (pa_tagstruct_getu32(t, &u->channel) < 0 || pa_tagstruct_getu32(t, &u->device_index) < 0 #ifdef TUNNEL_SINK - || pa_tagstruct_getu32(t, &u->requested_bytes) < 0 + || pa_tagstruct_getu32(t, &bytes) < 0 #endif ) goto parse_error; @@ -548,24 +725,31 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (!pa_tagstruct_eof(t)) goto parse_error; +#ifdef TUNNEL_SINK start_subscribe(u); request_info(u); +#endif - assert(!u->time_event); + pa_assert(!u->time_event); pa_gettimeofday(&ntv); ntv.tv_sec += LATENCY_INTERVAL; u->time_event = u->core->mainloop->time_new(u->core->mainloop, &ntv, timeout_callback, u); request_latency(u); + + pa_log_debug("Stream created."); + #ifdef TUNNEL_SINK - send_bytes(u); + pa_asyncmsgq_post(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL, NULL); #endif return; parse_error: - pa_log("invalid reply. (create stream)"); - die(u); + pa_log("Invalid reply. (Create stream)"); + +fail: + pa_module_unload_request(u->module); } static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -575,24 +759,26 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t #ifdef TUNNEL_SINK pa_cvolume volume; #endif - assert(pd && u && u->pdispatch == pd); + + pa_assert(pd); + pa_assert(u); + pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY || pa_tagstruct_getu32(t, &u->version) < 0 || !pa_tagstruct_eof(t)) { if (command == PA_COMMAND_ERROR) - pa_log("failed to authenticate"); + pa_log("Failed to authenticate"); else - pa_log("protocol error."); - die(u); - return; + pa_log("Protocol error."); + + goto fail; } /* Minimum supported protocol version */ if (u->version < 8) { - pa_log("incompatible protocol version"); - die(u); - return; + pa_log("Incompatible protocol version"); + goto fail; } #ifdef TUNNEL_SINK @@ -615,6 +801,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t /* We ignore the server's reply here */ reply = pa_tagstruct_new(NULL, 0); + #ifdef TUNNEL_SINK pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); pa_tagstruct_putu32(reply, tag = u->ctag++); @@ -623,11 +810,11 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_channel_map(reply, &u->sink->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); - pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_TLENGTH); - pa_tagstruct_putu32(reply, DEFAULT_PREBUF); - pa_tagstruct_putu32(reply, DEFAULT_MINREQ); + pa_tagstruct_putu32(reply, u->maxlength); + pa_tagstruct_put_boolean(reply, FALSE); + pa_tagstruct_putu32(reply, u->tlength); + pa_tagstruct_putu32(reply, u->prebuf); + pa_tagstruct_putu32(reply, u->minreq); pa_tagstruct_putu32(reply, 0); pa_cvolume_reset(&volume, u->sink->sample_spec.channels); pa_tagstruct_put_cvolume(reply, &volume); @@ -639,59 +826,82 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_put_channel_map(reply, &u->source->channel_map); pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); - pa_tagstruct_putu32(reply, DEFAULT_MAXLENGTH); + pa_tagstruct_putu32(reply, u->maxlength); pa_tagstruct_put_boolean(reply, 0); - pa_tagstruct_putu32(reply, DEFAULT_FRAGSIZE); + pa_tagstruct_putu32(reply, u->fragsize); #endif pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); + + pa_log_debug("Connection authenticated, creating stream ..."); + + return; + +fail: + pa_module_unload_request(u->module); } static void pstream_die_callback(pa_pstream *p, void *userdata) { struct userdata *u = userdata; - assert(p && u); - pa_log("stream died."); - die(u); + pa_assert(p); + pa_assert(u); + + pa_log_warn("Stream died."); + pa_module_unload_request(u->module); } static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) { struct userdata *u = userdata; - assert(p && packet && u); + + pa_assert(p); + pa_assert(packet); + pa_assert(u); if (pa_pdispatch_run(u->pdispatch, packet, creds, u) < 0) { - pa_log("invalid packet"); - die(u); + pa_log("Invalid packet"); + pa_module_unload_request(u->module); + return; } } #ifndef TUNNEL_SINK -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, PA_GCC_UNUSED int64_t offset, PA_GCC_UNUSED pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { +static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { struct userdata *u = userdata; - assert(p && chunk && u); + + pa_assert(p); + pa_assert(chunk); + pa_assert(u); if (channel != u->channel) { - pa_log("recieved memory block on bad channel."); - die(u); + pa_log("Recieved memory block on bad channel."); + pa_module_unload_request(u->module); return; } - pa_source_post(u->source, chunk); + pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, PA_UINT_TO_PTR(seek), offset, chunk); + + u->counter += chunk->length; + u->counter_delta += chunk->length; } + #endif static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { struct userdata *u = userdata; pa_tagstruct *t; uint32_t tag; - assert(sc && u && u->client == sc); + + pa_assert(sc); + pa_assert(u); + pa_assert(u->client == sc); pa_socket_client_unref(u->client); u->client = NULL; if (!io) { - pa_log("connection failed."); + pa_log("Connection failed: %s", pa_cstrerror(errno)); pa_module_unload_request(u->module); return; } @@ -710,161 +920,85 @@ static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); pa_tagstruct_put_arbitrary(t, u->auth_cookie, sizeof(u->auth_cookie)); - pa_pstream_send_tagstruct(u->pstream, t); - pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); - -} - -#ifdef TUNNEL_SINK -static void sink_notify(pa_sink*sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; - - send_bytes(u); -} - -static pa_usec_t sink_get_latency(pa_sink *sink) { - struct userdata *u; - uint32_t l; - pa_usec_t usec = 0; - assert(sink && sink->userdata); - u = sink->userdata; - l = DEFAULT_TLENGTH; +#ifdef HAVE_CREDS +{ + pa_creds ucred; - if (l > u->requested_bytes) { - l -= u->requested_bytes; - usec += pa_bytes_to_usec(l, &u->sink->sample_spec); - } + if (pa_iochannel_creds_supported(io)) + pa_iochannel_creds_enable(io); - usec += u->host_latency; + ucred.uid = getuid(); + ucred.gid = getgid(); - return usec; + pa_pstream_send_tagstruct_with_creds(u->pstream, t, &ucred); } - -static int sink_get_hw_volume(pa_sink *sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; - - return 0; -} - -static int sink_set_hw_volume(pa_sink *sink) { - struct userdata *u; - pa_tagstruct *t; - uint32_t tag; - assert(sink && sink->userdata); - u = sink->userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); - pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->sink_name); - pa_tagstruct_put_cvolume(t, &sink->hw_volume); +#else pa_pstream_send_tagstruct(u->pstream, t); +#endif - return 0; + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); + + pa_log_debug("Connection established, authenticating ..."); } -static int sink_get_hw_mute(pa_sink *sink) { - struct userdata *u; - assert(sink && sink->userdata); - u = sink->userdata; +#ifdef TUNNEL_SINK +static int sink_get_volume(pa_sink *sink) { return 0; } -static int sink_set_hw_mute(pa_sink *sink) { +static int sink_set_volume(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; uint32_t tag; - assert(sink && sink->userdata); + + pa_assert(sink); u = sink->userdata; + pa_assert(u); t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_MUTE); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->sink_name); - pa_tagstruct_put_boolean(t, !!sink->hw_muted); + pa_tagstruct_putu32(t, u->device_index); + pa_tagstruct_put_cvolume(t, &sink->volume); pa_pstream_send_tagstruct(u->pstream, t); return 0; } -#else -static pa_usec_t source_get_latency(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - - return u->host_latency; -} - -static int source_get_hw_volume(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - +static int sink_get_mute(pa_sink *sink) { return 0; } -static int source_set_hw_volume(pa_source *source) { +static int sink_set_mute(pa_sink *sink) { struct userdata *u; pa_tagstruct *t; uint32_t tag; - assert(source && source->userdata); - u = source->userdata; - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_VOLUME); - pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->source_name); - pa_tagstruct_put_cvolume(t, &source->hw_volume); - pa_pstream_send_tagstruct(u->pstream, t); - - return 0; -} -static int source_get_hw_mute(pa_source *source) { - struct userdata *u; - assert(source && source->userdata); - u = source->userdata; - - return 0; -} + pa_assert(sink); + u = sink->userdata; + pa_assert(u); -static int source_set_hw_mute(pa_source *source) { - struct userdata *u; - pa_tagstruct *t; - uint32_t tag; - assert(source && source->userdata); - u = source->userdata; + if (u->version < 11) + return -1; t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, PA_COMMAND_SET_SOURCE_MUTE); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE); pa_tagstruct_putu32(t, tag = u->ctag++); - - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, u->source_name); - pa_tagstruct_put_boolean(t, !!source->hw_muted); + pa_tagstruct_putu32(t, u->device_index); + pa_tagstruct_put_boolean(t, !!sink->muted); pa_pstream_send_tagstruct(u->pstream, t); return 0; } + #endif static int load_key(struct userdata *u, const char*fn) { - assert(u); + pa_assert(u); - u->auth_cookie_in_property = 0; + u->auth_cookie_in_property = FALSE; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { pa_log_debug("using already loaded auth cookie."); @@ -882,29 +1016,29 @@ static int load_key(struct userdata *u, const char*fn) { pa_log_debug("loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) - u->auth_cookie_in_property = 1; + u->auth_cookie_in_property = TRUE; return 0; } -int pa__init(pa_core *c, pa_module*m) { +int pa__init(pa_module*m) { pa_modargs *ma = NULL; struct userdata *u = NULL; pa_sample_spec ss; pa_channel_map map; char *t, *dn = NULL; - assert(c && m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("failed to parse module arguments"); goto fail; } - u = pa_xmalloc(sizeof(struct userdata)); + u = pa_xnew(struct userdata, 1); m->userdata = u; u->module = m; - u->core = c; + u->core = m->core; u->client = NULL; u->pdispatch = NULL; u->pstream = NULL; @@ -917,12 +1051,16 @@ int pa__init(pa_core *c, pa_module*m) { u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; u->source = NULL; #endif + u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE); u->ctag = 1; u->device_index = u->channel = PA_INVALID_INDEX; - u->host_latency = 0; - u->auth_cookie_in_property = 0; + u->auth_cookie_in_property = FALSE; u->time_event = NULL; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + if (load_key(u, pa_modargs_get_value(ma, "cookie", NULL)) < 0) goto fail; @@ -931,20 +1069,17 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) { pa_log("invalid sample format specification"); goto fail; } - if (!(u->client = pa_socket_client_new_string(c->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { + if (!(u->client = pa_socket_client_new_string(m->core->mainloop, u->server_name, PA_NATIVE_DEFAULT_PORT))) { pa_log("failed to connect to server '%s'", u->server_name); goto fail; } - if (!u->client) - goto fail; - pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK @@ -952,55 +1087,81 @@ int pa__init(pa_core *c, pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->sink = pa_sink_new(c, __FILE__, dn, 0, &ss, &map))) { - pa_log("failed to create sink."); + if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 0, &ss, &map))) { + pa_log("Failed to create sink."); goto fail; } - u->sink->get_latency = sink_get_latency; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; - u->sink->get_hw_mute = sink_get_hw_mute; - u->sink->set_hw_mute = sink_set_hw_mute; - u->sink->notify = sink_notify; + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; + u->sink->set_state = sink_set_state; + u->sink->get_latency = sink_get_latency; + u->sink->get_volume = sink_get_volume; + u->sink->get_mute = sink_get_mute; + u->sink->set_volume = sink_set_volume; + u->sink->set_mute = sink_set_mute; + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); - pa_sink_set_owner(u->sink, m); #else if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->source = pa_source_new(c, __FILE__, dn, 0, &ss, &map))) { - pa_log("failed to create source."); + if (!(u->source = pa_source_new(m->core, __FILE__, dn, 0, &ss, &map))) { + pa_log("Failed to create source."); goto fail; } - u->source->get_latency = source_get_latency; - u->source->get_hw_volume = source_get_hw_volume; - u->source->set_hw_volume = source_set_hw_volume; - u->source->get_hw_mute = source_get_hw_mute; - u->source->set_hw_mute = source_set_hw_mute; + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; + u->source->set_state = source_set_state; + u->source->get_latency = source_get_latency; + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); - - pa_source_set_owner(u->source, m); #endif pa_xfree(dn); u->time_event = NULL; + u->maxlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MAXLENGTH_MSEC, &ss); +#ifdef TUNNEL_SINK + u->tlength = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_TLENGTH_MSEC, &ss); + u->minreq = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_MINREQ_MSEC, &ss); + u->prebuf = u->tlength; +#else + u->fragsize = pa_usec_to_bytes(PA_USEC_PER_MSEC * DEFAULT_FRAGSIZE_MSEC, &ss); +#endif + + u->counter = u->counter_delta = 0; + pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec()); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; + } + +#ifdef TUNNEL_SINK + pa_sink_put(u->sink); +#else + pa_source_put(u->source); +#endif + pa_modargs_free(ma); return 0; fail: - pa__done(c, m); + pa__done(m); if (ma) pa_modargs_free(ma); @@ -1010,17 +1171,59 @@ fail: return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata* u; - assert(c && m); + + pa_assert(m); if (!(u = m->userdata)) return; - close_stuff(u); +#ifdef TUNNEL_SINK + if (u->sink) + pa_sink_unlink(u->sink); +#else + if (u->source) + pa_source_unlink(u->source); +#endif + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + +#ifdef TUNNEL_SINK + if (u->sink) + pa_sink_unref(u->sink); +#else + if (u->source) + pa_source_unref(u->source); +#endif + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->pstream) { + pa_pstream_unlink(u->pstream); + pa_pstream_unref(u->pstream); + } + + if (u->pdispatch) + pa_pdispatch_unref(u->pdispatch); + + if (u->client) + pa_socket_client_unref(u->client); if (u->auth_cookie_in_property) - pa_authkey_prop_unref(c, PA_NATIVE_COOKIE_PROPERTY_NAME); + pa_authkey_prop_unref(m->core, PA_NATIVE_COOKIE_PROPERTY_NAME); + + if (u->smoother) + pa_smoother_free(u->smoother); + + if (u->time_event) + u->core->mainloop->time_free(u->time_event); #ifdef TUNNEL_SINK pa_xfree(u->sink_name); @@ -1031,5 +1234,3 @@ void pa__done(pa_core *c, pa_module*m) { pa_xfree(u); } - - -- cgit From 0ce32bd40c07af44cb13c80f559d18e162266a89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 20:01:20 +0000 Subject: fail on name clash git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1980 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 1682007a..936821ff 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1087,7 +1087,7 @@ int pa__init(pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 0, &ss, &map))) { + if (!(u->sink = pa_sink_new(m->core, __FILE__, dn, 1, &ss, &map))) { pa_log("Failed to create sink."); goto fail; } @@ -1112,7 +1112,7 @@ int pa__init(pa_module*m) { if (!(dn = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)))) dn = pa_sprintf_malloc("tunnel.%s", u->server_name); - if (!(u->source = pa_source_new(m->core, __FILE__, dn, 0, &ss, &map))) { + if (!(u->source = pa_source_new(m->core, __FILE__, dn, 1, &ss, &map))) { pa_log("Failed to create source."); goto fail; } -- cgit From 33c238b7ef4b6c00f46714f14b3c6e1f29af6fde Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 21:23:08 +0000 Subject: ignore network sinks/sources git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1988 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 936821ff..c6b0a2cb 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1100,6 +1100,7 @@ int pa__init(pa_module*m) { u->sink->get_mute = sink_get_mute; u->sink->set_volume = sink_set_volume; u->sink->set_mute = sink_set_mute; + u->sink->flags = PA_SINK_NETWORK|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL; pa_sink_set_module(u->sink, m); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); @@ -1121,6 +1122,7 @@ int pa__init(pa_module*m) { u->source->userdata = u; u->source->set_state = source_set_state; u->source->get_latency = source_get_latency; + u->source->flags = PA_SOURCE_NETWORK|PA_SOURCE_LATENCY; pa_source_set_module(u->source, m); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); -- cgit From 5ef242c5b323a0abaca4cfb44b3a1cba99a4c43d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 29 Oct 2007 22:14:34 +0000 Subject: don't try to send pause request before our stream is properly set up git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1989 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c6b0a2cb..7b6b1b82 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -230,6 +230,9 @@ static void stream_cork(struct userdata *u, pa_bool_t cork) { else pa_smoother_resume(u->smoother, pa_rtclock_usec()); + if (!u->pstream) + return; + t = pa_tagstruct_new(NULL, 0); #ifdef TUNNEL_SINK pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); @@ -811,7 +814,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->sink_name); pa_tagstruct_putu32(reply, u->maxlength); - pa_tagstruct_put_boolean(reply, FALSE); + pa_tagstruct_put_boolean(reply, !PA_SINK_OPENED(pa_sink_get_state(u->sink))); pa_tagstruct_putu32(reply, u->tlength); pa_tagstruct_putu32(reply, u->prebuf); pa_tagstruct_putu32(reply, u->minreq); @@ -827,7 +830,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, PA_INVALID_INDEX); pa_tagstruct_puts(reply, u->source_name); pa_tagstruct_putu32(reply, u->maxlength); - pa_tagstruct_put_boolean(reply, 0); + pa_tagstruct_put_boolean(reply, !PA_SOURCE_OPENED(pa_source_get_state(u->source))); pa_tagstruct_putu32(reply, u->fragsize); #endif -- cgit From bb2e1afd5181ac67a7daf769b9adc506665a8ed4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 00:49:50 +0000 Subject: initialize userdata struct with 0 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1994 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 7b6b1b82..5ad4711d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -448,7 +448,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G if (command == PA_COMMAND_ERROR) pa_log("Failed to get latency."); else - pa_log("Protocol error."); + pa_log("Protocol error 1."); goto fail; } @@ -590,7 +590,7 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED if (command == PA_COMMAND_ERROR) pa_log("Failed to get info."); else - pa_log("Protocol error."); + pa_log("Protocol error 2."); goto fail; } @@ -695,7 +695,7 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN if (command == PA_COMMAND_ERROR) pa_log("Failed to create stream."); else - pa_log("Protocol error."); + pa_log("Protocol error 3."); goto fail; } @@ -773,7 +773,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t if (command == PA_COMMAND_ERROR) pa_log("Failed to authenticate"); else - pa_log("Protocol error."); + pa_log("Protocol error 4."); goto fail; } @@ -1038,7 +1038,7 @@ int pa__init(pa_module*m) { goto fail; } - u = pa_xnew(struct userdata, 1); + u = pa_xnew0(struct userdata, 1); m->userdata = u; u->module = m; u->core = m->core; -- cgit From 1e0454eb74485d0f323e7cecd55470a38bd5683e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 01:50:22 +0000 Subject: rework the tunnel naming scheme, and make it follow the description changes of the underlying devices; never check for tagstruct eof, to ease later extensions git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1995 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 260 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 231 insertions(+), 29 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 5ad4711d..c36e70b7 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -123,8 +123,8 @@ enum { #ifdef TUNNEL_SINK static void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); #endif +static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -132,8 +132,8 @@ static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK [PA_COMMAND_REQUEST] = command_request, - [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, #endif + [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, [PA_COMMAND_OVERFLOW] = command_overflow, [PA_COMMAND_UNDERFLOW] = command_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, @@ -177,6 +177,10 @@ struct userdata { pa_smoother *smoother; + char *device_description; + char *server_fqdn; + char *user_name; + uint32_t maxlength; #ifdef TUNNEL_SINK uint32_t tlength; @@ -414,8 +418,7 @@ static void command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED ui pa_assert(u->pdispatch == pd); if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &bytes) < 0) { pa_log("Invalid protocol reply"); goto fail; } @@ -458,8 +461,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, PA_G pa_tagstruct_get_timeval(t, &local) < 0 || pa_tagstruct_get_timeval(t, &remote) < 0 || pa_tagstruct_gets64(t, &write_index) < 0 || - pa_tagstruct_gets64(t, &read_index) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_gets64(t, &read_index) < 0) { pa_log("Invalid reply. (latency)"); goto fail; } @@ -571,8 +573,119 @@ static pa_usec_t source_get_latency(pa_source *s) { } #endif +static void update_description(struct userdata *u) { + char *d; + + pa_assert(u); + + if (!u->server_fqdn || !u->user_name || !u->device_description) + return; + + d = pa_sprintf_malloc("%s's %s on %s", u->user_name, u->device_description, u->server_fqdn); + +#ifdef TUNNEL_SINK + pa_sink_set_description(u->sink, d); +#else + pa_source_set_description(u->source, d); +#endif + + pa_xfree(d); +} + +static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + pa_sample_spec ss; + const char *server_name, *server_version, *user_name, *host_name, *default_sink_name, *default_source_name; + uint32_t cookie; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 6."); + goto fail; + } + + if (pa_tagstruct_gets(t, &server_name) < 0 || + pa_tagstruct_gets(t, &server_version) < 0 || + pa_tagstruct_gets(t, &user_name) < 0 || + pa_tagstruct_gets(t, &host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_gets(t, &default_sink_name) < 0 || + pa_tagstruct_gets(t, &default_source_name) < 0 || + pa_tagstruct_getu32(t, &cookie) < 0) { + pa_log("Invalid reply. (get_server_info)"); + goto fail; + } + + pa_xfree(u->server_fqdn); + u->server_fqdn = pa_xstrdup(host_name); + + pa_xfree(u->user_name); + u->user_name = pa_xstrdup(user_name); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + #ifdef TUNNEL_SINK +static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, monitor_source, flags; + const char *name, *description, *monitor_source_name, *driver; + pa_sample_spec ss; + pa_channel_map cm; + pa_cvolume volume; + int mute; + pa_usec_t latency; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 5."); + goto fail; + } + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &cm) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_source) < 0 || + pa_tagstruct_gets(t, &monitor_source_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + pa_log("Invalid reply. (get_sink_info)"); + goto fail; + } + + pa_xfree(u->device_description); + u->device_description = pa_xstrdup(description); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; uint32_t idx, owner_module, client, sink; @@ -606,12 +719,14 @@ static void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED pa_tagstruct_get_usec(t, &sink_usec) < 0 || pa_tagstruct_gets(t, &resample_method) < 0 || pa_tagstruct_gets(t, &driver) < 0 || - (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) || - !pa_tagstruct_eof(t)) { + (u->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0)) { pa_log("Invalid reply. (get_info)"); goto fail; } + if (idx != u->device_index) + return; + pa_assert(u->sink); if ((u->version < 11 || !!mute == !!u->sink->muted) && @@ -630,17 +745,94 @@ fail: pa_module_unload_request(u->module); } +#else + +static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + uint32_t idx, owner_module, monitor_of_sink, flags; + const char *name, *description, *monitor_of_sink_name, *driver; + pa_sample_spec ss; + pa_channel_map cm; + pa_cvolume volume; + int mute; + pa_usec_t latency; + + pa_assert(pd); + pa_assert(u); + + if (command != PA_COMMAND_REPLY) { + if (command == PA_COMMAND_ERROR) + pa_log("Failed to get info."); + else + pa_log("Protocol error 5."); + goto fail; + } + + if (pa_tagstruct_getu32(t, &idx) < 0 || + pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &description) < 0 || + pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &cm) < 0 || + pa_tagstruct_getu32(t, &owner_module) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || + pa_tagstruct_get_boolean(t, &mute) < 0 || + pa_tagstruct_getu32(t, &monitor_of_sink) < 0 || + pa_tagstruct_gets(t, &monitor_of_sink_name) < 0 || + pa_tagstruct_get_usec(t, &latency) < 0 || + pa_tagstruct_gets(t, &driver) < 0 || + pa_tagstruct_getu32(t, &flags) < 0) { + pa_log("Invalid reply. (get_source_info)"); + goto fail; + } + + pa_xfree(u->device_description); + u->device_description = pa_xstrdup(description); + + update_description(u); + + return; + +fail: + pa_module_unload_request(u->module); +} + +#endif + static void request_info(struct userdata *u) { pa_tagstruct *t; uint32_t tag; pa_assert(u); + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, server_info_cb, u, NULL); + +#ifdef TUNNEL_SINK t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); pa_tagstruct_putu32(t, tag = u->ctag++); pa_tagstruct_putu32(t, u->device_index); pa_pstream_send_tagstruct(u->pstream, t); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL); + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->sink_name); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_info_cb, u, NULL); +#else + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, tag = u->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, u->source_name); + pa_pstream_send_tagstruct(u->pstream, t); + pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, source_info_cb, u, NULL); +#endif } static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -654,14 +846,20 @@ static void command_subscribe_event(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t com pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &idx) < 0) { pa_log("Invalid protocol reply"); pa_module_unload_request(u->module); return; } - if (e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE)) + if (e != (PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE) && +#ifdef TUNNEL_SINK + e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && + e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) +#else + e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE) +#endif + ) return; request_info(u); @@ -675,10 +873,16 @@ static void start_subscribe(struct userdata *u) { t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = u->ctag++); - pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SINK_INPUT); + pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SERVER| +#ifdef TUNNEL_SINK + PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SINK +#else + PA_SUBSCRIPTION_MASK_SOURCE +#endif + ); + pa_pstream_send_tagstruct(u->pstream, t); } -#endif static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { struct userdata *u = userdata; @@ -725,13 +929,8 @@ static void create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN #endif } - if (!pa_tagstruct_eof(t)) - goto parse_error; - -#ifdef TUNNEL_SINK start_subscribe(u); request_info(u); -#endif pa_assert(!u->time_event); pa_gettimeofday(&ntv); @@ -768,8 +967,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_assert(u->pdispatch == pd); if (command != PA_COMMAND_REPLY || - pa_tagstruct_getu32(t, &u->version) < 0 || - !pa_tagstruct_eof(t)) { + pa_tagstruct_getu32(t, &u->version) < 0) { if (command == PA_COMMAND_ERROR) pa_log("Failed to authenticate"); else @@ -785,21 +983,21 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, sink %s", - pa_get_host_name(hn, sizeof(hn)), + pa_snprintf(name, sizeof(name), "%s@%s", pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn)), u->sink->name); #else - pa_snprintf(name, sizeof(name), "Tunnel from host %s, user %s, source %s", - pa_get_host_name(hn, sizeof(hn)), + pa_snprintf(name, sizeof(name), "%s@%s", pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn)), u->source->name); #endif reply = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); pa_tagstruct_putu32(reply, tag = u->ctag++); - pa_tagstruct_puts(reply, name); + pa_tagstruct_puts(reply, "PulseAudio"); pa_pstream_send_tagstruct(u->pstream, reply); /* We ignore the server's reply here */ @@ -1004,7 +1202,7 @@ static int load_key(struct userdata *u, const char*fn) { u->auth_cookie_in_property = FALSE; if (!fn && pa_authkey_prop_get(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) { - pa_log_debug("using already loaded auth cookie."); + pa_log_debug("Using already loaded auth cookie."); pa_authkey_prop_ref(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME); u->auth_cookie_in_property = 1; return 0; @@ -1016,7 +1214,7 @@ static int load_key(struct userdata *u, const char*fn) { if (pa_authkey_load_auto(fn, u->auth_cookie, sizeof(u->auth_cookie)) < 0) return -1; - pa_log_debug("loading cookie from disk."); + pa_log_debug("Loading cookie from disk."); if (pa_authkey_prop_put(u->core, PA_NATIVE_COOKIE_PROPERTY_NAME, u->auth_cookie, sizeof(u->auth_cookie)) >= 0) u->auth_cookie_in_property = TRUE; @@ -1108,7 +1306,7 @@ int pa__init(pa_module*m) { pa_sink_set_module(u->sink, m); pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); pa_sink_set_rtpoll(u->sink, u->rtpoll); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("%s%s%s", u->sink_name ? u->sink_name : "", u->sink_name ? " on " : "", u->server_name)); pa_xfree(t); #else @@ -1130,7 +1328,7 @@ int pa__init(pa_module*m) { pa_source_set_module(u->source, m); pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); - pa_source_set_description(u->source, t = pa_sprintf_malloc("Tunnel to %s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); + pa_source_set_description(u->source, t = pa_sprintf_malloc("%s%s%s", u->source_name ? u->source_name : "", u->source_name ? " on " : "", u->server_name)); pa_xfree(t); #endif @@ -1237,5 +1435,9 @@ void pa__done(pa_module*m) { #endif pa_xfree(u->server_name); + pa_xfree(u->device_description); + pa_xfree(u->server_fqdn); + pa_xfree(u->user_name); + pa_xfree(u); } -- cgit From 201dff7b2e881228b14c4aa67fb51360f548043c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 02:05:53 +0000 Subject: ignore updates not relevant to us git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1996 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index c36e70b7..485b6f3b 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -675,6 +675,9 @@ static void sink_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint3 goto fail; } + if (strcmp(name, u->sink_name)) + return; + pa_xfree(u->device_description); u->device_description = pa_xstrdup(description); @@ -785,6 +788,9 @@ static void source_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uin goto fail; } + if (strcmp(name, u->source_name)) + return; + pa_xfree(u->device_description); u->device_description = pa_xstrdup(description); -- cgit From 72817f9d9dcd7548972b7d1090fefa19436ca538 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 30 Oct 2007 02:35:00 +0000 Subject: rename stream names too, when the sink name changes git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1997 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 485b6f3b..edc03c99 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -575,13 +575,15 @@ static pa_usec_t source_get_latency(pa_source *s) { static void update_description(struct userdata *u) { char *d; + char un[128], hn[128]; + pa_tagstruct *t; pa_assert(u); if (!u->server_fqdn || !u->user_name || !u->device_description) return; - d = pa_sprintf_malloc("%s's %s on %s", u->user_name, u->device_description, u->server_fqdn); + d = pa_sprintf_malloc("%s on %s@%s", u->device_description, u->user_name, u->server_fqdn); #ifdef TUNNEL_SINK pa_sink_set_description(u->sink, d); @@ -590,6 +592,23 @@ static void update_description(struct userdata *u) { #endif pa_xfree(d); + + d = pa_sprintf_malloc("%s for %s@%s", u->device_description, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); + + t = pa_tagstruct_new(NULL, 0); +#ifdef TUNNEL_SINK + pa_tagstruct_putu32(t, PA_COMMAND_SET_PLAYBACK_STREAM_NAME); +#else + pa_tagstruct_putu32(t, PA_COMMAND_SET_RECORD_STREAM_NAME); +#endif + pa_tagstruct_putu32(t, u->ctag++); + pa_tagstruct_putu32(t, u->channel); + pa_tagstruct_puts(t, d); + pa_pstream_send_tagstruct(u->pstream, t); + + pa_xfree(d); } static void server_info_cb(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { @@ -989,15 +1008,15 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t } #ifdef TUNNEL_SINK - pa_snprintf(name, sizeof(name), "%s@%s", - pa_get_user_name(un, sizeof(un)), - pa_get_host_name(hn, sizeof(hn)), - u->sink->name); + pa_snprintf(name, sizeof(name), "%s for %s@%s", + u->sink_name, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); #else - pa_snprintf(name, sizeof(name), "%s@%s", - pa_get_user_name(un, sizeof(un)), - pa_get_host_name(hn, sizeof(hn)), - u->source->name); + pa_snprintf(name, sizeof(name), "%s for %s@%s", + u->source_name, + pa_get_user_name(un, sizeof(un)), + pa_get_host_name(hn, sizeof(hn))); #endif reply = pa_tagstruct_new(NULL, 0); -- cgit From e313fe1b3d0d9f9945c41c151d72edbe9cf1ec54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 18:25:40 +0000 Subject: tag modules that may only be loaded once at most especially, and enforce that in the module loader git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2043 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index edc03c99..05cece7d 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -59,7 +59,8 @@ #ifdef TUNNEL_SINK #include "module-tunnel-sink-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sinks") +PA_MODULE_DESCRIPTION("Tunnel module for sinks"); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "server=
" "sink= " @@ -68,10 +69,10 @@ PA_MODULE_USAGE( "channels= " "rate= " "sink_name= " - "channel_map=") + "channel_map="); #else #include "module-tunnel-source-symdef.h" -PA_MODULE_DESCRIPTION("Tunnel module for sources") +PA_MODULE_DESCRIPTION("Tunnel module for sources"); PA_MODULE_USAGE( "server=
" "source= " @@ -80,11 +81,11 @@ PA_MODULE_USAGE( "channels= " "rate= " "source_name= " - "channel_map=") + "channel_map="); #endif -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_VERSION(PACKAGE_VERSION); #define DEFAULT_TLENGTH_MSEC 100 #define DEFAULT_MINREQ_MSEC 10 -- cgit From 02f49a24f4eaa97a68874a3116a136202a4605b8 Mon Sep 17 00:00:00 2001 From: Sjoerd Simons Date: Fri, 4 Jan 2008 14:57:31 +0000 Subject: Implement opcodes in the tunnel modules that were added in version 12 of the protocol. Based on a patch by coling. (fixes #193) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2096 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-tunnel.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src/modules/module-tunnel.c') diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 05cece7d..a53e3932 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -129,6 +129,8 @@ static void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t static void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_overflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); +static void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { #ifdef TUNNEL_SINK @@ -139,6 +141,10 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_UNDERFLOW] = command_underflow, [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, + [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = command_suspend, + [PA_COMMAND_RECORD_STREAM_SUSPENDED] = command_suspend, + [PA_COMMAND_PLAYBACK_STREAM_MOVED] = command_moved, + [PA_COMMAND_RECORD_STREAM_MOVED] = command_moved, }; struct userdata { @@ -226,6 +232,28 @@ static void command_underflow(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, pa_log_warn("Server signalled buffer underrun."); } +static void command_suspend(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); + + pa_log_debug("Server reports a stream suspension."); +} + +static void command_moved(pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { + struct userdata *u = userdata; + + pa_assert(pd); + pa_assert(t); + pa_assert(u); + pa_assert(u->pdispatch == pd); + + pa_log_debug("Server reports a stream move."); +} + static void stream_cork(struct userdata *u, pa_bool_t cork) { pa_tagstruct *t; pa_assert(u); @@ -1058,6 +1086,18 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t pa_tagstruct_putu32(reply, u->fragsize); #endif + /* New flags added in 0.9.8 */ + if (u->version >= 12) { + /* TODO: set these to useful values */ + pa_tagstruct_put_boolean(reply, FALSE); /*no_remap*/ + pa_tagstruct_put_boolean(reply, FALSE); /*no_remix*/ + pa_tagstruct_put_boolean(reply, FALSE); /*fix_format*/ + pa_tagstruct_put_boolean(reply, FALSE); /*fix_rate*/ + pa_tagstruct_put_boolean(reply, FALSE); /*fix_channels*/ + pa_tagstruct_put_boolean(reply, FALSE); /*no_move*/ + pa_tagstruct_put_boolean(reply, FALSE); /*variable_rate*/ + } + pa_pstream_send_tagstruct(u->pstream, reply); pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); -- cgit