diff options
58 files changed, 971 insertions, 169 deletions
| diff --git a/configure.ac b/configure.ac index a54f383f..658910c6 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@  # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.  AC_PREREQ(2.57) -AC_INIT([polypaudio],[0.7.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.8],[mzcbylcnhqvb (at) 0pointer (dot) de])  AC_CONFIG_SRCDIR([polyp/main.c])  AC_CONFIG_HEADERS([config.h])  AM_INIT_AUTOMAKE([foreign -Wall]) @@ -28,7 +28,7 @@ AM_INIT_AUTOMAKE([foreign -Wall])  AC_SUBST(PA_MAJORMINOR, "$PACKAGE_VERSION")  AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/polypaudio/]) -AC_SUBST(PA_API_VERSION, 7) +AC_SUBST(PA_API_VERSION, 8)  if type -p stow > /dev/null && test -d /usr/local/stow ; then     AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) @@ -1,23 +1,31 @@  *** $Id$ *** -*** later **** -- event more commenting -- polish for starting polypaudio as root/system-wide instance +Architectural changes:  - per-channel volume +- channel mapping ("left", "right", "rear", "subwoofer") +- add API for synchronizing multiple sinks/sources to a common clock +- absolutely indexed write()s from client +- remove "polyplib-" prefix + +Fixes:  - improve module-oss-mmap latency measurement  - module-tunnel: improve latency calculation +- make alsa modules use mmap +- event more commenting + +Features:  - add radio module -- pass meta info for hearing impaired -- add sync API -- X11: support for the X11 synchronization extension  - xmlrpc/http  - dbus  - rendezvous -- make alsa modules use mmap +- polish for starting polypaudio as root/system-wide instance +- export connection fd -*********** +Long term: +- pass meta info for hearing impaired +- X11: support for the X11 synchronization extension -backends for: +Backends for:  - portaudio  (semi-done)  - alsa-lib  - sdl diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 83b5670a..70051671 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -220,7 +220,9 @@ polypaudio_SOURCES = idxset.c idxset.h \  		props.h props.c \  		mcalign.c mcalign.h \  		g711.c g711.h \ -		pid.c pid.h +		pid.c pid.h \ +		random.c random.h \ +		typeid.c typeid.h  polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)  polypaudio_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) @@ -455,7 +457,9 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = polyplib.h \  		conf-parser.c conf-parser.h \  		strlist.c strlist.h \  		strbuf.c strbuf.h \ -		mcalign.c mcalign.h +		mcalign.c mcalign.h \ +		typeid.c typeid.h \ +		random.c random.h  libpolyp_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS)  libpolyp_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0 @@ -560,7 +564,7 @@ module_x11_publish_la_LIBADD = $(AM_LIBADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EX  bin_PROGRAMS+= \  		pax11publish -pax11publish_SOURCES = pax11publish.c util.c xmalloc.c log.c authkey.c client-conf.c conf-parser.c x11prop.c +pax11publish_SOURCES = pax11publish.c util.c util.h xmalloc.c xmalloc.h log.c log.h authkey.c authkey.h client-conf.c client-conf.h conf-parser.c conf-parser.h x11prop.c x11prop.h random.c random.h  pax11publish_CFLAGS = $(AM_CFLAGS) $(X_CFLAGS)  pax11publish_LDADD = $(AM_LDADD) $(X_PRE_LIBS) -lX11 $(X_LIBS) $(X_EXTRA_LIBS) @@ -613,6 +617,21 @@ module_zeroconf_publish_la_LDFLAGS = -module -avoid-version  module_zeroconf_publish_la_LIBADD = $(AM_LIBADD) $(HOWL_LIBS) libhowl-wrap.la  module_zeroconf_publish_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +lib_LTLIBRARIES+= \ +		libpolyp-browse-@PA_MAJORMINOR@.la + +libpolyp_browse_@PA_MAJORMINOR@_la_SOURCES = polyplib-browser.c polyplib-browser.h  +libpolyp_browse_@PA_MAJORMINOR@_la_CFLAGS = $(AM_CFLAGS) $(HOWL_CFLAGS) +libpolyp_browse_@PA_MAJORMINOR@_la_LIBADD = $(AM_LIBADD) libpolyp-@PA_MAJORMINOR@.la $(HOWL_LIBS) +libpolyp_browse_@PA_MAJORMINOR@_la_LDFLAGS = -version-info 0:0:0  + +bin_PROGRAMS += \ +		pabrowse + +pabrowse_SOURCES = pabrowse.c +pabrowse_LDADD = $(AM_LDADD) libpolyp-@PA_MAJORMINOR@.la libpolyp-error-@PA_MAJORMINOR@.la libpolyp-mainloop-@PA_MAJORMINOR@.la libpolyp-browse-@PA_MAJORMINOR@.la +pabrowse_CFLAGS = $(AM_CFLAGS) +  endif  ### GLIB 2.0 support diff --git a/polyp/authkey.c b/polyp/authkey.c index 1355c8d9..e16883d3 100644 --- a/polyp/authkey.c +++ b/polyp/authkey.c @@ -38,50 +38,24 @@  #include "authkey.h"  #include "util.h"  #include "log.h" - -#define RANDOM_DEVICE "/dev/urandom" +#include "random.h"  /* Generate a new authorization key, store it in file fd and return it in *data  */ -static int generate(int fd, void *data, size_t length) { -    int random_fd, ret = -1; +static int generate(int fd, void *ret_data, size_t length) {      ssize_t r; -    assert(fd >= 0 && data && length); - -    if ((random_fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { - -        if ((r = pa_loop_read(random_fd, data, length)) < 0 || (size_t) r != length) { -            pa_log(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); -            goto finish; -        } -         -    } else { -        uint8_t *p; -        size_t l; -        pa_log(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" -               ", falling back to unsecure pseudo RNG.\n", strerror(errno)); +    assert(fd >= 0 && ret_data && length); -        srandom(time(NULL)); -         -        for (p = data, l = length; l > 0; p++, l--) -            *p = (uint8_t) random(); -    } +    pa_random(ret_data, length);      lseek(fd, 0, SEEK_SET);      ftruncate(fd, 0); -    if ((r = pa_loop_write(fd, data, length)) < 0 || (size_t) r != length) { +    if ((r = pa_loop_write(fd, ret_data, length)) < 0 || (size_t) r != length) {          pa_log(__FILE__": failed to write cookie file: %s\n", strerror(errno)); -        goto finish; +        return -1;      } -    ret = 0; - -finish: - -    if (random_fd >= 0) -        close(random_fd); - -    return ret; +    return 0;  }  /* Load an euthorization cookie from file fn and store it in data. If diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 629b28e2..dd40add2 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -59,6 +59,7 @@ char *pa_client_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_client *client;      uint32_t index = PA_IDXSET_INVALID; +    char tid[5];      assert(c);      s = pa_strbuf_new(); @@ -67,7 +68,7 @@ char *pa_client_list_to_string(struct pa_core *c) {      pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_ncontents(c->clients));      for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) { -        pa_strbuf_printf(s, "    index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); +        pa_strbuf_printf(s, "    index: %u\n\tname: <%s>\n\ttype: <%s>\n", client->index, client->name, pa_typeid_to_string(client->typeid, tid, sizeof(tid)));          if (client->owner)              pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); @@ -80,6 +81,7 @@ char *pa_sink_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_sink *sink;      uint32_t index = PA_IDXSET_INVALID; +    char tid[5];      assert(c);      s = pa_strbuf_new(); @@ -93,9 +95,10 @@ char *pa_sink_list_to_string(struct pa_core *c) {          assert(sink->monitor_source);          pa_strbuf_printf(              s, -            "  %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", +            "  %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n",              c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',              sink->index, sink->name, +            pa_typeid_to_string(sink->typeid, tid, sizeof(tid)),              (unsigned) sink->volume,              pa_volume_to_dB(sink->volume),              (float) pa_sink_get_latency(sink), @@ -115,6 +118,7 @@ char *pa_source_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_source *source;      uint32_t index = PA_IDXSET_INVALID; +    char tid[5];      assert(c);      s = pa_strbuf_new(); @@ -125,10 +129,11 @@ char *pa_source_list_to_string(struct pa_core *c) {      for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) {          char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];          pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); -        pa_strbuf_printf(s, "  %c index: %u\n\tname: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", +        pa_strbuf_printf(s, "  %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n",                           c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ',                           source->index,                           source->name, +                         pa_typeid_to_string(source->typeid, tid, sizeof(tid)),                           (float) pa_source_get_latency(source),                           ss); @@ -148,6 +153,7 @@ char *pa_source_output_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_source_output *o;      uint32_t index = PA_IDXSET_INVALID; +    char tid[5];      static const char* const state_table[] = {          "RUNNING",          "CORKED", @@ -170,9 +176,10 @@ char *pa_source_output_list_to_string(struct pa_core *c) {              rm = "invalid";          pa_strbuf_printf( -            s, "  index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", +            s, "  index: %u\n\tname: '%s'\n\ttype: <%s>\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n",              o->index,              o->name, +            pa_typeid_to_string(o->typeid, tid, sizeof(tid)),              state_table[o->state],              o->source->index, o->source->name,              ss, @@ -190,6 +197,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_sink_input *i;      uint32_t index = PA_IDXSET_INVALID; +    char tid[5];      static const char* const state_table[] = {          "RUNNING",          "CORKED", @@ -212,9 +220,10 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {          pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);          assert(i->sink);          pa_strbuf_printf( -            s, "    index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", +            s, "    index: %u\n\tname: <%s>\n\ttype: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n",              i->index,              i->name, +            pa_typeid_to_string(i->typeid, tid, sizeof(tid)),              state_table[i->state],              i->sink->index, i->sink->name,              (unsigned) i->volume, diff --git a/polyp/cli.c b/polyp/cli.c index 4d4342bf..16323cba 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -45,6 +45,7 @@  #include "log.h"  #define PROMPT ">>> " +#define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_')  struct pa_cli {      struct pa_core *core; @@ -75,7 +76,7 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct      c->eof_callback = NULL;      pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); -    c->client = pa_client_new(core, "CLI", cname); +    c->client = pa_client_new(core, PA_TYPEID_CLI, cname);      assert(c->client);      c->client->kill = client_kill;      c->client->userdata = c; diff --git a/polyp/client.c b/polyp/client.c index 40f5e385..8c7f4800 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -33,7 +33,7 @@  #include "subscribe.h"  #include "log.h" -struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name, char *name) { +struct pa_client *pa_client_new(struct pa_core *core, pa_typeid_t typeid, const char *name) {      struct pa_client *c;      int r;      assert(core); @@ -42,7 +42,7 @@ struct pa_client *pa_client_new(struct pa_core *core, const char *protocol_name,      c->name = pa_xstrdup(name);      c->owner = NULL;      c->core = core; -    c->protocol_name = pa_xstrdup(protocol_name); +    c->typeid = typeid;      c->kill = NULL;      c->userdata = NULL; @@ -68,7 +68,6 @@ void pa_client_free(struct pa_client *c) {      pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name);      pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);      pa_xfree(c->name); -    pa_xfree(c->protocol_name);      pa_xfree(c);  } diff --git a/polyp/client.h b/polyp/client.h index 324bb27c..2a3a09e0 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -24,6 +24,7 @@  #include "core.h"  #include "module.h" +#include "typeid.h"  /* Every connection to the server should have a pa_client   * attached. That way the user may generate a listing of all connected @@ -31,18 +32,17 @@  struct pa_client {      uint32_t index; +    pa_typeid_t typeid;      struct pa_module *owner;      char *name;      struct pa_core *core; -    char *protocol_name;      void (*kill)(struct pa_client *c);      void *userdata;  }; -/* Protocol name should be something like "ESOUND", "NATIVE", ... */ -struct pa_client *pa_client_new(struct pa_core *c, const char *protocol_name, char *name); +struct pa_client *pa_client_new(struct pa_core *c, pa_typeid_t typeid, const char *name);  /* This function should be called only by the code that created the client */  void pa_client_free(struct pa_client *c); diff --git a/polyp/core.c b/polyp/core.c index 03682fdc..c213faa0 100644 --- a/polyp/core.c +++ b/polyp/core.c @@ -39,6 +39,7 @@  #include "xmalloc.h"  #include "subscribe.h"  #include "props.h" +#include "random.h"  struct pa_core* pa_core_new(struct pa_mainloop_api *m) {      struct pa_core* c; @@ -84,9 +85,10 @@ struct pa_core* pa_core_new(struct pa_mainloop_api *m) {      c->resample_method = PA_RESAMPLER_SRC_SINC_FASTEST;      pa_property_init(c); + +    pa_random(&c->cookie, sizeof(c->cookie));      pa_check_signal_is_blocked(SIGPIPE); -          return c;  } diff --git a/polyp/core.h b/polyp/core.h index 6c6070b1..36604424 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -34,6 +34,10 @@   * variables for the daemon. */  struct pa_core { +    /* A random value which may be used to identify this instance of +     * polypaudio. Not cryptographically secure in any way. */ +    uint32_t cookie; +          struct pa_mainloop_api *mainloop;      /* idxset of all kinds of entities */ diff --git a/polyp/endianmacros.h b/polyp/endianmacros.h index 75c0af0a..00b992db 100644 --- a/polyp/endianmacros.h +++ b/polyp/endianmacros.h @@ -31,32 +31,44 @@  #define INT16_SWAP(x) ((int16_t)(((int16_t) x >> 8) | ((int16_t) x << 8)))  #define UINT16_SWAP(x) ((uint16_t)(((uint16_t) x >> 8) | ((uint16_t) x << 8)))  #define INT32_SWAP(x) ((int32_t)(((int32_t) x >> 24) | ((int32_t) x << 24) | (((int32_t) x & 0xFF00) << 16) | (((int32_t) x) >> 16) & 0xFF00)) -#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | (((uint32_t) x) >> 16) & 0xFF00)) +#define UINT32_SWAP(x) ((uint32_t)(((uint32_t) x >> 24) | ((uint32_t) x << 24) | (((uint32_t) x & 0xFF00) << 16) | ((((uint32_t) x) >> 16) & 0xFF00)))  #ifdef WORDS_BIGENDIAN   #define INT16_FROM_LE(x) INT16_SWAP(x)   #define INT16_FROM_BE(x) ((int16_t)(x)) +   #define INT16_TO_LE(x) INT16_SWAP(x)   #define INT16_TO_BE(x) ((int16_t)(x))   #define UINT16_FROM_LE(x) UINT16_SWAP(x)   #define UINT16_FROM_BE(x) ((uint16_t)(x)) +   #define INT32_FROM_LE(x) INT32_SWAP(x)   #define INT32_FROM_BE(x) ((int32_t)(x)) +   #define UINT32_FROM_LE(x) UINT32_SWAP(x)   #define UINT32_FROM_BE(x) ((uint32_t)(x)) + + #define UINT32_TO_LE(x) UINT32_SWAP(x) + #define UINT32_TO_BE(x) ((uint32_t)(x))  #else   #define INT16_FROM_LE(x) ((int16_t)(x))   #define INT16_FROM_BE(x) INT16_SWAP(x) +   #define INT16_TO_LE(x) ((int16_t)(x))   #define INT16_TO_BE(x) INT16_SWAP(x)   #define UINT16_FROM_LE(x) ((uint16_t)(x))   #define UINT16_FROM_BE(x) UINT16_SWAP(x) +   #define INT32_FROM_LE(x) ((int32_t)(x))   #define INT32_FROM_BE(x) INT32_SWAP(x) +   #define UINT32_FROM_LE(x) ((uint32_t)(x))   #define UINT32_FROM_BE(x) UINT32_SWAP(x) + + #define UINT32_TO_LE(x) ((uint32_t)(x)) + #define UINT32_TO_BE(x) UINT32_SWAP(x)  #endif  #endif diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index daf71d71..3fb221fa 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -25,7 +25,7 @@  #include <sys/time.h>  #include <time.h> -#include "cdecl.h" +#include <polyp/cdecl.h>  /** \file   *  diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index d7a1cb53..9933d37a 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -46,6 +46,8 @@ PA_MODULE_DESCRIPTION("ALSA Sink")  PA_MODULE_VERSION(PACKAGE_VERSION)  PA_MODULE_USAGE("sink_name=<name for the sink> device=<ALSA device> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>") +#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') +  struct userdata {      snd_pcm_t *pcm_handle;      struct pa_sink *sink; @@ -212,7 +214,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {          goto fail;      } -    u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); +    u->sink = pa_sink_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);      assert(u->sink);      u->sink->get_latency = sink_get_latency_cb; diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 56eb1455..67e38a1d 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -46,6 +46,8 @@ PA_MODULE_DESCRIPTION("ALSA Source")  PA_MODULE_VERSION(PACKAGE_VERSION)  PA_MODULE_USAGE("source_name=<name for the source> device=<ALSA device> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>") +#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') +  struct userdata {      snd_pcm_t *pcm_handle;      struct pa_source *source; @@ -203,7 +205,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {          goto fail;      } -    u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); +    u->source = pa_source_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);      assert(u->source);      u->source->userdata = u; diff --git a/polyp/module-combine.c b/polyp/module-combine.c index 7b3c26dd..ca79d7df 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -43,6 +43,8 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one")  PA_MODULE_VERSION(PACKAGE_VERSION)  PA_MODULE_USAGE("sink_name=<name for the sink> master=<master sink> slaves=<slave sinks> adjust_time=<seconds> resample_method=<method>") +#define PA_TYPEID_COMBINE PA_TYPEID_MAKE('C', 'M', 'B', 'N') +  #define DEFAULT_SINK_NAME "combined"  #define MEMBLOCKQ_MAXLENGTH (1024*170)  #define RENDER_SIZE (1024*10) @@ -214,7 +216,7 @@ static struct output *output_new(struct userdata *u, struct pa_sink *sink, int r      o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat);      snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); -    if (!(o->sink_input = pa_sink_input_new(sink, t, &u->sink->sample_spec, 1, resample_method))) +    if (!(o->sink_input = pa_sink_input_new(sink, PA_TYPEID_COMBINE, t, &u->sink->sample_spec, 1, resample_method)))          goto fail;      o->sink_input->get_latency = sink_input_get_latency_cb; @@ -325,7 +327,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {          goto fail;      } -    if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { +    if (!(u->sink = pa_sink_new(c, PA_TYPEID_COMBINE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) {          pa_log(__FILE__": failed to create sink\n");          goto fail;      } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index 2cc61440..82c38cc2 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -52,6 +52,8 @@ PA_MODULE_USAGE("sink_name=<name for the sink> server=<address> cookie=<filename  #define DEFAULT_SINK_NAME "esound_output" +#define PA_TYPEID_ESOUND_SINK PA_TYPEID_MAKE('E', 'S', 'D', 'S') +  struct userdata {      struct pa_core *core; @@ -352,7 +354,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      u->state = STATE_AUTH;      u->latency = 0; -    if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { +    if (!(u->sink = pa_sink_new(c, PA_TYPEID_ESOUND_SINK, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create sink.\n");          goto fail;      } diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index 6d4ea89b..fcac1ea4 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -49,6 +49,8 @@ PA_MODULE_USAGE("format=<sample format> channels=<number of channels> rate=<samp  #define DEFAULT_SINK_NAME "null" +#define PA_TYPEID_NULL PA_TYPEID_MAKE('N', 'U', 'L', 'L') +  struct userdata {      struct pa_core *core;      struct pa_module *module; @@ -106,7 +108,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      u->module = m;      m->userdata = u; -    if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { +    if (!(u->sink = pa_sink_new(c, PA_TYPEID_NULL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create sink.\n");          goto fail;      } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index 6fe4fa0c..3c5c0ad8 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -53,6 +53,8 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)")  PA_MODULE_VERSION(PACKAGE_VERSION)  PA_MODULE_USAGE("sink_name=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>") +#define PA_TYPEID_OSS_MMAP PA_TYPEID_MAKE('O', 'S', 'S', 'M') +  struct userdata {      struct pa_sink *sink;      struct pa_source *source; @@ -302,7 +304,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {              }          } else { -            u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); +            u->source = pa_source_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec);              assert(u->source);              u->source->userdata = u;              pa_source_set_owner(u->source, m); @@ -334,7 +336,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {          } else {              pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); -            u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); +            u->sink = pa_sink_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec);              assert(u->sink);              u->sink->get_latency = sink_get_latency_cb;              u->sink->userdata = u; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index fa01876d..67922d82 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -52,6 +52,8 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source")  PA_MODULE_VERSION(PACKAGE_VERSION)  PA_MODULE_USAGE("sink_name=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<fragment size>") +#define PA_TYPEID_OSS PA_TYPEID_MAKE('O', 'S', 'S', '_') +  struct userdata {      struct pa_sink *sink;      struct pa_source *source; @@ -325,7 +327,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      }      if (mode != O_WRONLY) { -        u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); +        u->source = pa_source_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);          assert(u->source);          u->source->userdata = u;          u->source->get_latency = source_get_latency_cb; @@ -335,7 +337,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {          u->source = NULL;      if (mode != O_RDONLY) { -        u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); +        u->sink = pa_sink_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss);          assert(u->sink);          u->sink->get_latency = sink_get_latency_cb;          u->sink->userdata = u; diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 6c441cc8..b6d8dc2e 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -50,6 +50,8 @@ PA_MODULE_USAGE("sink_name=<name for the sink> file=<path of the FIFO> format=<s  #define DEFAULT_FIFO_NAME "/tmp/music.output"  #define DEFAULT_SINK_NAME "fifo_output" +#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') +  struct userdata {      struct pa_core *core; @@ -175,7 +177,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      u->module = m;      m->userdata = u; -    if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { +    if (!(u->sink = pa_sink_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create sink.\n");          goto fail;      } diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index e8a17b96..5a397162 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -50,6 +50,8 @@ PA_MODULE_USAGE("source_name=<name for the source> file=<path of the FIFO> forma  #define DEFAULT_FIFO_NAME "/tmp/music.input"  #define DEFAULT_SOURCE_NAME "fifo_input" +#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') +  struct userdata {      struct pa_core *core; @@ -152,7 +154,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      u->filename = pa_xstrdup(p);      u->core = c; -    if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { +    if (!(u->source = pa_source_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create source.\n");          goto fail;      } diff --git a/polyp/module-sine.c b/polyp/module-sine.c index 83414821..d8f7e4ef 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -40,6 +40,8 @@ PA_MODULE_DESCRIPTION("Sine wave generator")  PA_MODULE_USAGE("sink=<sink to connect to> frequency=<frequency in Hz>")  PA_MODULE_VERSION(PACKAGE_VERSION) +#define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E') +  struct userdata {      struct pa_core *core;      struct pa_module *module; @@ -140,7 +142,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      calc_sine(u->memblock->data, u->memblock->length, frequency);      snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); -    if (!(u->sink_input = pa_sink_input_new(sink, t, &ss, 0, -1))) +    if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SINE, t, &ss, 0, -1)))          goto fail;      u->sink_input->peek = sink_input_peek; diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index d165aab8..9da87b3d 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -60,6 +60,8 @@ PA_MODULE_USAGE("server=<address> source=<remote source name> cookie=<filename>  PA_MODULE_AUTHOR("Lennart Poettering")  PA_MODULE_VERSION(PACKAGE_VERSION) +#define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L') +  #define DEFAULT_SINK_NAME "tunnel"  #define DEFAULT_SOURCE_NAME "tunnel" @@ -624,7 +626,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      pa_socket_client_set_callback(u->client, on_connection, u);  #ifdef TUNNEL_SINK -    if (!(u->sink = pa_sink_new(c, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { +    if (!(u->sink = pa_sink_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create sink.\n");          goto fail;      } @@ -636,7 +638,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) {      pa_sink_set_owner(u->sink, m);  #else -    if (!(u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { +    if (!(u->source = pa_source_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) {          pa_log(__FILE__": failed to create source.\n");          goto fail;      } diff --git a/polyp/module-zeroconf-publish.c b/polyp/module-zeroconf-publish.c index 363c2419..c88ac766 100644 --- a/polyp/module-zeroconf-publish.c +++ b/polyp/module-zeroconf-publish.c @@ -40,6 +40,7 @@  #include "log.h"  #include "subscribe.h"  #include "dynarray.h" +#include "endianmacros.h"  PA_MODULE_AUTHOR("Lennart Poettering")  PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher") @@ -79,21 +80,36 @@ static sw_result publish_reply(sw_discovery discovery, sw_discovery_publish_stat      return SW_OKAY;  } -static void get_service_sample_spec(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss) { -    assert(u && s && s->loaded.valid && ret_ss); +static void get_service_data(struct userdata *u, struct service *s, struct pa_sample_spec *ret_ss, char **ret_description, pa_typeid_t *ret_typeid) { +    assert(u && s && s->loaded.valid && ret_ss && ret_description && ret_typeid);      if (s->loaded.type == PA_NAMEREG_SINK) {          struct pa_sink *sink = pa_idxset_get_by_index(u->core->sinks, s->loaded.index);          assert(sink);          *ret_ss = sink->sample_spec; +        *ret_description = sink->description; +        *ret_typeid = sink->typeid;      } else if (s->loaded.type == PA_NAMEREG_SOURCE) {          struct pa_source *source = pa_idxset_get_by_index(u->core->sources, s->loaded.index);          assert(source);          *ret_ss = source->sample_spec; +        *ret_description = source->description; +        *ret_typeid = source->typeid;      } else          assert(0);  } +static void txt_record_server_data(struct pa_core *c, sw_text_record t) { +    char s[256]; +    assert(c); + +    sw_text_record_add_key_and_string_value(t, "server-version", PACKAGE_NAME" "PACKAGE_VERSION); +    sw_text_record_add_key_and_string_value(t, "user-name", pa_get_user_name(s, sizeof(s))); +    sw_text_record_add_key_and_string_value(t, "fqdn", pa_get_fqdn(s, sizeof(s))); +    snprintf(s, sizeof(s), "0x%08x", c->cookie); +    sw_text_record_add_key_and_string_value(t, "cookie", s); +} +  static int publish_service(struct userdata *u, struct service *s) {      assert(u && s);      char t[256]; @@ -120,18 +136,27 @@ static int publish_service(struct userdata *u, struct service *s) {      free_txt = 1;      sw_text_record_add_key_and_string_value(txt, "device", s->name); + +    txt_record_server_data(u->core, txt);      if (s->loaded.valid) { -        char z[64]; +        char z[64], *description; +        pa_typeid_t typeid;          struct pa_sample_spec ss; -        get_service_sample_spec(u, s, &ss); +        get_service_data(u, s, &ss, &description, &typeid);          snprintf(z, sizeof(z), "%u", ss.rate);          sw_text_record_add_key_and_string_value(txt, "rate", z);          snprintf(z, sizeof(z), "%u", ss.channels);          sw_text_record_add_key_and_string_value(txt, "channels", z);          sw_text_record_add_key_and_string_value(txt, "format", pa_sample_format_to_string(ss.format)); + +        sw_text_record_add_key_and_string_value(txt, "description", description); + +        snprintf(z, sizeof(z), "0x%8x", typeid); +        sw_text_record_add_key_and_string_value(txt, "typeid", z); +                  if (sw_discovery_publish(pa_howl_wrapper_get_discovery(u->howl_wrapper), 0, t,                                   s->loaded.type == PA_NAMEREG_SINK ? SERVICE_NAME_SINK : SERVICE_NAME_SOURCE, diff --git a/polyp/pabrowse.c b/polyp/pabrowse.c new file mode 100644 index 00000000..ccea0cd4 --- /dev/null +++ b/polyp/pabrowse.c @@ -0,0 +1,139 @@ +/* $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 <config.h> +#endif + +#include <stdio.h> +#include <assert.h> +#include <signal.h> + +#include <polyp/mainloop.h> +#include <polyp/mainloop-signal.h> +#include <polyp/polyplib-browser.h> +#include <polyp/typeid.h> + +static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { +    fprintf(stderr, "Got signal, exiting\n"); +    m->quit(m, 0); +} + +static void dump_server(const struct pa_browse_info *i) { +    char t[16]; + +    if (i->cookie) +        snprintf(t, sizeof(t), "0x%08x", *i->cookie); +     +    printf("server: %s\n" +           "server-version: %s\n" +           "user-name: %s\n" +           "fqdn: %s\n" +           "cookie: %s\n", +           i->server, +           i->server_version ? i->server_version : "n/a", +           i->user_name ? i->user_name : "n/a", +           i->fqdn ? i->fqdn : "n/a", +           i->cookie ? t : "n/a"); +} + +static void dump_device(const struct pa_browse_info *i) { +    char t[16], ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + +    if (i->sample_spec) +        pa_sample_spec_snprint(ss, sizeof(ss), i->sample_spec); + +    if (i->typeid) +        pa_typeid_to_string(*i->typeid, t, sizeof(t)); +     +    printf("device: %s\n" +           "description: %s\n" +           "type: %s\n" +           "sample spec: %s\n", +           i->device, +           i->description ? i->description : "n/a", +           i->typeid ? t : "n/a", +           i->sample_spec ? ss : "n/a"); +            +} + +static void browser_callback(struct pa_browser *b, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata) { +    assert(b && i); + +    switch (c) { + +        case PA_BROWSE_NEW_SERVER: +            printf("\n=> new server <%s>\n", i->name); +            dump_server(i); +            break; + +        case PA_BROWSE_NEW_SINK: +            printf("\n=> new sink <%s>\n", i->name); +            dump_server(i); +            dump_device(i); +            break; + +        case PA_BROWSE_NEW_SOURCE: +            printf("\n=> new source <%s>\n", i->name); +            dump_server(i); +            dump_device(i); +            break; +             +        case PA_BROWSE_REMOVE: +            printf("\n=> removed service <%s>\n", i->name); +            break; +             +        default: +            ; +    } +} + + +int main(int argc, char *argv[]) { +    struct pa_mainloop *mainloop = NULL; +    struct pa_browser *browser = NULL; +    int ret = 1, r; + +    if (!(mainloop = pa_mainloop_new())) +        goto finish; + +    r = pa_signal_init(pa_mainloop_get_api(mainloop)); +    assert(r == 0); +    pa_signal_new(SIGINT, exit_signal_callback, NULL); +    pa_signal_new(SIGTERM, exit_signal_callback, NULL); +    signal(SIGPIPE, SIG_IGN); +     +    if (!(browser = pa_browser_new(pa_mainloop_get_api(mainloop)))) +        goto finish; + +    pa_browser_set_callback(browser, browser_callback, NULL); +     +    ret = 0; +    pa_mainloop_run(mainloop, &ret); + +finish: +    if (mainloop) { +        pa_signal_done(); +        pa_mainloop_free(mainloop); +    } + +    return ret; +} diff --git a/polyp/pacat.c b/polyp/pacat.c index 8c3ee0ba..5910d13f 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -38,7 +38,7 @@  #include <polyp/mainloop-signal.h>  #include <polyp/polyplib-version.h> -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8  #error Invalid Polypaudio API version  #endif @@ -290,7 +290,7 @@ static void stdout_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int  /* UNIX signal to quit recieved */  static void exit_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {      if (verbose) -        fprintf(stderr, "Got SIGINT, exiting.\n"); +        fprintf(stderr, "Got signal, exiting.\n");      quit(0);  } @@ -479,6 +479,7 @@ int main(int argc, char *argv[]) {      r = pa_signal_init(mainloop_api);      assert(r == 0);      pa_signal_new(SIGINT, exit_signal_callback, NULL); +    pa_signal_new(SIGTERM, exit_signal_callback, NULL);      pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);      signal(SIGPIPE, SIG_IGN); diff --git a/polyp/pactl.c b/polyp/pactl.c index 6300b656..d4dc6ad1 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,7 +41,7 @@  #include <polyp/mainloop-signal.h>  #include <polyp/sample.h> -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8  #error Invalid Polypaudio API version  #endif @@ -134,20 +134,22 @@ static void get_server_info_callback(struct pa_context *c, const struct pa_serve             "Server Version: %s\n"             "Default Sample Specification: %s\n"             "Default Sink: %s\n" -           "Default Source: %s\n", +           "Default Source: %s\n" +           "Cookie: %08x\n",             i->user_name,             i->host_name,             i->server_name,             i->server_version,             s,             i->default_sink_name, -           i->default_source_name); +           i->default_source_name, +           i->cookie);      complete_action();  }  static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata) { -    char s[PA_SAMPLE_SPEC_SNPRINT_MAX]; +    char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];      if (is_last < 0) {          fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); @@ -170,6 +172,7 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in      printf("*** Sink #%u ***\n"             "Name: %s\n" +           "Type: %s\n"             "Description: %s\n"             "Sample Specification: %s\n"             "Owner Module: %u\n" @@ -178,16 +181,18 @@ static void get_sink_info_callback(struct pa_context *c, const struct pa_sink_in             "Latency: %0.0f usec\n",             i->index,             i->name, +           pa_typeid_to_string(i->typeid, tid, sizeof(tid)),             i->description,             s,             i->owner_module,             i->volume, pa_volume_to_dB(i->volume),             i->monitor_source,             (double) i->latency); +  }  static void get_source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata) { -    char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32]; +    char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5];      if (is_last < 0) {          fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); @@ -212,18 +217,21 @@ static void get_source_info_callback(struct pa_context *c, const struct pa_sourc      printf("*** Source #%u ***\n"             "Name: %s\n" +           "Type: %s\n"             "Description: %s\n"             "Sample Specification: %s\n"             "Owner Module: %u\n"             "Monitor of Sink: %s\n"             "Latency: %0.0f usec\n",             i->index, +           pa_typeid_to_string(i->typeid, tid, sizeof(tid)),             i->name,             i->description,             s,             i->owner_module,             i->monitor_of_sink != PA_INVALID_INDEX ? t : "no",             (double) i->latency); +      }  static void get_module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata) { @@ -261,7 +269,7 @@ static void get_module_info_callback(struct pa_context *c, const struct pa_modul  }  static void get_client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata) { -    char t[32]; +    char t[32], tid[5];      if (is_last < 0) {          fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); @@ -284,16 +292,16 @@ static void get_client_info_callback(struct pa_context *c, const struct pa_clien      printf("*** Client #%u ***\n"             "Name: %s\n" -           "Owner Module: %s\n" -           "Protocol Name: %s\n", +           "Type: %s\n" +           "Owner Module: %s\n",             i->index,             i->name, -           i->owner_module != PA_INVALID_INDEX ? t : "n/a", -           i->protocol_name); +           pa_typeid_to_string(i->typeid, tid, sizeof(tid)), +           i->owner_module != PA_INVALID_INDEX ? t : "n/a");  }  static void get_sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { -    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; +    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];      if (is_last < 0) {          fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); @@ -318,6 +326,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s      printf("*** Sink Input #%u ***\n"             "Name: %s\n" +           "Type: %s\n"             "Owner Module: %s\n"             "Client: %s\n"             "Sink: %u\n" @@ -328,6 +337,7 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s             "Resample method: %s\n",             i->index,             i->name, +           pa_typeid_to_string(i->typeid, tid, sizeof(tid)),             i->owner_module != PA_INVALID_INDEX ? t : "n/a",             i->client != PA_INVALID_INDEX ? k : "n/a",             i->sink, @@ -338,8 +348,9 @@ static void get_sink_input_info_callback(struct pa_context *c, const struct pa_s             i->resample_method ? i->resample_method : "n/a");  } +  static void get_source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata) { -    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; +    char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5];      if (is_last < 0) {          fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); @@ -364,6 +375,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p      printf("*** Source Output #%u ***\n"             "Name: %s\n" +           "Type: %s\n"             "Owner Module: %s\n"             "Client: %s\n"             "Source: %u\n" @@ -373,6 +385,7 @@ static void get_source_output_info_callback(struct pa_context *c, const struct p             "Resample method: %s\n",             i->index,             i->name, +           pa_typeid_to_string(i->typeid, tid, sizeof(tid)),             i->owner_module != PA_INVALID_INDEX ? t : "n/a",             i->client != PA_INVALID_INDEX ? k : "n/a",             i->source, diff --git a/polyp/paplay.c b/polyp/paplay.c index 0faa0ff2..2eaf07c1 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -40,7 +40,7 @@  #include <polyp/mainloop-signal.h>  #include <polyp/polyplib-version.h> -#if PA_API_VERSION != 7 +#if PA_API_VERSION != 8  #error Invalid Polypaudio API version  #endif diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index 1b611db4..c7a85454 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -32,6 +32,8 @@  #include "sink-input.h"  #include "xmalloc.h" +#define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K') +  static void sink_input_kill(struct pa_sink_input *i) {      struct pa_memchunk *c;      assert(i && i->userdata); @@ -88,7 +90,7 @@ int pa_play_memchunk(struct pa_sink *sink, const char *name, const struct pa_sam      if (volume <= 0)          return 0; -    if (!(si = pa_sink_input_new(sink, name, ss, 0, -1))) +    if (!(si = pa_sink_input_new(sink, PA_TYPEID_MEMCHUNK, name, ss, 0, -1)))          return -1;      si->volume = volume; diff --git a/polyp/polyplib-browser.c b/polyp/polyplib-browser.c new file mode 100644 index 00000000..a1bd3fb7 --- /dev/null +++ b/polyp/polyplib-browser.c @@ -0,0 +1,307 @@ +/* $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. +***/ + +#include <assert.h> +#include <howl.h> + +#include "polyplib-browser.h" +#include "xmalloc.h" +#include "log.h" +#include "util.h" + +#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." +#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." +#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." + +struct pa_browser { +    int ref; +    struct pa_mainloop_api *mainloop; + +    void (*callback)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata); +    void *callback_userdata; +     +    sw_discovery discovery; +    struct pa_io_event *io_event; +}; + + +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event*e, int fd, enum pa_io_event_flags events, void *userdata) { +    struct pa_browser *b = userdata; +    assert(a && b && b->mainloop == a); + +    if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { +        pa_log(__FILE__": connection to HOWL daemon failed.\n"); +        b->mainloop->io_free(b->io_event); +        b->io_event = NULL; +        return; +    } +} + + +static sw_result resolve_reply( +    sw_discovery discovery, +    sw_discovery_oid oid, +    sw_uint32 interface_index, +    sw_const_string name, +    sw_const_string type, +    sw_const_string domain, +    sw_ipv4_address address, +    sw_port port, +    sw_octets text_record, +    sw_ulong text_record_len, +    sw_opaque extra) { +     +    struct pa_browser *b = extra; +    struct pa_browse_info i; +    char ip[256], a[256]; +    enum pa_browse_opcode opcode; +    int device_found = 0; +    uint32_t cookie; +    pa_typeid_t typeid; +    struct pa_sample_spec ss; +    int ss_valid = 0; +    sw_text_record_iterator iterator; +    int free_iterator = 0; +    char *c = NULL; +     +    assert(b); + +    sw_discovery_cancel(discovery, oid); + +    memset(&i, 0, sizeof(i)); +    i.name = name; +         +    if (!b->callback) +        goto fail; +     +    if (!strcmp(type, SERVICE_NAME_SINK)) +        opcode = PA_BROWSE_NEW_SINK; +    else if (!strcmp(type, SERVICE_NAME_SOURCE)) +        opcode = PA_BROWSE_NEW_SOURCE; +    else if (!strcmp(type, SERVICE_NAME_SERVER)) +        opcode = PA_BROWSE_NEW_SERVER; +    else +        goto fail; +     + +    snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); +    i.server = a; +     +    if (text_record && text_record_len) { +        char key[SW_TEXT_RECORD_MAX_LEN]; +        uint8_t val[SW_TEXT_RECORD_MAX_LEN]; +        uint32_t val_len; +   +        if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { +            pa_log("sw_text_record_string_iterator_init() failed.\n"); +            goto fail; +        } + +        free_iterator = 1; +         +        while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { +            c = pa_xstrndup((char*) val, val_len); +             +            if (!strcmp(key, "device")) { +                device_found = 1; +                pa_xfree((char*) i.device); +                i.device = c; +                c = NULL; +            } else if (!strcmp(key, "server-version")) { +                pa_xfree((char*) i.server_version); +                i.server_version = c; +                c = NULL; +            } else if (!strcmp(key, "user-name")) { +                pa_xfree((char*) i.user_name); +                i.user_name = c; +                c = NULL; +            } else if (!strcmp(key, "fqdn")) { +                pa_xfree((char*) i.fqdn); +                i.fqdn = c; +                c = NULL; +            } else if (!strcmp(key, "cookie")) { + +                if (pa_atou(c, &cookie) < 0) +                    goto fail; +                 +                i.cookie = &cookie; +            } else if (!strcmp(key, "description")) { +                pa_xfree((char*) i.description); +                i.description = c; +                c = NULL; +            } else if (!strcmp(key, "typeid")) { + +                if (pa_atou(c, &typeid) < 0) +                    goto fail; + +                i.typeid = &typeid; +            } else if (!strcmp(key, "channels")) { +                uint32_t ch; +                 +                if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) +                    goto fail; + +                ss.channels = (uint8_t) ch; +                ss_valid |= 1; + +            } else if (!strcmp(key, "rate")) { +                if (pa_atou(c, &ss.rate) < 0) +                    goto fail; +                ss_valid |= 2; +            } else if (!strcmp(key, "format")) { + +                if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) +                    goto fail; +                 +                ss_valid |= 4; +            } + +            pa_xfree(c); +            c = NULL; +        } +         +    } + +    /* No device txt record was sent for a sink or source service */ +    if (opcode != PA_BROWSE_NEW_SERVER && !device_found)  +        goto fail; + +    if (ss_valid == 7) +        i.sample_spec = &ss; +     + +    b->callback(b, opcode, &i, b->callback_userdata); + +fail: +    pa_xfree((void*) i.device); +    pa_xfree((void*) i.fqdn); +    pa_xfree((void*) i.server_version); +    pa_xfree((void*) i.user_name); +    pa_xfree((void*) i.description); +    pa_xfree(c); + +    if (free_iterator) +        sw_text_record_iterator_fina(iterator); + +     +    return SW_OKAY; +} + +static sw_result browse_reply( +    sw_discovery discovery, +    sw_discovery_oid id, +    sw_discovery_browse_status status, +    sw_uint32 interface_index, +    sw_const_string name, +    sw_const_string type, +    sw_const_string domain, +    sw_opaque extra) { +     +    struct pa_browser *b = extra; +    assert(b); + +    switch (status) { +        case SW_DISCOVERY_BROWSE_ADD_SERVICE: { +            sw_discovery_oid oid; +            fprintf(stderr, "debug: new service: %s\n", name); + +            if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) +                pa_log("sw_discovery_resolve() failed\n"); + +            break; +        } +             +        case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: +            if (b->callback) { +                struct pa_browse_info i; +                memset(&i, 0, sizeof(i)); +                i.name = name; +                b->callback(b, PA_BROWSE_REMOVE, &i, b->callback_userdata); +            } +            break; + +        default: +            ; +    } + +    return SW_OKAY; +} + +struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop) { +    struct pa_browser *b; +    sw_discovery_oid oid; + +    b = pa_xmalloc(sizeof(struct pa_browser)); +    b->mainloop = mainloop; +    b->ref = 1; +    b->callback = NULL; +    b->callback_userdata = NULL; + +    if (sw_discovery_init(&b->discovery) != SW_OKAY) { +        pa_log("sw_discovery_init() failed.\n"); +        pa_xfree(b); +        return NULL; +    } +     +    if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || +        sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || +        sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { + +        pa_log("sw_discovery_browse() failed.\n"); +         +        sw_discovery_fina(b->discovery); +        pa_xfree(b); +        return NULL; +    } +     +    b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); +    return b; +} + +static void browser_free(struct pa_browser *b) { +    assert(b && b->mainloop); + +    if (b->io_event) +        b->mainloop->io_free(b->io_event); +     +    sw_discovery_fina(b->discovery); +    pa_xfree(b); +} + +struct pa_browser *pa_browser_ref(struct pa_browser *b) { +    assert(b && b->ref >= 1); +    b->ref++; +    return b; +} + +void pa_browser_unref(struct pa_browser *b) { +    assert(b && b->ref >= 1); + +    if ((-- (b->ref)) <= 0) +        browser_free(b); +} + +void pa_browser_set_callback(struct pa_browser *b, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void* userdata), void *userdata) { +    assert(b); + +    b->callback = cb; +    b->callback_userdata = userdata; +} diff --git a/polyp/polyplib-browser.h b/polyp/polyplib-browser.h new file mode 100644 index 00000000..c13eff22 --- /dev/null +++ b/polyp/polyplib-browser.h @@ -0,0 +1,65 @@ +#ifndef foopolyplibbrowserhfoo +#define foopolyplibbrowserhfoo + +/* $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. +***/ + +#include <polyp/mainloop-api.h> +#include <polyp/sample.h> +#include <polyp/cdecl.h> +#include <polyp/typeid.h> + +PA_C_DECL_BEGIN + +struct pa_browser; + +enum pa_browse_opcode { +    PA_BROWSE_NEW_SERVER, +    PA_BROWSE_NEW_SINK, +    PA_BROWSE_NEW_SOURCE, +    PA_BROWSE_REMOVE +}; + +struct pa_browser *pa_browser_new(struct pa_mainloop_api *mainloop); +struct pa_browser *pa_browser_ref(struct pa_browser *z); +void pa_browser_unref(struct pa_browser *z); + +struct pa_browse_info { +    /* Unique service name */ +    const char *name;  /* always available */ + +    /* Server info */ +    const char *server; /* always available */ +    const char *server_version, *user_name, *fqdn; /* optional */ +    const uint32_t *cookie;  /* optional */ + +    /* Device info */ +    const char *device; /* always available when this information is of a sink/source */ +    const char *description;  /* optional */ +    const pa_typeid_t *typeid;  /* optional */ +    const struct pa_sample_spec *sample_spec;  /* optional */ +}; + +void pa_browser_set_callback(struct pa_browser *z, void (*cb)(struct pa_browser *z, enum pa_browse_opcode c, const struct pa_browse_info *i, void *userdata), void *userdata); + +PA_C_DECL_END + +#endif diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index db4b121d..0283312a 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,4 +1,3 @@ -  #ifndef foopolyplibcontexthfoo  #define foopolyplibcontexthfoo @@ -23,11 +22,11 @@    USA.  ***/ -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" -#include "cdecl.h" -#include "polyplib-operation.h" +#include <polyp/sample.h> +#include <polyp/polyplib-def.h> +#include <polyp/mainloop-api.h> +#include <polyp/cdecl.h> +#include <polyp/polyplib-operation.h>  /** \file   * Connection contexts for asynchrononous communication with a diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 44c2034b..9adb68fc 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -26,8 +26,8 @@  #include <sys/time.h>  #include <time.h> -#include "cdecl.h" -#include "sample.h" +#include <polyp/cdecl.h> +#include <polyp/sample.h>  /** \file   * Global definitions */ diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index fe632c26..166555c0 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -85,6 +85,7 @@ static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t c                 pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||                 pa_tagstruct_gets(t, &i.default_sink_name) < 0 ||                 pa_tagstruct_gets(t, &i.default_source_name) < 0 || +               pa_tagstruct_getu32(t, &i.cookie) < 0 ||                 !pa_tagstruct_eof(t)) {          pa_context_fail(o->context, PA_ERROR_PROTOCOL); @@ -130,7 +131,9 @@ static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t com                  pa_tagstruct_getu32(t, &i.volume) < 0 ||                  pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||                  pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || -                pa_tagstruct_get_usec(t, &i.latency) < 0) { +                pa_tagstruct_get_usec(t, &i.latency) < 0 || +                pa_tagstruct_getu32(t, &i.typeid) < 0) { +                                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish;              } @@ -222,7 +225,8 @@ static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t c                  pa_tagstruct_getu32(t, &i.owner_module) < 0 ||                  pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||                  pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || -                pa_tagstruct_get_usec(t, &i.latency) < 0) { +                pa_tagstruct_get_usec(t, &i.latency) < 0 || +                pa_tagstruct_getu32(t, &i.typeid) < 0) {                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish; @@ -310,8 +314,8 @@ static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t c              if (pa_tagstruct_getu32(t, &i.index) < 0 ||                  pa_tagstruct_gets(t, &i.name) < 0 || -                pa_tagstruct_gets(t, &i.protocol_name) < 0 || -                pa_tagstruct_getu32(t, &i.owner_module) < 0) { +                pa_tagstruct_getu32(t, &i.owner_module) < 0 || +                pa_tagstruct_getu32(t, &i.typeid) < 0 ) {                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish;              } @@ -450,7 +454,9 @@ static void context_get_sink_input_info_callback(struct pa_pdispatch *pd, uint32                  pa_tagstruct_getu32(t, &i.volume) < 0 ||                  pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||                  pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || -                pa_tagstruct_gets(t, &i.resample_method) < 0) { +                pa_tagstruct_gets(t, &i.resample_method) < 0 || +                pa_tagstruct_getu32(t, &i.typeid) < 0) { +                                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish;              } @@ -521,7 +527,9 @@ static void context_get_source_output_info_callback(struct pa_pdispatch *pd, uin                  pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||                  pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||                  pa_tagstruct_get_usec(t, &i.source_usec) < 0 || -                pa_tagstruct_gets(t, &i.resample_method) < 0) { +                pa_tagstruct_gets(t, &i.resample_method) < 0 || +                pa_tagstruct_getu32(t, &i.typeid) < 0) { +                                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish;              } @@ -659,6 +667,7 @@ static void context_get_sample_info_callback(struct pa_pdispatch *pd, uint32_t c                  pa_tagstruct_getu32(t, &i.bytes) < 0 ||                  pa_tagstruct_get_boolean(t, &i.lazy) < 0 ||                  pa_tagstruct_gets(t, &i.filename) < 0) { +                                  pa_context_fail(o->context, PA_ERROR_PROTOCOL);                  goto finish;              } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 08b36f86..ba9bde3c 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -24,9 +24,10 @@  #include <inttypes.h> -#include "polyplib-operation.h" -#include "polyplib-context.h" -#include "cdecl.h" +#include <polyp/polyplib-operation.h> +#include <polyp/polyplib-context.h> +#include <polyp/cdecl.h> +#include <polyp/typeid.h>  /** \file   * @@ -57,6 +58,7 @@ struct pa_sink_info {      uint32_t monitor_source;           /**< Index of the monitor source connected to this sink */      const char *monitor_source_name;   /**< The name of the monitor source */      pa_usec_t latency;                 /**< Length of filled playback buffer of this sink */ +    pa_typeid_t typeid;                /**< Implementation type. \since 0.8 */  };  /** Get information about a sink by its name */ @@ -78,6 +80,7 @@ struct pa_source_info {      uint32_t monitor_of_sink;           /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */      const char *monitor_of_sink_name;   /**< Name of the owning sink, or PA_INVALID_INDEX */      pa_usec_t latency;                  /**< Length of filled record buffer of this source. \since 0.5 */ +    pa_typeid_t typeid;                /**< Implementation type. \since 0.8 */  };  /** Get information about a source by its name */ @@ -97,7 +100,8 @@ struct pa_server_info {      const char *server_name;            /**< Server package name (usually "polypaudio") */      struct pa_sample_spec sample_spec;  /**< Default sample specification */      const char *default_sink_name;      /**< Name of default sink. \since 0.4 */ -    const char *default_source_name;      /**< Name of default sink. \since 0.4*/ +    const char *default_source_name;    /**< Name of default sink. \since 0.4*/ +    uint32_t cookie;                    /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */  };  /** Get some information about the server */ @@ -123,7 +127,7 @@ struct pa_client_info {      uint32_t index;                      /**< Index of this client */      const char *name;                    /**< Name of this client */      uint32_t owner_module;               /**< Index of the owning module, or PA_INVALID_INDEX */ -    const char *protocol_name;           /**< A string describing the protocol name this client is connected over (i.e. "ESOUND", "NATIVE", "SIMPLE") */ +    pa_typeid_t typeid;                  /**< Implementation type. \since 0.8 */  };  /** Get information about a client by its index */ @@ -144,6 +148,7 @@ struct pa_sink_input_info {      pa_usec_t buffer_usec;               /**< Latency due to buffering in sink input, see pa_latency_info for details */      pa_usec_t sink_usec;                 /**< Latency of the sink device, see pa_latency_info for details */      const char *resample_method;         /**< Thre resampling method used by this sink input. \since 0.7 */ +    pa_typeid_t typeid;                  /**< Implementation type. \since 0.8 */  };  /** Get some information about a sink input by its index */ @@ -163,6 +168,7 @@ struct pa_source_output_info {      pa_usec_t buffer_usec;               /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */      pa_usec_t source_usec;               /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */      const char *resample_method;         /**< Thre resampling method used by this source output. \since 0.7 */ +    pa_typeid_t typeid;                  /**< Implementation type. \since 0.8 */  };  /** Get information about a source output by its index */ diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index bd1366d2..5c3af49c 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -22,8 +22,8 @@    USA.  ***/ -#include "cdecl.h" -#include "polyplib-def.h" +#include <polyp/cdecl.h> +#include <polyp/polyplib-def.h>  /** \file   * Asynchronous operations */ diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index 051bdd12..8ec375ea 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -24,9 +24,9 @@  #include <sys/types.h> -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "cdecl.h" +#include <polyp/polyplib-context.h> +#include <polyp/polyplib-stream.h> +#include <polyp/cdecl.h>  /** \file   * All sample cache related routines */ diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 53873491..939b2ae6 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -24,10 +24,10 @@  #include <sys/types.h> -#include "sample.h" -#include "polyplib-def.h" -#include "cdecl.h" -#include "polyplib-operation.h" +#include <polyp/sample.h> +#include <polyp/polyplib-def.h> +#include <polyp/cdecl.h> +#include <polyp/polyplib-operation.h>  /** \file   * Audio streams for input, output and sample upload */ diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index a677bd02..5c697b71 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -24,9 +24,9 @@  #include <inttypes.h> -#include "polyplib-def.h" -#include "polyplib-context.h" -#include "cdecl.h" +#include <polyp/polyplib-def.h> +#include <polyp/polyplib-context.h> +#include <polyp/cdecl.h>  /** \file   * Daemon introspection event subscription subsystem. Use this diff --git a/polyp/polyplib.h b/polyp/polyplib.h index a0c418d4..b9b9b447 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,16 +22,16 @@    USA.  ***/ -#include "cdecl.h" -#include "mainloop-api.h" -#include "sample.h" -#include "polyplib-def.h" -#include "polyplib-context.h" -#include "polyplib-stream.h" -#include "polyplib-introspect.h" -#include "polyplib-subscribe.h" -#include "polyplib-scache.h" -#include "polyplib-version.h" +#include <polyp/cdecl.h> +#include <polyp/mainloop-api.h> +#include <polyp/sample.h> +#include <polyp/polyplib-def.h> +#include <polyp/polyplib-context.h> +#include <polyp/polyplib-stream.h> +#include <polyp/polyplib-introspect.h> +#include <polyp/polyplib-subscribe.h> +#include <polyp/polyplib-scache.h> +#include <polyp/polyplib-version.h>  /** \file   * Include all polyplib header file at once. The following files are included: \ref mainloop-api.h, \ref sample.h, diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index a32a9bd8..d9ed66b9 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -63,6 +63,8 @@  #define SCACHE_PREFIX "esound." +#define PA_TYPEID_ESOUND PA_TYPEID_MAKE('E', 'S', 'D', 'P') +  /* This is heavily based on esound's code */  struct connection { @@ -320,7 +322,7 @@ static int esd_proto_stream_play(struct connection *c, esd_proto_t request, cons      assert(!c->sink_input && !c->input_memblockq); -    if (!(c->sink_input = pa_sink_input_new(sink, name, &ss, 0, -1))) { +    if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_ESOUND, name, &ss, 0, -1))) {          pa_log(__FILE__": failed to create sink input.\n");          return -1;      } @@ -392,7 +394,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co      assert(!c->output_memblockq && !c->source_output); -    if (!(c->source_output = pa_source_output_new(source, name, &ss, -1))) { +    if (!(c->source_output = pa_source_output_new(source, PA_TYPEID_ESOUND, name, &ss, -1))) {          pa_log(__FILE__": failed to create source output\n");          return -1;      } @@ -1058,7 +1060,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo      pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));      assert(p->core); -    c->client = pa_client_new(p->core, "ESOUND", cname); +    c->client = pa_client_new(p->core, PA_TYPEID_ESOUND, cname);      assert(c->client);      c->client->owner = p->module;      c->client->kill = client_kill_cb; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 94dc5e5f..d5619ef7 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -56,6 +56,8 @@  /* Don't accept more connection than this */  #define MAX_CONNECTIONS 10 +#define PA_TYPEID_NATIVE PA_TYPEID_MAKE('N', 'A', 'T', 'V') +  struct connection;  struct pa_protocol_native; @@ -272,7 +274,7 @@ static struct record_stream* record_stream_new(struct connection *c, struct pa_s      size_t base;      assert(c && source && ss && name && maxlength); -    if (!(source_output = pa_source_output_new(source, name, ss, -1))) +    if (!(source_output = pa_source_output_new(source, PA_TYPEID_NATIVE, name, ss, -1)))          return NULL;      s = pa_xmalloc(sizeof(struct record_stream)); @@ -316,7 +318,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, struct      struct pa_sink_input *sink_input;      assert(c && sink && ss && name && maxlength); -    if (!(sink_input = pa_sink_input_new(sink, name, ss, 0, -1))) +    if (!(sink_input = pa_sink_input_new(sink, PA_TYPEID_NATIVE, name, ss, 0, -1)))          return NULL;      s = pa_xmalloc(sizeof(struct playback_stream)); @@ -1118,6 +1120,7 @@ static void sink_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink *sink) {      pa_tagstruct_putu32(t, sink->monitor_source->index);      pa_tagstruct_puts(t, sink->monitor_source->name);      pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); +    pa_tagstruct_putu32(t, sink->typeid);  }  static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) { @@ -1130,14 +1133,15 @@ static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *sour      pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1);      pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL);      pa_tagstruct_put_usec(t, pa_source_get_latency(source)); +    pa_tagstruct_putu32(t, source->typeid);  }  static void client_fill_tagstruct(struct pa_tagstruct *t, struct pa_client *client) {      assert(t && client);      pa_tagstruct_putu32(t, client->index);      pa_tagstruct_puts(t, client->name); -    pa_tagstruct_puts(t, client->protocol_name);      pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); +    pa_tagstruct_putu32(t, client->typeid);  }  static void module_fill_tagstruct(struct pa_tagstruct *t, struct pa_module *module) { @@ -1161,6 +1165,7 @@ static void sink_input_fill_tagstruct(struct pa_tagstruct *t, struct pa_sink_inp      pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s));      pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink));      pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); +    pa_tagstruct_putu32(t, s->typeid);  }  static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) { @@ -1174,6 +1179,7 @@ static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_sourc      pa_tagstruct_put_usec(t, pa_source_output_get_latency(s));      pa_tagstruct_put_usec(t, pa_source_get_latency(s->source));      pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); +    pa_tagstruct_putu32(t, s->typeid);  }  static void scache_fill_tagstruct(struct pa_tagstruct *t, struct pa_scache_entry *e) { @@ -1366,6 +1372,9 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u      pa_tagstruct_puts(reply, n);      n = pa_namereg_get_default_source_name(c->protocol->core);      pa_tagstruct_puts(reply, n); + +    pa_tagstruct_putu32(reply, c->protocol->core->cookie); +          pa_pstream_send_tagstruct(c->pstream, reply);  } @@ -2022,7 +2031,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo      c->protocol = p;      assert(p->core); -    c->client = pa_client_new(p->core, "NATIVE", "Client"); +    c->client = pa_client_new(p->core, PA_TYPEID_NATIVE, "Client");      assert(c->client);      c->client->kill = client_kill_cb;      c->client->userdata = c; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index 3dddc474..8d05a7fa 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -42,6 +42,8 @@  /* Don't allow more than this many concurrent connections */  #define MAX_CONNECTIONS 10 +#define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L') +  struct connection {      struct pa_protocol_simple *protocol;      struct pa_iochannel *io; @@ -308,7 +310,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo      c->playback.fragment_size = 0;      pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); -    c->client = pa_client_new(p->core, "SIMPLE", cname); +    c->client = pa_client_new(p->core, PA_TYPEID_SIMPLE, cname);      assert(c->client);      c->client->owner = p->module;      c->client->kill = client_kill_cb; @@ -323,7 +325,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo              goto fail;          } -        if (!(c->sink_input = pa_sink_input_new(sink, c->client->name, &p->sample_spec, 0, -1))) { +        if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, 0, -1))) {              pa_log(__FILE__": Failed to create sink input.\n");              goto fail;          } @@ -353,7 +355,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo              goto fail;          } -        c->source_output = pa_source_output_new(source, c->client->name, &p->sample_spec, -1); +        c->source_output = pa_source_output_new(source, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, -1);          if (!c->source_output) {              pa_log(__FILE__": Failed to create source output.\n");              goto fail; diff --git a/polyp/random.c b/polyp/random.c new file mode 100644 index 00000000..456954a2 --- /dev/null +++ b/polyp/random.c @@ -0,0 +1,61 @@ +/* $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.1 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 +  Lesser 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. +***/ + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> +#include <time.h> + +#include "random.h" +#include "util.h" +#include "log.h" + +#define RANDOM_DEVICE "/dev/urandom" + +void pa_random(void *ret_data, size_t length) { +    int fd; +    ssize_t r = 0; +    assert(ret_data && length); +     +    if ((fd = open(RANDOM_DEVICE, O_RDONLY)) >= 0) { + +        if ((r = pa_loop_read(fd, ret_data, length)) < 0 || (size_t) r != length) +            pa_log_error(__FILE__": failed to read entropy from '%s'\n", RANDOM_DEVICE); + +        close(fd); +    } + +    if ((size_t) r != length) { +        uint8_t *p; +        size_t l; +         +        pa_log_warn(__FILE__": WARNING: Failed to open entropy device '"RANDOM_DEVICE"': %s" +                    ", falling back to unsecure pseudo RNG.\n", strerror(errno)); + +        srandom(time(NULL)); +         +        for (p = ret_data, l = length; l > 0; p++, l--) +            *p = (uint8_t) random(); +    } +} diff --git a/polyp/random.h b/polyp/random.h new file mode 100644 index 00000000..bfb3df08 --- /dev/null +++ b/polyp/random.h @@ -0,0 +1,27 @@ +#ifndef foorandomhfoo +#define foorandomhfoo + +/* $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.1 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 +  Lesser 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. +***/ + +void pa_random(void *ret_data, size_t length); +     +#endif diff --git a/polyp/sample.c b/polyp/sample.c index b0723f70..51afaa01 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -163,23 +163,23 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) {  enum pa_sample_format pa_parse_sample_format(const char *format) { -    if (strcmp(format, "s16le") == 0) +    if (strcasecmp(format, "s16le") == 0)          return PA_SAMPLE_S16LE; -    else if (strcmp(format, "s16be") == 0) +    else if (strcasecmp(format, "s16be") == 0)          return PA_SAMPLE_S16BE; -    else if (strcmp(format, "s16ne") == 0 || strcmp(format, "s16") == 0 || strcmp(format, "16") == 0) +    else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0)          return PA_SAMPLE_S16NE; -    else if (strcmp(format, "u8") == 0 || strcmp(format, "8") == 0) +    else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0)          return PA_SAMPLE_U8; -    else if (strcmp(format, "float32") == 0 || strcmp(format, "float32ne") == 0) +    else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0)          return PA_SAMPLE_FLOAT32; -    else if (strcmp(format, "float32le") == 0) +    else if (strcasecmp(format, "float32le") == 0)          return PA_SAMPLE_FLOAT32LE; -    else if (strcmp(format, "float32be") == 0) +    else if (strcasecmp(format, "float32be") == 0)          return PA_SAMPLE_FLOAT32BE; -    else if (strcmp(format, "ulaw") == 0) +    else if (strcasecmp(format, "ulaw") == 0)          return PA_SAMPLE_ULAW; -    else if (strcmp(format, "alaw") == 0) +    else if (strcasecmp(format, "alaw") == 0)          return PA_SAMPLE_ALAW;      return -1; diff --git a/polyp/sample.h b/polyp/sample.h index 59226c46..d4873eb5 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -26,7 +26,7 @@  #include <sys/types.h>  #include <math.h> -#include "cdecl.h" +#include <polyp/cdecl.h>  /** \file   * Constants and routines for sample type handling */ @@ -86,7 +86,7 @@ int pa_sample_spec_valid(const struct pa_sample_spec *spec);  /** Return non-zero when the two sample type specifications match */  int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_spec*b); -/* Return a descriptive string for the specified sample format. \since 0.7.1 */ +/* Return a descriptive string for the specified sample format. \since 0.8 */  const char *pa_sample_format_to_string(enum pa_sample_format f);  /** Maximum required string length for pa_sample_spec_snprint() */ diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 347b8f5c..3e7fdf7b 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,7 +36,7 @@  #define CONVERT_BUFFER_LENGTH 4096 -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) { +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method) {      struct pa_sink_input *i;      struct pa_resampler *resampler = NULL;      int r; @@ -59,6 +59,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con      i->ref = 1;      i->state = PA_SINK_INPUT_RUNNING;      i->name = pa_xstrdup(name); +    i->typeid = typeid;      i->client = NULL;      i->owner = NULL;      i->sink = s; diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 5482369d..83abe537 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -42,6 +42,7 @@ struct pa_sink_input {      enum pa_sink_input_state state;      uint32_t index; +    pa_typeid_t typeid;      char *name;      struct pa_module *owner; @@ -64,7 +65,7 @@ struct pa_sink_input {      struct pa_resampler *resampler;  }; -struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method); +struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int variable_rate, int resample_method);  void pa_sink_input_unref(struct pa_sink_input* i);  struct pa_sink_input* pa_sink_input_ref(struct pa_sink_input* i); diff --git a/polyp/sink.c b/polyp/sink.c index 3d20884b..481e5cf7 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -39,7 +39,7 @@  #define MAX_MIX_CHANNELS 32 -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { +struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {      struct pa_sink *s;      char *n = NULL;      char st[256]; @@ -55,6 +55,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co      s->name = pa_xstrdup(name);      s->description = NULL; +    s->typeid = typeid;      s->ref = 1;      s->state = PA_SINK_RUNNING; @@ -65,7 +66,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co      s->inputs = pa_idxset_new(NULL, NULL);      n = pa_sprintf_malloc("%s_monitor", name); -    s->monitor_source = pa_source_new(core, n, 0, spec); +    s->monitor_source = pa_source_new(core, typeid, n, 0, spec);      assert(s->monitor_source);      pa_xfree(n);      s->monitor_source->monitor_of = s; diff --git a/polyp/sink.h b/polyp/sink.h index 5da4ca43..844af964 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -30,6 +30,7 @@ struct pa_sink;  #include "sample.h"  #include "idxset.h"  #include "source.h" +#include "typeid.h"  #define PA_MAX_INPUTS_PER_SINK 6 @@ -43,6 +44,7 @@ struct pa_sink {      enum pa_sink_state state;      uint32_t index; +    pa_typeid_t typeid;      char *name, *description;      struct pa_module *owner; @@ -59,7 +61,7 @@ struct pa_sink {      void *userdata;  }; -struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +struct pa_sink* pa_sink_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);  void pa_sink_disconnect(struct pa_sink* s);  void pa_sink_unref(struct pa_sink*s);  struct pa_sink* pa_sink_ref(struct pa_sink *s); diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index 43f93230..621c3ed9 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -36,6 +36,7 @@  #include "log.h"  #define BUF_SIZE (1024*10) +#define PA_TYPEID_SOUND_FILE PA_TYPEID_MAKE('S', 'N', 'D', 'F')  struct userdata {      SNDFILE *sndfile; @@ -160,7 +161,7 @@ int pa_play_file(struct pa_sink *sink, const char *fname, pa_volume_t volume) {          goto fail;      } -    if (!(u->sink_input = pa_sink_input_new(sink, fname, &ss, 0, -1))) +    if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SOUND_FILE, fname, &ss, 0, -1)))          goto fail;      u->sink_input->volume = volume; diff --git a/polyp/source-output.c b/polyp/source-output.c index 3568fd6f..f954c23f 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,7 +33,7 @@  #include "subscribe.h"  #include "log.h" -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method) { +struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method) {      struct pa_source_output *o;      struct pa_resampler *resampler = NULL;      int r; @@ -56,6 +56,8 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n      o->ref = 1;      o->state = PA_SOURCE_OUTPUT_RUNNING;      o->name = pa_xstrdup(name); +    o->typeid = typeid; +          o->client = NULL;      o->owner = NULL;      o->source = s; diff --git a/polyp/source-output.h b/polyp/source-output.h index 0247a09a..f3187aa9 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -42,6 +42,7 @@ struct pa_source_output {      enum pa_source_output_state state;      uint32_t index; +    pa_typeid_t typeid;      char *name;      struct pa_module *owner; @@ -58,7 +59,7 @@ struct pa_source_output {      void *userdata;  }; -struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *name, const struct pa_sample_spec *spec, int resample_method); +struct pa_source_output* pa_source_output_new(struct pa_source *s, pa_typeid_t typeid, const char *name, const struct pa_sample_spec *spec, int resample_method);  void pa_source_output_unref(struct pa_source_output* o);  struct pa_source_output* pa_source_output_ref(struct pa_source_output *o); diff --git a/polyp/source.c b/polyp/source.c index 7cdb9117..fc73272c 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -35,7 +35,7 @@  #include "subscribe.h"  #include "log.h" -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec) { +struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec) {      struct pa_source *s;      char st[256];      int r; @@ -53,6 +53,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail      s->name = pa_xstrdup(name);      s->description = NULL; +    s->typeid = typeid;       s->owner = NULL;      s->core = core; diff --git a/polyp/source.h b/polyp/source.h index 1e6310b0..0fac2b34 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -31,6 +31,7 @@ struct pa_source;  #include "memblock.h"  #include "memchunk.h"  #include "sink.h" +#include "typeid.h"  #define PA_MAX_OUTPUTS_PER_SOURCE 16 @@ -44,6 +45,7 @@ struct pa_source {      enum pa_source_state state;      uint32_t index; +    pa_typeid_t typeid;      char *name, *description;      struct pa_module *owner; @@ -57,7 +59,7 @@ struct pa_source {      void *userdata;  }; -struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail, const struct pa_sample_spec *spec); +struct pa_source* pa_source_new(struct pa_core *core, pa_typeid_t typeid, const char *name, int fail, const struct pa_sample_spec *spec);  void pa_source_disconnect(struct pa_source *s);  void pa_source_unref(struct pa_source *s);  struct pa_source* pa_source_ref(struct pa_source *c); diff --git a/polyp/typeid.c b/polyp/typeid.c new file mode 100644 index 00000000..70d3df33 --- /dev/null +++ b/polyp/typeid.c @@ -0,0 +1,33 @@ +/* $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.1 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 +  Lesser 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. +***/ + +#include <stdio.h> + +#include "typeid.h" + +char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length) { +    if (id == PA_TYPEID_UNKNOWN) +        snprintf(ret_s, length, "????"); +    else +        snprintf(ret_s, length, "%c%c%c%c", (char) (id >> 24), (char) (id >> 16), (char) (id >> 8), (char) (id)); +     +    return ret_s; +} diff --git a/polyp/typeid.h b/polyp/typeid.h new file mode 100644 index 00000000..bd10b2e4 --- /dev/null +++ b/polyp/typeid.h @@ -0,0 +1,40 @@ +#ifndef footypeidhfoo +#define footypeidhfoo + +/* $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.1 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 +  Lesser 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. +***/ + +#include <inttypes.h> +#include <sys/types.h> + +typedef uint32_t pa_typeid_t; + +#define PA_TYPEID_UNKNOWN ((pa_typeid_t) -1) + +char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length); + +#define PA_TYPEID_MAKE(a,b,c,d) (\ +    (((pa_typeid_t) a & 0xFF) << 24) | \ +    (((pa_typeid_t) b & 0xFF) << 16) | \ +    (((pa_typeid_t) c & 0xFF) << 8) | \ +    (((pa_typeid_t) d & 0xFF))) + +#endif | 
