From 22cb23eedb2eae7c79dc8fcf395be08bfc666256 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 14 Aug 2004 20:25:32 +0000 Subject: implement proper refcounting in polyplib split polyplib to multiple modules add some prelimenary documentation add doxygen support git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@123 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 25 +- polyp/cdecl.h | 21 + polyp/glib-mainloop.h | 20 +- polyp/llist.h | 39 + polyp/mainloop-api.h | 44 +- polyp/mainloop.h | 5 + polyp/memblock.c | 42 +- polyp/memblock.h | 4 +- polyp/native-common.h | 18 +- polyp/pacat.c | 150 ++-- polyp/pactl.c | 146 ++-- polyp/polyplib-context.c | 1490 ++++++-------------------------------- polyp/polyplib-context.h | 182 ++--- polyp/polyplib-def.h | 17 +- polyp/polyplib-error.h | 12 +- polyp/polyplib-internal.h | 1528 ++------------------------------------- polyp/polyplib-introspect.c | 1651 +++++++------------------------------------ polyp/polyplib-introspect.h | 109 +-- polyp/polyplib-operation.c | 78 ++ polyp/polyplib-operation.h | 56 ++ polyp/polyplib-sample.c | 1550 ---------------------------------------- polyp/polyplib-sample.h | 178 ----- polyp/polyplib-scache.c | 1495 +-------------------------------------- polyp/polyplib-scache.h | 162 +---- polyp/polyplib-simple.c | 68 +- polyp/polyplib-simple.h | 33 +- polyp/polyplib-stream.c | 1594 +++++++---------------------------------- polyp/polyplib-stream.h | 178 ++--- polyp/polyplib-subscribe.c | 1514 +-------------------------------------- polyp/polyplib-subscribe.h | 158 +---- polyp/polyplib.c | 1550 ---------------------------------------- polyp/polyplib.h | 156 +--- polyp/sample-util.c | 7 - polyp/sample-util.h | 4 - polyp/sample.c | 8 + polyp/sample.h | 21 +- polyp/socket-client.c | 2 +- polyp/socket-client.h | 2 + polyp/tagstruct.h | 2 - polyp/xmalloc.c | 29 +- polyp/xmalloc.h | 2 + 41 files changed, 1618 insertions(+), 12732 deletions(-) create mode 100644 polyp/cdecl.h create mode 100644 polyp/llist.h create mode 100644 polyp/polyplib-operation.c create mode 100644 polyp/polyplib-operation.h delete mode 100644 polyp/polyplib-sample.c delete mode 100644 polyp/polyplib-sample.h delete mode 100644 polyp/polyplib.c (limited to 'polyp') diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ce753da4..7f70ec9d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -25,12 +25,19 @@ polypincludedir=$(includedir)/polyp EXTRA_DIST = polypaudio.pa depmod.py bin_PROGRAMS = polypaudio pacat pactl -noinst_PROGRAMS = pacat-simple parec-simple mainloop-test mainloop-test-glib +noinst_PROGRAMS = mainloop-test mainloop-test-glib pacat-simple parec-simple polypinclude_HEADERS=polyplib.h \ polyplib-def.h \ polyplib-simple.h \ polyplib-error.h \ + polyplib-stream.h \ + polyplib-context.h \ + polyplib-introspect.h \ + polyplib-subscribe.h \ + polyplib-operation.h \ + polyplib-scache.h \ + cdecl.h \ mainloop-api.h \ mainloop.h \ mainloop-signal.h \ @@ -72,10 +79,11 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-x11-bell.la lib_LTLIBRARIES=libpolyp.la \ - libpolyp-simple.la \ libpolyp-error.la \ libpolyp-mainloop.la \ - libpolyp-mainloop-glib.la + libpolyp-mainloop-glib.la \ + libpolyp-simple.la + polypaudio_SOURCES = idxset.c idxset.h \ queue.c queue.h \ @@ -261,7 +269,7 @@ module_x11_bell_la_SOURCES = module-x11-bell.c module_x11_bell_la_LDFLAGS = -module -avoid-version module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib -libpolyp_la_SOURCES = polyplib.c polyplib.h \ +libpolyp_la_SOURCES = polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ iochannel.c iochannel.h \ @@ -281,7 +289,14 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \ socket-util.c socket-util.h \ native-common.h \ sample.c sample.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + polyplib-operation.c polyplib-operation.h \ + polyplib-context.c polyplib-context.h \ + polyplib-stream.c polyplib-stream.h \ + polyplib-introspect.c polyplib-introspect.h \ + polyplib-scache.c polyplib-scache.h \ + polyplib-subscribe.c polyplib-subscribe.h \ + cdecl.h libpolyp_la_CFLAGS = $(AM_CFLAGS) libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \ diff --git a/polyp/cdecl.h b/polyp/cdecl.h new file mode 100644 index 00000000..39880a47 --- /dev/null +++ b/polyp/cdecl.h @@ -0,0 +1,21 @@ +#ifndef foocdeclhfoo +#define foocdeclhfoo + +/** \file + * C++ compatibility support */ + +#ifdef __cplusplus +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN extern "C" { +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END } + +#else +/** If using C++ this macro enables C mode, otherwise does nothing */ +#define PA_C_DECL_BEGIN +/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ +#define PA_C_DECL_END + +#endif + +#endif diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 7655108a..c67e72bd 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -4,20 +4,26 @@ #include #include "mainloop-api.h" +#include "cdecl.h" -#ifdef __cplusplus -extern "C" { -#endif +/** \file + * GLIB main loop support */ + +PA_C_DECL_BEGIN +/** \struct pa_glib_mainloop + * A GLIB main loop object */ struct pa_glib_mainloop; +/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */ struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); + +/** Free the GLIB main loop object */ void pa_glib_mainloop_free(struct pa_glib_mainloop* g); + +/** Return the abstract main loop API vtable for the GLIB main loop object */ struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_BEGIN #endif diff --git a/polyp/llist.h b/polyp/llist.h new file mode 100644 index 00000000..1f145de2 --- /dev/null +++ b/polyp/llist.h @@ -0,0 +1,39 @@ +#ifndef foollistfoo +#define foollistfoo + +#define PA_LLIST_HEAD(t,name) t *name + +#define PA_LLIST_FIELDS(t) t *next, *prev; + +#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0) + +#define PA_LLIST_INIT(t,item) do { \ + t *_item = (item); \ + assert(_item); \ + _item->prev = _item->next = NULL; \ + } while(0) + +#define PA_LLIST_PREPEND(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->next = *_head)) \ + _item->next->prev = _item; \ + _item->prev = NULL; \ + *_head = _item; \ + } while (0) + +#define PA_LLIST_REMOVE(t,head,item) do { \ + t **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->next) \ + _item->next->prev = _item->prev; \ + if (_item->prev) \ + _item->prev->next = _item->next; \ + else {\ + assert(*_head == _item); \ + *_head = _item->next; \ + } \ + _item->next = _item->prev = NULL; \ + } while(0) + +#endif diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 1b9e2783..97ab6a68 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -22,26 +22,37 @@ USA. ***/ -#include #include +#include -#ifdef __cplusplus -extern "C" { -#endif +#include "cdecl.h" +PA_C_DECL_BEGIN + +/** A bitmask for IO events */ enum pa_io_event_flags { - PA_IO_EVENT_NULL = 0, - PA_IO_EVENT_INPUT = 1, - PA_IO_EVENT_OUTPUT = 2, - PA_IO_EVENT_HANGUP = 4, - PA_IO_EVENT_ERROR = 8, + PA_IO_EVENT_NULL = 0, /**< No event */ + PA_IO_EVENT_INPUT = 1, /**< Input event */ + PA_IO_EVENT_OUTPUT = 2, /**< Output event */ + PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ + PA_IO_EVENT_ERROR = 8, /**< Error event */ }; +/** \struct pa_io_event + * An IO event source object */ struct pa_io_event; + +/** \struct pa_defer_event + * A deferred event source object. Events of this type are triggered once in every main loop iteration */ struct pa_defer_event; + +/** \struct pa_time_event + * A timer event source object */ struct pa_time_event; +/** An abstract mainloop API vtable */ struct pa_mainloop_api { + /** A pointer to some private, arbitrary data of the main loop implementation */ void *userdata; /* IO sources */ @@ -56,20 +67,25 @@ struct pa_mainloop_api { void (*time_free)(struct pa_time_event* e); void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata)); - /* Deferred sources */ + /** Create a new deferred event source object */ struct pa_defer_event* (*defer_new)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event* e, void *userdata), void *userdata); + + /** Enable or disable a deferred event source temporarily */ void (*defer_enable)(struct pa_defer_event* e, int b); + + /** Free a deferred event source object */ void (*defer_free)(struct pa_defer_event* e); + + /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ void (*defer_set_destroy)(struct pa_defer_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata)); - /* Exit mainloop */ + /** Exit the main loop and return the specfied retval*/ void (*quit)(struct pa_mainloop_api*a, int retval); }; +/** Run the specified callback function once from the main loop using an anonymous defer event. */ void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 58448c3e..4a4c85df 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -23,6 +23,9 @@ ***/ #include "mainloop-api.h" +#include "cdecl.h" + +PA_C_DECL_BEGIN struct pa_mainloop; @@ -34,4 +37,6 @@ int pa_mainloop_run(struct pa_mainloop *m, int *retval); struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m); +PA_C_DECL_END + #endif diff --git a/polyp/memblock.c b/polyp/memblock.c index 0571f5da..a4452efa 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -39,6 +39,7 @@ struct pa_memblock *pa_memblock_new(size_t length) { b->ref = 1; b->length = length; b->data = b+1; + b->free_cb = NULL; memblock_count++; memblock_total += length; return b; @@ -50,6 +51,7 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + b->free_cb = NULL; memblock_count++; memblock_total += length; return b; @@ -61,6 +63,21 @@ struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) { b->ref = 1; b->length = length; b->data = d; + b->free_cb = NULL; + memblock_count++; + memblock_total += length; + return b; +} + +struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p)) { + struct pa_memblock *b; + assert(d && length && free_cb); + b = pa_xmalloc(sizeof(struct pa_memblock)); + b->type = PA_MEMBLOCK_USER; + b->ref = 1; + b->length = length; + b->data = d; + b->free_cb = free_cb; memblock_count++; memblock_total += length; return b; @@ -74,31 +91,28 @@ struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) { void pa_memblock_unref(struct pa_memblock*b) { assert(b && b->ref >= 1); - b->ref--; - - if (b->ref == 0) { - if (b->type == PA_MEMBLOCK_DYNAMIC) - pa_xfree(b->data); + if ((--(b->ref)) == 0) { memblock_count--; memblock_total -= b->length; + if (b->type == PA_MEMBLOCK_USER) { + assert(b->free_cb); + b->free_cb(b->data); + } else if (b->type == PA_MEMBLOCK_DYNAMIC) + pa_xfree(b->data); + pa_xfree(b); } } void pa_memblock_unref_fixed(struct pa_memblock *b) { - void *d; - - assert(b && b->ref >= 1); + assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED); - if (b->ref == 1) { + if (b->ref == 1) pa_memblock_unref(b); - return; - } else { - d = pa_xmalloc(b->length); - memcpy(d, b->data, b->length); - b->data = d; + else { + b->data = pa_xmemdup(b->data, b->length); b->type = PA_MEMBLOCK_DYNAMIC; b->ref--; } diff --git a/polyp/memblock.h b/polyp/memblock.h index 4bb02977..6e79aa3e 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -25,18 +25,20 @@ #include #include -enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC }; +enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC, PA_MEMBLOCK_USER }; struct pa_memblock { enum pa_memblock_type type; unsigned ref; size_t length; void *data; + void (*free_cb)(void *p); }; struct pa_memblock *pa_memblock_new(size_t length); struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length); struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length); +struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p)); void pa_memblock_unref(struct pa_memblock*b); struct pa_memblock* pa_memblock_ref(struct pa_memblock*b); diff --git a/polyp/native-common.h b/polyp/native-common.h index 4d5ab53d..fa3213d0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -64,6 +64,9 @@ enum { PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, + + PA_COMMAND_SET_SINK_VOLUME, + PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_MAX }; @@ -90,13 +93,14 @@ enum { #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie" enum pa_subscription_mask { - PA_SUBSCRIPTION_FACILITY_SINK = 1, - PA_SUBSCRIPTION_FACILITY_SOURCE = 2, - PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4, - PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8, - PA_SUBSCRIPTION_FACILITY_MODULE = 16, - PA_SUBSCRIPTION_FACILITY_CLIENT = 32, - PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64, + PA_SUBSCRIPTION_MASK_NULL = 0, + PA_SUBSCRIPTION_MASK_SINK = 1, + PA_SUBSCRIPTION_MASK_SOURCE = 2, + PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, + PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, + PA_SUBSCRIPTION_MASK_MODULE = 16, + PA_SUBSCRIPTION_MASK_CLIENT = 32, + PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, }; enum pa_subscription_event_type { diff --git a/polyp/pacat.c b/polyp/pacat.c index 4d8605c7..5d29451a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -52,18 +52,6 @@ static void quit(int ret) { mainloop_api->quit(mainloop_api, ret); } -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} - -static void stream_die_callback(struct pa_stream *s, void *userdata) { - assert(s); - fprintf(stderr, "Stream deleted, exiting.\n"); - quit(1); -} - static void do_stream_write(size_t length) { size_t l; assert(length); @@ -75,7 +63,7 @@ static void do_stream_write(size_t length) { if (l > buffer_length) l = buffer_length; - pa_stream_write(stream, buffer+buffer_index, l); + pa_stream_write(stream, buffer+buffer_index, l, NULL); buffer_length -= l; buffer_index += l; @@ -115,63 +103,97 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le buffer_index = 0; } -static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) { +static void stream_state_callback(struct pa_stream *s, void *userdata) { assert(s); - if (!success) { - fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); - quit(1); - return; + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + break; + + case PA_STREAM_READY: + fprintf(stderr, "Stream successfully created\n"); + break; + + case PA_STREAM_TERMINATED: + quit(0); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); } - - fprintf(stderr, "Stream created.\n"); } -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { +static void context_state_callback(struct pa_context *c, void *userdata) { static const struct pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; - - assert(c && !stream); - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } + assert(c); - fprintf(stderr, "Connection established.\n"); - - if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) { - fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + + assert(c && !stream); + fprintf(stderr, "Connection established.\n"); + + stream = pa_stream_new(c, "pacat", &ss); + assert(stream); + + pa_stream_set_state_callback(stream, stream_state_callback, NULL); + pa_stream_set_write_callback(stream, stream_write_callback, NULL); + pa_stream_set_read_callback(stream, stream_read_callback, NULL); + + if (mode == PLAYBACK) + pa_stream_connect_playback(stream, NULL, NULL); + else + pa_stream_connect_record(stream, NULL, NULL); + + break; + + case PA_CONTEXT_TERMINATED: + quit(0); + break; + + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); } - - pa_stream_set_die_callback(stream, stream_die_callback, NULL); - pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_set_read_callback(stream, stream_read_callback, NULL); - - return; - -fail: - quit(1); } static void context_drain_complete(struct pa_context*c, void *userdata) { - quit(0); + pa_context_disconnect(c); } -static void stream_drain_complete(struct pa_stream*s, void *userdata) { +static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) { + struct pa_operation *o; + + if (!success) { + fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context))); + quit(1); + } + fprintf(stderr, "Playback stream drained.\n"); - pa_stream_free(stream); + pa_stream_disconnect(stream); + pa_stream_unref(stream); stream = NULL; - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); - else + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else { + pa_operation_unref(o); fprintf(stderr, "Draining connection to server.\n"); + } } static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { @@ -184,7 +206,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int return; } - if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream))) + if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream))) l = 4096; buffer = malloc(l); @@ -192,7 +214,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int if ((r = read(fd, buffer, l)) <= 0) { if (r == 0) { fprintf(stderr, "Got EOF.\n"); - pa_stream_drain(stream, stream_drain_complete, NULL); + pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL)); } else { fprintf(stderr, "read() failed: %s\n", strerror(errno)); quit(1); @@ -259,10 +281,11 @@ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, v } static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) { - if (mode == PLAYBACK) { - fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); - pa_stream_get_latency(stream, stream_get_latency_callback, NULL); - } + if (mode != PLAYBACK) + return; + + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL)); } int main(int argc, char *argv[]) { @@ -306,12 +329,9 @@ int main(int argc, char *argv[]) { goto quit; } - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); + pa_context_set_state_callback(context, context_state_callback, NULL); + + pa_context_connect(context, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -320,15 +340,21 @@ int main(int argc, char *argv[]) { quit: if (stream) - pa_stream_free(stream); + pa_stream_unref(stream); + if (context) - pa_context_free(context); + pa_context_unref(context); + if (stdio_event) { + assert(mainloop_api); + mainloop_api->io_free(stdio_event); + } + if (m) { pa_signal_done(); pa_mainloop_free(m); } - + if (buffer) free(buffer); diff --git a/polyp/pactl.c b/polyp/pactl.c index 2f3a4833..0ff2aa90 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -68,31 +68,27 @@ static void quit(int ret) { mainloop_api->quit(mainloop_api, ret); } -static void context_die_callback(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(1); -} static void context_drain_complete(struct pa_context *c, void *userdata) { - assert(c); - fprintf(stderr, "Connection to server shut down, exiting.\n"); - quit(0); + pa_context_disconnect(c); } static void drain(void) { - if (pa_context_drain(context, context_drain_complete, NULL) < 0) - quit(0); + struct pa_operation *o; + if (!(o = pa_context_drain(context, context_drain_complete, NULL))) + pa_context_disconnect(context); + else + pa_operation_unref(o); } -static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) { - if (blocks == (uint32_t) -1) { +static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) { + if (!i) { fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c))); quit(1); return; } - fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total); + fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", i->memblock_count, i->memblock_total); drain(); } @@ -116,22 +112,23 @@ static void remove_sample_callback(struct pa_context *c, int success, void *user drain(); } -static void stream_die_callback(struct pa_stream *s, void *userdata) { - assert(s); - fprintf(stderr, "Stream deleted, exiting.\n"); - quit(1); -} - -static void finish_sample_callback(struct pa_stream *s, int success, void *userdata) { +static void stream_state_callback(struct pa_stream *s, void *userdata) { assert(s); - if (!success) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); - return; + switch (pa_stream_get_state(s)) { + case PA_STREAM_CREATING: + case PA_STREAM_READY: + break; + + case PA_STREAM_TERMINATED: + drain(); + break; + + case PA_STREAM_FAILED: + default: + fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + quit(1); } - - drain(); } static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) { @@ -151,58 +148,55 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user quit(1); } - pa_stream_write(s, d, length); - free(d); + pa_stream_write(s, d, length, free); sample_length -= length; if (sample_length <= 0) { pa_stream_set_write_callback(sample_stream, NULL, NULL); - pa_stream_finish_sample(sample_stream, finish_sample_callback, NULL); - } -} - -static void upload_callback(struct pa_stream *s, int success, void *userdata) { - if (!success) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context))); - quit(1); + pa_stream_finish_upload(sample_stream); } } -static void context_complete_callback(struct pa_context *c, int success, void *userdata) { +static void context_state_callback(struct pa_context *c, void *userdata) { assert(c); + switch (pa_context_get_state(c)) { + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + break; + + case PA_CONTEXT_READY: + if (action == STAT) + pa_operation_unref(pa_context_stat(c, stat_callback, NULL)); + else if (action == PLAY_SAMPLE) + pa_operation_unref(pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL)); + else if (action == REMOVE_SAMPLE) + pa_operation_unref(pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL)); + else if (action == UPLOAD_SAMPLE) { + + sample_stream = pa_stream_new(c, sample_name, &sample_spec); + assert(sample_stream); + + pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); + pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); + pa_stream_connect_upload(sample_stream, sample_length); + } else { + assert(action == EXIT); + pa_context_exit_daemon(c); + drain(); + } + break; - if (!success) { - fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } + case PA_CONTEXT_TERMINATED: + quit(0); + break; - fprintf(stderr, "Connection established.\n"); - - if (action == STAT) - pa_context_stat(c, stat_callback, NULL); - else if (action == PLAY_SAMPLE) - pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL); - else if (action == REMOVE_SAMPLE) - pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL); - else if (action == UPLOAD_SAMPLE) { - if (!(sample_stream = pa_context_upload_sample(c, sample_name, &sample_spec, sample_length, upload_callback, NULL))) { - fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(c))); - goto fail; - } - - pa_stream_set_die_callback(sample_stream, stream_die_callback, NULL); - pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL); - } else { - assert(action == EXIT); - pa_context_exit(c); - drain(); + case PA_CONTEXT_FAILED: + default: + fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c))); + quit(1); } - - return; - -fail: - quit(1); } static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) { @@ -234,12 +228,15 @@ int main(int argc, char *argv[]) { sample_name = argv[3]; else { char *f = strrchr(argv[2], '/'); + size_t n; if (f) f++; else f = argv[2]; - strncpy(sample_name = tmp, f, strcspn(f, ".")); + n = strcspn(f, "."); + strncpy(sample_name = tmp, f, n); + tmp[n] = 0; } memset(&sfinfo, 0, sizeof(sfinfo)); @@ -292,12 +289,8 @@ int main(int argc, char *argv[]) { goto quit; } - if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) { - fprintf(stderr, "pa_context_connext() failed.\n"); - goto quit; - } - - pa_context_set_die_callback(context, context_die_callback, NULL); + pa_context_set_state_callback(context, context_state_callback, NULL); + pa_context_connect(context, NULL); if (pa_mainloop_run(m, &ret) < 0) { fprintf(stderr, "pa_mainloop_run() failed.\n"); @@ -305,8 +298,11 @@ int main(int argc, char *argv[]) { } quit: + if (sample_stream) + pa_stream_unref(sample_stream); + if (context) - pa_context_free(context); + pa_context_unref(context); if (m) { pa_signal_done(); @@ -315,6 +311,6 @@ quit: if (sndfile) sf_close(sndfile); - + return ret; } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 35001d3d..5f849e24 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -31,7 +31,8 @@ #include #include -#include "polyplib.h" +#include "polyplib-internal.h" +#include "polyplib-context.h" #include "native-common.h" #include "pdispatch.h" #include "pstream.h" @@ -42,128 +43,11 @@ #include "util.h" #include "xmalloc.h" -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, + [PA_COMMAND_REQUEST] = { pa_command_request }, + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed }, + [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed }, + [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event }, }; struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { @@ -171,65 +55,41 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * assert(mainloop && name); c = pa_xmalloc(sizeof(struct pa_context)); + c->ref = 1; c->name = pa_xstrdup(name); c->mainloop = mainloop; c->client = NULL; c->pstream = NULL; c->pdispatch = NULL; c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; + assert(c->playback_streams && c->record_streams); + + PA_LLIST_HEAD_INIT(struct pa_stream, c->streams); + PA_LLIST_HEAD_INIT(struct pa_operation, c->operations); + c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; + c->state = PA_CONTEXT_UNCONNECTED; c->ctag = 0; - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; + c->state_callback = NULL; + c->state_userdata = NULL; c->subscribe_callback = NULL; c->subscribe_userdata = NULL; - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - pa_check_for_sigpipe(); return c; } -void pa_context_free(struct pa_context *c) { +static void context_free(struct pa_context *c) { assert(c); - while (c->first_stream) - pa_stream_free(c->first_stream); + while (c->operations) + pa_operation_cancel(c->operations); + + while (c->streams) + pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); if (c->client) pa_socket_client_free(c->client); @@ -237,6 +97,7 @@ void pa_context_free(struct pa_context *c) { pa_pdispatch_free(c->pdispatch); if (c->pstream) pa_pstream_free(c->pstream); + if (c->record_streams) pa_dynarray_free(c->record_streams, NULL, NULL); if (c->playback_streams) @@ -246,66 +107,82 @@ void pa_context_free(struct pa_context *c) { pa_xfree(c); } -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; +struct pa_context* pa_context_ref(struct pa_context *c) { + assert(c && c->ref >= 1); + c->ref++; + return c; } -static void context_dead(struct pa_context *c) { - struct pa_stream *s; +void pa_context_unref(struct pa_context *c) { + assert(c && c->ref >= 1); + + if ((--(c->ref)) == 0) + context_free(c); +} + +void pa_context_set_state(struct pa_context *c, enum pa_context_state st) { assert(c); - if (c->state == CONTEXT_DEAD) + if (c->state == st) return; - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; + pa_context_ref(c); + + if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { + struct pa_stream *s; + + s = c->streams ? pa_stream_ref(c->streams) : NULL; + while (s) { + struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; + pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); + pa_stream_unref(s); + s = n; + } + + if (c->pdispatch) + pa_pdispatch_free(c->pdispatch); + c->pdispatch = NULL; - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; + if (c->pstream) + pa_pstream_free(c->pstream); + c->pstream = NULL; - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; + if (c->client) + pa_socket_client_free(c->client); + c->client = NULL; + } + + c->state = st; + if (c->state_callback) + c->state_callback(c, c->state_userdata); + + pa_context_unref(c); +} + +void pa_context_fail(struct pa_context *c, int error) { + assert(c); + c->error = error; + pa_context_set_state(c, PA_CONTEXT_FAILED); } static void pstream_die_callback(struct pa_pstream *p, void *userdata) { struct pa_context *c = userdata; assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); + pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED); } static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { struct pa_context *c = userdata; assert(p && packet && c); + pa_context_ref(c); + if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); + pa_context_fail(c, PA_ERROR_PROTOCOL); } + + pa_context_unref(c); } static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { @@ -313,90 +190,100 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in struct pa_stream *s; assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; + pa_context_ref(c); + + if ((s = pa_dynarray_get(c->record_streams, channel))) { + if (s->read_callback) + s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + } - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); + pa_context_unref(c); } -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { +int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { assert(c && t); - + if (command == PA_COMMAND_ERROR) { if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; + pa_context_fail(c, PA_ERROR_PROTOCOL); return -1; + } - - return 0; + } else if (command == PA_COMMAND_TIMEOUT) + c->error = PA_ERROR_TIMEOUT; + else { + pa_context_fail(c, PA_ERROR_PROTOCOL); + return -1; } - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; + return 0; } static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); + assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME)); + pa_context_ref(c); + if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); + if (pa_context_handle_error(c, command, t) < 0) + pa_context_fail(c, PA_ERROR_PROTOCOL); - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + goto finish; } - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; + switch(c->state) { + case PA_CONTEXT_AUTHORIZING: { + struct pa_tagstruct *t; + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_puts(t, c->name); + pa_pstream_send_tagstruct(c->pstream, t); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); + + pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); + break; + } - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); + case PA_CONTEXT_SETTING_NAME : + pa_context_set_state(c, PA_CONTEXT_READY); + break; + + default: + assert(0); } - return; +finish: + pa_context_unref(c); } static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { struct pa_context *c = userdata; struct pa_tagstruct *t; uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); + assert(client && c && c->state == PA_CONTEXT_CONNECTING); + pa_context_ref(c); + pa_socket_client_free(client); c->client = NULL; if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } - + + assert(!c->pstream); c->pstream = pa_pstream_new(c->mainloop, io); assert(c->pstream); + pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - + + assert(!c->pdispatch); c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); assert(c->pdispatch); @@ -407,7 +294,11 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; + + pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); + +finish: + pa_context_unref(c); } static struct sockaddr *resolve_server(const char *server, size_t *len) { @@ -438,353 +329,89 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) { return sa; } -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); +int pa_context_connect(struct pa_context *c, const char *server) { + int r = -1; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED); + pa_context_ref(c); + if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; + pa_context_fail(c, PA_ERROR_AUTHKEY); + goto finish; } if (!server) - if (!(server = getenv("POLYP_SERVER"))) + if (!(server = getenv(ENV_DEFAULT_SERVER))) server = DEFAULT_SERVER; assert(!c->client); if (*server == '/') { if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } } else { struct sockaddr* sa; size_t sa_len; if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; + pa_context_fail(c, PA_ERROR_INVALIDSERVER); + goto finish; } c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); pa_xfree(sa); if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; + pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED); + goto finish; } } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; + pa_context_set_state(c, PA_CONTEXT_CONNECTING); - return 0; + r = 0; + +finish: + pa_context_unref(c); + + return r; } -int pa_context_is_dead(struct pa_context *c) { +void pa_context_disconnect(struct pa_context *c) { assert(c); - return c->state == CONTEXT_DEAD; + pa_context_set_state(c, PA_CONTEXT_TERMINATED); } -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; +enum pa_context_state pa_context_get_state(struct pa_context *c) { + assert(c && c->ref >= 1); + return c->state; } int pa_context_errno(struct pa_context *c) { - assert(c); + assert(c && c->ref >= 1); return c->error; } -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; +void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { + assert(c && c->ref >= 1); + c->state_callback = cb; + c->state_userdata = userdata; } int pa_context_is_pending(struct pa_context *c) { - assert(c); + assert(c && c->ref >= 1); - if (c->state != CONTEXT_READY) + if (c->state != PA_CONTEXT_READY) return 0; + assert(c->pstream && c->pdispatch); return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); +static void set_dispatch_callbacks(struct pa_operation *o); static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { set_dispatch_callbacks(userdata); @@ -794,107 +421,59 @@ static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { set_dispatch_callbacks(userdata); } -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); +static void set_dispatch_callbacks(struct pa_operation *o) { + int done = 1; + assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY); - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); + pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); + pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; + if (pa_pdispatch_is_pending(o->context->pdispatch)) { + pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); + done = 0; } - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; + if (pa_pstream_is_pending(o->context->pstream)) { + pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); + done = 0; } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; + if (!done) + pa_operation_ref(o); + else { + if (o->callback) { + void (*cb)(struct pa_context *c, void *userdata); + cb = (void*) o->callback; + cb(o->context, o->userdata); } + + pa_operation_done(o); + } - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } + pa_operation_unref(o); } +struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) { + struct pa_operation *o; + assert(c && c->ref >= 1 && c->state == PA_CONTEXT_READY); -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); + if (!pa_context_is_pending(c)) + return NULL; - if (!complete) { - s->drain_complete_callback = NULL; - return; - } + o = pa_operation_new(c, NULL); + assert(o); + o->callback = cb; + o->userdata = userdata; - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + set_dispatch_callbacks(pa_operation_ref(o)); - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); + return o; } -void pa_context_exit(struct pa_context *c) { +void pa_context_exit_daemon(struct pa_context *c) { struct pa_tagstruct *t; + assert(c && c->ref >= 1); + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_EXIT); @@ -902,649 +481,46 @@ void pa_context_exit(struct pa_context *c) { pa_pstream_send_tagstruct(c->pstream, t); } -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); +void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + if (o->callback) { + void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback; + cb(o->context, success, o->userdata); } - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; +struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; + uint32_t tag; + assert(c && cb); - c->stat_callback = cb; - c->stat_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (cb == NULL) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); + pa_tagstruct_putu32(t, command); pa_tagstruct_putu32(t, tag = c->ctag++); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o); - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); + return pa_operation_ref(o); } diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index a0dd9f9c..6a1cc8bd 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibcontexthfoo +#define foopolyplibcontexthfoo /* $Id$ */ @@ -22,157 +22,71 @@ USA. ***/ -#include - #include "sample.h" #include "polyplib-def.h" #include "mainloop-api.h" +#include "cdecl.h" +#include "polyplib-operation.h" + +/** \file + * Connection contexts */ + +PA_C_DECL_BEGIN + +/** The state of a connection context */ +enum pa_context_state { + PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ + PA_CONTEXT_CONNECTING, /**< A connection is being established */ + PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ + PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ + PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ + PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ + PA_CONTEXT_TERMINATED /**< The connect was terminated cleanly */ +}; -#ifdef __cplusplus -//extern "C" { -#endif - +/** \struct pa_context + * A connection context to a daemon */ struct pa_context; -struct pa_stream; +/** Instantiate a new connection context with an abstract mainloop API + * and an application name */ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); + +/** Decrease the reference counter of the context by one */ void pa_context_unref(struct pa_context *c); + +/** Increase the reference counter of the context by one */ struct pa_context* pa_context_ref(struct pa_context *c); -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); +/** Set a callback function that is called whenever the context status changes */ +void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); +/** Return the error number of the last failed operation */ int pa_context_errno(struct pa_context *c); +/** Return non-zero if some data is pending to be written to the connection */ int pa_context_is_pending(struct pa_context *c); -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); +/** Return the current context status */ +enum pa_context_state pa_context_get_state(struct pa_context *c); -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); +/** Connect the context to the specified server. If server is NULL, +connect to the default server. This routine may but will not always +return synchronously on error. Use pa_context_set_state_callback() to +be notified when the connection is established */ +int pa_context_connect(struct pa_context *c, const char *server); -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); +/** Terminate the context connection immediately */ +void pa_context_disconnect(struct pa_context *c); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); +/** Drain the context. If there is nothing to drain, the function returns NULL */ +struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata); -struct pa_context* pa_stream_get_context(struct pa_stream *p); +/** Tell the daemon to exit. No operation object is returned as the + * connection is terminated when the daemon quits, thus this operation + * would never complete. */ +void pa_context_exit_daemon(struct pa_context *c); -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index d96c6899..fc19be69 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -23,14 +23,13 @@ ***/ #include - -#ifdef __cplusplus -extern "C" { -#endif - #include "native-common.h" +#include "cdecl.h" + +PA_C_DECL_BEGIN enum pa_stream_direction { + PA_STREAM_NODIRECTION, PA_STREAM_PLAYBACK, PA_STREAM_RECORD, PA_STREAM_UPLOAD @@ -43,9 +42,9 @@ struct pa_buffer_attr { uint32_t minreq; uint32_t fragsize; }; - -#ifdef __cplusplus -} -#endif + +#define PA_INVALID_INDEX ((uint32_t) -1) + +PA_C_DECL_END #endif diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index d76ce6ff..d7519af4 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -23,15 +23,13 @@ ***/ #include +#include "cdecl.h" -#ifdef __cplusplus -extern "C" { -#endif +PA_C_DECL_BEGIN; +/** Return a human readable error message for the specified numeric error code */ const char* pa_strerror(uint32_t error); -#ifdef __cplusplus -} -#endif - +PA_C_DECL_END; + #endif diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 35001d3d..0b6b3887 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -1,3 +1,6 @@ +#ifndef foopolyplibinternalhfoo +#define foopolyplibinternalhfoo + /* $Id$ */ /*** @@ -19,28 +22,16 @@ USA. ***/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" +#include "mainloop-api.h" +#include "socket-client.h" #include "pstream.h" +#include "pdispatch.h" #include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" + +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "polyplib-operation.h" +#include "llist.h" #define DEFAULT_MAXLENGTH 204800 #define DEFAULT_TLENGTH 10240 @@ -52,68 +43,41 @@ #define DEFAULT_SERVER "/tmp/polypaudio/native" #define DEFAULT_PORT "4713" +#define ENV_DEFAULT_SINK "POLYP_SINK" +#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" +#define ENV_DEFAULT_SERVER "POLYP_SERVER" + struct pa_context { + int ref; + char *name; struct pa_mainloop_api* mainloop; + struct pa_socket_client *client; struct pa_pstream *pstream; struct pa_pdispatch *pdispatch; + struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; + PA_LLIST_HEAD(struct pa_stream, streams); + PA_LLIST_HEAD(struct pa_operation, operations); + uint32_t ctag; uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; + enum pa_context_state state; - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; + void (*state_callback)(struct pa_context*c, void *userdata); + void *state_userdata; void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; struct pa_stream { + int ref; struct pa_context *context; - struct pa_stream *next, *previous; + PA_LLIST_FIELDS(struct pa_stream); char *name; struct pa_buffer_attr buffer_attr; @@ -122,1429 +86,47 @@ struct pa_stream { int channel_valid; uint32_t device_index; enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; uint32_t requested_bytes; + enum pa_stream_state state; + + void (*state_callback)(struct pa_stream*c, void *userdata); + void *state_userdata; void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); void *read_userdata; void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; }; -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +struct pa_operation { + int ref; + struct pa_context *context; + struct pa_stream *stream; + PA_LLIST_FIELDS(struct pa_operation); -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, + enum pa_operation_state state; + void *userdata; + void (*callback)(); }; -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); +void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - pa_socket_client_free(client); - c->client = NULL; +struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s); +void pa_operation_done(struct pa_operation *o); - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} +void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} +void pa_context_fail(struct pa_context *c, int error); +void pa_context_set_state(struct pa_context *c, enum pa_context_state st); +int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t); +struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata); -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} +void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st); -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} +#endif diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 35001d3d..345a9cd5 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -23,1528 +23,421 @@ #include #endif -#include #include -#include -#include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } +#include "polyplib-introspect.h" +#include "polyplib-context.h" +#include "polyplib-internal.h" +#include "pstream-util.h" - return 0; - } +/*** Statistics ***/ - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); +static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + struct pa_stat_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; + p = NULL; + } else if (pa_tagstruct_getu32(t, &i.memblock_count) < 0 || + pa_tagstruct_getu32(t, &i.memblock_total) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_stat_info*i, void *userdata) = o->callback; + cb(o->context, p, o->userdata); } - return; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; +struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, cb, userdata); } -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); +/*** Server Info ***/ - freeaddrinfo(result); - - return sa; -} +static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + struct pa_server_info i, *p = &i; + assert(pd && o && o->context && o->ref >= 1); -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; + p = NULL; + } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || + pa_tagstruct_gets(t, &i.server_version) < 0 || + pa_tagstruct_gets(t, &i.user_name) < 0 || + pa_tagstruct_gets(t, &i.host_name) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_server_info*i, void *userdata) = o->callback; + cb(o->context, p, o->userdata); } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; +struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, cb, userdata); } -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; +/*** Sink Info ***/ - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); +static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_sink_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + pa_tagstruct_getu32(t, &i.owner_module) < 0 || + 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_getu32(t, &i.latency) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - set_dispatch_callbacks(c); - - return 0; +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } +struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, cb, userdata); } - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } + assert(c && cb); - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); + pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o); - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); + return pa_operation_ref(o); } -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; +/*** Source info ***/ - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); +static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_source_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.description) < 0 || + pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || + 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_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, cb, userdata); } -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; +struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - - s = internal_stream_new(c); - assert(s); + assert(c && cb); - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o); - return s; + return pa_operation_ref(o); } -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} +/*** Client info ***/ -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; + eof = -1; + } else { + + while (!pa_tagstruct_eof(t)) { + struct pa_client_info i; + + 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_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } + } } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(c && name && *name && (!dev || *dev)); + assert(c && cb); - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); + pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, index); + pa_tagstruct_puts(t, ""); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o); - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); + return pa_operation_ref(o); } -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); +struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, cb, userdata); } -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} +/*** Module info ***/ -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int eof = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; + eof = -1; + } else { - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + while (!pa_tagstruct_eof(t)) { + struct pa_module_info i; + + if (pa_tagstruct_getu32(t, &i.index) < 0 || + pa_tagstruct_gets(t, &i.name) < 0 || + pa_tagstruct_gets(t, &i.argument) < 0 || + pa_tagstruct_getu32(t, &i.n_used) < 0 || + pa_tagstruct_getu32(t, &i.auto_unload) < 0) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } + + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + cb(o->context, &i, 0, o->userdata); + } } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); + if (o->callback) { + void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback; + cb(o->context, NULL, eof, o->userdata); } - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); +finish: + pa_operation_done(o); + pa_operation_unref(o); } -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { struct pa_tagstruct *t; + struct pa_operation *o; uint32_t tag; - assert(c); + assert(c && cb); - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, index); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o); - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); + return pa_operation_ref(o); } -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); +struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { + return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, cb, userdata); } -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); +/*** Volume manipulation ***/ - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); + assert(c && index != PA_INVALID_INDEX); - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); pa_tagstruct_puts(t, ""); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); + return pa_operation_ref(o); } - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); + assert(c && name); - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, PA_INVALID_INDEX); + pa_tagstruct_puts(t, name); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; - assert(c); + assert(c && index != PA_INVALID_INDEX); - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); + pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_putu32(t, index); + pa_tagstruct_putu32(t, volume); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); + return pa_operation_ref(o); } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index a0dd9f9c..bca752e2 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibintrospecthfoo +#define foopolyplibintrospecthfoo /* $Id$ */ @@ -22,61 +22,13 @@ USA. ***/ -#include +#include -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-operation.h" +#include "polyplib-context.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN struct pa_sink_info { const char *name; @@ -90,9 +42,9 @@ struct pa_sink_info { uint32_t latency; }; -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); struct pa_source_info { const char *name; @@ -104,9 +56,9 @@ struct pa_source_info { const char *monitor_of_sink_name; }; -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); struct pa_server_info { const char *user_name; @@ -116,7 +68,7 @@ struct pa_server_info { struct pa_sample_spec sample_spec; }; -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); struct pa_module_info { uint32_t index; @@ -124,8 +76,8 @@ struct pa_module_info { uint32_t n_used, auto_unload; }; -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); struct pa_client_info { uint32_t index; @@ -134,8 +86,8 @@ struct pa_client_info { const char *protocol_name; }; -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); struct pa_sink_input_info { uint32_t index; @@ -148,8 +100,8 @@ struct pa_sink_input_info { uint32_t latency; }; -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); struct pa_source_output_info { uint32_t index; @@ -160,19 +112,20 @@ struct pa_source_output_info { struct pa_sample_spec sample_spec; }; -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); +struct pa_stat_info { + uint32_t memblock_count; + uint32_t memblock_total; +}; -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c new file mode 100644 index 00000000..994ac016 --- /dev/null +++ b/polyp/polyplib-operation.c @@ -0,0 +1,78 @@ +#include + +#include "xmalloc.h" +#include "polyplib-internal.h" +#include "polyplib-operation.h" + +struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s) { + struct pa_operation *o; + assert(c); + + o = pa_xmalloc(sizeof(struct pa_operation)); + o->ref = 1; + o->context = pa_context_ref(c); + o->stream = s ? pa_stream_ref(s) : NULL; + + o->state = PA_OPERATION_RUNNING; + o->userdata = NULL; + o->callback = NULL; + + PA_LLIST_PREPEND(struct pa_operation, o->context->operations, o); + return pa_operation_ref(o); +} + +struct pa_operation *pa_operation_ref(struct pa_operation *o) { + assert(o && o->ref >= 1); + o->ref++; + return o; +} + +void pa_operation_unref(struct pa_operation *o) { + assert(o && o->ref >= 1); + + if ((--(o->ref)) == 0) { + assert(!o->context); + assert(!o->stream); + free(o); + } +} + +static void operation_set_state(struct pa_operation *o, enum pa_operation_state st) { + assert(o && o->ref >= 1); + + if (st == o->state) + return; + + if (!o->context) + return; + + o->state = st; + + if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { + PA_LLIST_REMOVE(struct pa_operation, o->context->operations, o); + pa_context_unref(o->context); + if (o->stream) + pa_stream_unref(o->stream); + o->context = NULL; + o->stream = NULL; + o->callback = NULL; + o->userdata = NULL; + + pa_operation_unref(o); + } +} + +void pa_operation_cancel(struct pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_CANCELED); +} + +void pa_operation_done(struct pa_operation *o) { + assert(o && o->ref >= 1); + operation_set_state(o, PA_OPERATION_DONE); +} + +enum pa_operation_state pa_operation_get_state(struct pa_operation *o) { + assert(o && o->ref >= 1); + return o->state; +} diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h new file mode 100644 index 00000000..7d0adc26 --- /dev/null +++ b/polyp/polyplib-operation.h @@ -0,0 +1,56 @@ +#ifndef foopolypliboperationhfoo +#define foopolypliboperationhfoo + +/* $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 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 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 "cdecl.h" + +/** \file + * Asynchronous operations */ + +PA_C_DECL_BEGIN + +enum pa_operation_state { + PA_OPERATION_RUNNING, /**< The operation is still running */ + PA_OPERATION_DONE, /**< The operation has been completed */ + PA_OPERATION_CANCELED, /**< The operation has been canceled */ +}; + +/** \struct pa_operation + * An asynchronous operation object */ +struct pa_operation; + +/** Increase the reference count by one */ +struct pa_operation *pa_operation_ref(struct pa_operation *o); + +/** Decrease the reference count by one */ +void pa_operation_unref(struct pa_operation *o); + +/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ +void pa_operation_cancel(struct pa_operation *o); + +/** Return the current status of the operation */ +enum pa_operation_state pa_operation_get_state(struct pa_operation *o); + +PA_C_DECL_END + +#endif diff --git a/polyp/polyplib-sample.c b/polyp/polyplib-sample.c deleted file mode 100644 index 35001d3d..00000000 --- a/polyp/polyplib-sample.c +++ /dev/null @@ -1,1550 +0,0 @@ -/* $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 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 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 "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-sample.h b/polyp/polyplib-sample.h deleted file mode 100644 index a0dd9f9c..00000000 --- a/polyp/polyplib-sample.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo - -/* $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 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 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 - -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" - -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 35001d3d..8215eaec 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -23,1083 +23,73 @@ #include #endif -#include #include #include +#include #include -#include -#include -#include -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" +#include "polyplib-scache.h" +#include "polyplib-internal.h" #include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; +void pa_stream_connect_upload(struct pa_stream *s, size_t length) { struct pa_tagstruct *t; uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); + assert(s && length); - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); + pa_stream_ref(s); - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); + s->state = PA_STREAM_CREATING; + s->direction = PA_STREAM_UPLOAD; - s->state = STREAM_CREATING; - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_puts(t, s->name); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - + pa_tagstruct_putu32(t, length); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); + pa_stream_unref(s); } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +void pa_stream_finish_upload(struct pa_stream *s) { struct pa_tagstruct *t; uint32_t tag; - assert(s && s->state == STREAM_READY); + assert(s); - if (!complete) { - s->drain_complete_callback = NULL; + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) return; - } - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); + pa_stream_unref(s); } -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c && name && *name && (!dev || *dev)); - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; + if (!dev) + dev = getenv(ENV_DEFAULT_SINK); + t = pa_tagstruct_new(NULL, 0); assert(t); pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); @@ -1109,44 +99,20 @@ void pa_context_play_sample(struct pa_context *c, const char *name, const char * pa_tagstruct_putu32(t, volume); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); + return pa_operation_ref(o); } -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { +struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c && name); - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; t = pa_tagstruct_new(NULL, 0); assert(t); @@ -1154,397 +120,8 @@ void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb) pa_tagstruct_putu32(t, tag = c->ctag++); pa_tagstruct_puts(t, name); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index a0dd9f9c..ce74bef0 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibscachehfoo +#define foopolyplibscachehfoo /* $Id$ */ @@ -24,155 +24,27 @@ #include -#include "sample.h" -#include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); +/** \file + * All sample cache related routines */ -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Make this stream a sample upload stream */ +void pa_stream_connect_upload(struct pa_stream *s, size_t length); -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; +/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */ +void pa_stream_finish_upload(struct pa_stream *s); -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); +/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ +struct pa_operation* pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; +/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ +struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 1f5ea553..66ee5995 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -49,15 +49,28 @@ struct pa_simple { static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata); static int check_error(struct pa_simple *p, int *perror) { + enum pa_context_state cst; + enum pa_stream_state sst; assert(p); - if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) { - if (perror) - *perror = pa_context_errno(p->context); - return -1; - } + if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) + goto fail; + assert(cst != PA_CONTEXT_TERMINATED); + + if (p->stream) { + if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED) + goto fail; + + assert(sst != PA_STREAM_TERMINATED); + } + return 0; + +fail: + if (perror) + *perror = pa_context_errno(p->context); + return -1; } static int iterate(struct pa_simple *p, int block, int *perror) { @@ -96,7 +109,7 @@ struct pa_simple* pa_simple_new( struct pa_simple *p; int error = PA_ERROR_INTERNAL; - assert(ss); + assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); p = pa_xmalloc(sizeof(struct pa_simple)); p->context = NULL; @@ -110,23 +123,25 @@ struct pa_simple* pa_simple_new( if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name))) goto fail; - - if (pa_context_connect(p->context, server, NULL, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } + + pa_context_connect(p->context, server); /* Wait until the context is ready */ - while (!pa_context_is_ready(p->context)) { + while (pa_context_get_state(p->context) != PA_CONTEXT_READY) { if (iterate(p, 1, &error) < 0) goto fail; } - if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL))) + if (!(p->stream = pa_stream_new(p->context, stream_name, ss))) goto fail; + if (dir == PA_STREAM_PLAYBACK) + pa_stream_connect_playback(p->stream, dev, attr); + else + pa_stream_connect_record(p->stream, dev, attr); + /* Wait until the stream is ready */ - while (!pa_stream_is_ready(p->stream)) { + while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { if (iterate(p, 1, &error) < 0) goto fail; } @@ -148,10 +163,10 @@ void pa_simple_free(struct pa_simple *s) { pa_xfree(s->read_data); if (s->stream) - pa_stream_free(s->stream); + pa_stream_unref(s->stream); if (s->context) - pa_context_free(s->context); + pa_context_unref(s->context); if (s->mainloop) pa_mainloop_free(s->mainloop); @@ -172,7 +187,7 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe if (l > length) l = length; - pa_stream_write(p->stream, data, l); + pa_stream_write(p->stream, data, l, NULL); data += l; length -= l; } @@ -193,8 +208,7 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v pa_xfree(p->read_data); } - p->read_data = pa_xmalloc(p->read_length = length); - memcpy(p->read_data, data, length); + p->read_data = pa_xmemdup(data, p->read_length = length); p->read_index = 0; } @@ -235,23 +249,31 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) { return 0; } -static void drain_complete(struct pa_stream *s, void *userdata) { +static void drain_complete(struct pa_stream *s, int success, void *userdata) { struct pa_simple *p = userdata; assert(s && p); - p->drained = 1; + p->drained = success ? 1 : -1; } int pa_simple_drain(struct pa_simple *p, int *perror) { + struct pa_operation *o; + assert(p && p->direction == PA_STREAM_PLAYBACK); p->drained = 0; - pa_stream_drain(p->stream, drain_complete, p); + o = pa_stream_drain(p->stream, drain_complete, p); while (!p->drained) { if (iterate(p, 1, perror) < 0) { - pa_stream_drain(p->stream, NULL, NULL); + pa_operation_cancel(o); + pa_operation_unref(o); return -1; } } + pa_operation_unref(o); + + if (p->drained < 0 && perror) + *perror = pa_context_errno(p->context); + return 0; } diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index 0544410c..ee2e27e3 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -26,24 +26,41 @@ #include "sample.h" #include "polyplib-def.h" +#include "cdecl.h" +/** \file + * A simple but limited synchronous playback and recording API. */ + +PA_C_DECL_BEGIN + +/** \struct pa_simple + * A simple connection object */ struct pa_simple; +/** Create a new connection to the server */ struct pa_simple* pa_simple_new( - const char *server, - const char *name, - enum pa_stream_direction dir, - const char *dev, - const char *stream_name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - int *error); + const char *server, /**< Server name, or NULL for default */ + const char *name, /**< A descriptive name for this client (application name, ...) */ + enum pa_stream_direction dir, /**< Open this stream for recording or playback? */ + const char *dev, /**< Sink (resp. source) name, or NULL for default */ + const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ + const struct pa_sample_spec *ss, /**< The sample type to use */ + const struct pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ + int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ + ); +/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ void pa_simple_free(struct pa_simple *s); +/** Write some data to the server */ int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error); + +/** Wait until all data already written is played by the daemon */ int pa_simple_drain(struct pa_simple *s, int *error); +/** Read some data from the server */ int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error); +PA_C_DECL_END + #endif diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 35001d3d..362dbad1 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -23,576 +23,217 @@ #include #endif -#include #include -#include #include -#include -#include -#include - -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; +#include - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; +#include "polyplib-internal.h" +#include "xmalloc.h" +#include "pstream-util.h" - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; +struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) { + assert(c && ss); + struct pa_stream *s; - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; + s = pa_xmalloc(sizeof(struct pa_stream)); + s->ref = 1; + s->context = c; - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; + s->read_callback = NULL; + s->read_userdata = NULL; + s->write_callback = NULL; + s->write_userdata = NULL; + s->state_callback = NULL; + s->state_userdata = NULL; - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} + s->state = PA_STREAM_NODIRECTION; + s->name = pa_xstrdup(name); + s->sample_spec = *ss; + s->channel = 0; + s->channel_valid = 0; + s->device_index = PA_INVALID_INDEX; + s->requested_bytes = 0; + s->state = PA_STREAM_DISCONNECTED; + memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); -void pa_context_free(struct pa_context *c) { - assert(c); + PA_LLIST_PREPEND(struct pa_stream, c->streams, s); - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); + return pa_stream_ref(s); } -static void stream_dead(struct pa_stream *s) { +static void stream_free(struct pa_stream *s) { assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); + pa_xfree(s->name); + pa_xfree(s); } -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); +void pa_stream_unref(struct pa_stream *s) { + assert(s && s->ref >= 1); - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } + if (--(s->ref) == 0) + stream_free(s); } -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +struct pa_stream* pa_stream_ref(struct pa_stream *s) { + assert(s && s->ref >= 1); + s->ref++; + return s; } -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; +enum pa_stream_state pa_stream_get_state(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->state; } -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; +struct pa_context* pa_stream_get_context(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->context; } -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; +uint32_t pa_stream_get_index(struct pa_stream *s) { + assert(s && s->ref >= 1); + return s->device_index; } - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); +void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) { + assert(s && s->ref >= 1); - freeaddrinfo(result); + if (s->state == st) + return; - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; + pa_stream_ref(s); - assert(!c->client); + s->state = st; - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } + if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { + if (s->channel_valid) + pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } + PA_LLIST_REMOVE(struct pa_stream, s->context->streams, s); + pa_stream_unref(s); } - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} + if (s->state_callback) + s->state_callback(s, s->state_userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; + pa_stream_unref(s); } -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; struct pa_stream *s; uint32_t channel; assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &channel) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; + goto finish; c->error = PA_ERROR_KILLED; - stream_dead(s); + pa_stream_set_state(s, PA_STREAM_FAILED); + +finish: + pa_context_unref(c); } -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s; struct pa_context *c = userdata; uint32_t bytes, channel; assert(pd && command == PA_COMMAND_REQUEST && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &channel) < 0 || pa_tagstruct_getu32(t, &bytes) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; + goto finish; - if (s->state != STREAM_READY) - return; + if (s->state != PA_STREAM_READY) + goto finish; + + pa_stream_ref(s); s->requested_bytes += bytes; if (s->requested_bytes && s->write_callback) s->write_callback(s, s->requested_bytes, s->write_userdata); + + pa_stream_unref(s); + +finish: + pa_context_unref(c); } -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); + assert(pd && s && s->state == PA_STREAM_CREATING); + pa_stream_ref(s); + if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; + + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; } if (pa_tagstruct_getu32(t, &s->channel) < 0 || ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; } s->channel_valid = 1; pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); + pa_stream_set_state(s, PA_STREAM_READY); + +finish: + pa_stream_unref(s); } -static void create_stream(struct pa_stream *s, const char *dev) { +static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { struct pa_tagstruct *t; uint32_t tag; - assert(s); + assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); + + pa_stream_ref(s); + + if (attr) + s->buffer_attr = *attr; + else { + s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; + s->buffer_attr.tlength = DEFAULT_TLENGTH; + s->buffer_attr.prebuf = DEFAULT_PREBUF; + s->buffer_attr.minreq = DEFAULT_MINREQ; + s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; + } - s->state = STREAM_CREATING; + pa_stream_set_state(s, PA_STREAM_CREATING); t = pa_tagstruct_new(NULL, 0); assert(t); + + if (!dev) { + if (s->direction == PA_STREAM_PLAYBACK) + dev = getenv(ENV_DEFAULT_SINK); + else + dev = getenv(ENV_DEFAULT_SOURCE); + } pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); pa_tagstruct_putu32(t, tag = s->context->ctag++); @@ -609,135 +250,40 @@ static void create_stream(struct pa_stream *s, const char *dev) { pa_tagstruct_putu32(t, s->buffer_attr.fragsize); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s); - create_stream(s, dev); - - return s; + pa_stream_unref(s); } -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_PLAYBACK; + create_stream(s, dev, attr); } -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { + assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); + s->direction = PA_STREAM_RECORD; + create_stream(s, dev, attr); } -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { +void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p)) { struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); + assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1); - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); + if (free_cb) { + chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb); + assert(chunk.memblock && chunk.memblock->data); + } else { + chunk.memblock = pa_memblock_new(length); + assert(chunk.memblock && chunk.memblock->data); + memcpy(chunk.memblock->data, data, length); + } chunk.index = 0; chunk.length = length; pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ if (length < s->requested_bytes) s->requested_bytes -= length; @@ -746,805 +292,163 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { } size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); + assert(s && s->state == PA_STREAM_READY && s->ref >= 1); return s->requested_bytes; } -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} +struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { + struct pa_operation *o; + struct pa_tagstruct *t; + uint32_t tag; + assert(s && s->ref >= 1 && s->state == PA_STREAM_READY); -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; + return pa_operation_ref(o); } -int pa_context_is_pending(struct pa_context *c) { - assert(c); +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + uint32_t latency; + assert(pd && o && o->stream && o->context); - if (c->state != CONTEXT_READY) - return 0; + if (command != PA_COMMAND_REPLY) { + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} + latency = (uint32_t) -1; + } else if (pa_tagstruct_getu32(t, &latency) < 0 || !pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; + } -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; + if (o->callback) { + void (*cb)(struct pa_stream *s, uint32_t latency, void *userdata) = o->callback; + cb(o->stream, latency, o->userdata); + } + +finish: + pa_operation_done(o); + pa_operation_unref(o); } -static void set_dispatch_callbacks(struct pa_context *c); +struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_operation *o; + struct pa_tagstruct *t; + + o = pa_operation_new(s->context, s); + assert(o); + o->callback = cb; + o->userdata = userdata; -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = s->context->ctag++); + pa_tagstruct_putu32(t, s->channel); + pa_pstream_send_tagstruct(s->context->pstream, t); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o); -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); + return pa_operation_ref(o); } -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); +void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + assert(pd && s && s->ref >= 1); - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } + pa_stream_ref(s); - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } + if (pa_context_handle_error(s->context, command, t) < 0) + goto finish; - stream_dead(s); - return; + pa_stream_set_state(s, PA_STREAM_FAILED); + goto finish; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(s->context, PA_ERROR_PROTOCOL); + goto finish; } - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } + pa_stream_set_state(s, PA_STREAM_TERMINATED); - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } +finish: + pa_stream_unref(s); } - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { +void pa_stream_disconnect(struct pa_stream *s) { struct pa_tagstruct *t; uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; + assert(s && s->ref >= 1); + + if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY) return; - } - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; + pa_stream_ref(s); t = pa_tagstruct_new(NULL, 0); assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); + pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : + (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); pa_tagstruct_putu32(t, tag = s->context->ctag++); pa_tagstruct_putu32(t, s->channel); pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s); - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); + pa_stream_unref(s); } -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->read_callback = cb; + s->read_userdata = userdata; } - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->write_callback = cb; + s->write_userdata = userdata; } -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); +void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { + assert(s && s->ref >= 1); + s->state_callback = cb; + s->state_userdata = userdata; } -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); +void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_operation *o = userdata; + int success = 1; + assert(pd && o && o->context && o->ref >= 1); if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } + if (pa_context_handle_error(o->context, command, t) < 0) + goto finish; - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; + success = 0; + } else if (!pa_tagstruct_eof(t)) { + pa_context_fail(o->context, PA_ERROR_PROTOCOL); + goto finish; } - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); + if (o->callback) { + void (*cb)(struct pa_stream *s, int success, void *userdata) = o->callback; + cb(o->stream, success, o->userdata); } - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); +finish: + pa_operation_done(o); + pa_operation_unref(o); } diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index a0dd9f9c..41801c6c 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibstreamhfoo +#define foopolyplibstreamhfoo /* $Id$ */ @@ -26,153 +26,79 @@ #include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" +#include "cdecl.h" +#include "polyplib-operation.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; +/** \file + * Audio streams for input, output and sample upload */ -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); +PA_C_DECL_BEGIN -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); +/** The state of a stream */ +enum pa_stream_state { + PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */ + PA_STREAM_CREATING, /**< The stream is being created */ + PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ + PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ + PA_STREAM_TERMINATED, /**< The stream has been terminated cleanly */ +}; -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); +/** \struct pa_stream + * A stream for playback or recording */ +struct pa_stream; -int pa_context_is_pending(struct pa_context *c); +/** Create a new, unconnected stream with the specified name and sample type */ +struct pa_stream* pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss); -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); +/** Decrease the reference counter by one */ void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); +/** Increase the reference counter by one */ +struct pa_stream *pa_stream_ref(struct pa_stream *s); -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); +/** Return the current state of the stream */ +enum pa_stream_state pa_stream_get_state(struct pa_stream *p); +/** Return the context this stream is attached to */ struct pa_context* pa_stream_get_context(struct pa_stream *p); +/** Return the device (sink input or source output) index this stream is connected to */ uint32_t pa_stream_get_index(struct pa_stream *s); -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); +/** Connect the stream to a sink */ +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; +/** Connect the stream to a source */ +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); +/** Disconnect a stream from a source/sink */ +void pa_stream_disconnect(struct pa_stream *s); -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; +/** Write some data to the server (for playback sinks), if free_cb is + * non-NULL this routine is called when all data has been written out + * and an internal reference to the specified data is kept, the data + * is not copied. If NULL, the data is copied into an internal + * buffer. */ +void pa_stream_write(struct pa_stream *p, const void *data, size_t length, void (*free_cb)(void *p)); -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); +/** Return the amount of bytes that may be written using pa_stream_write() */ +size_t pa_stream_writable_size(struct pa_stream *p); -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; +/** Drain a playback stream */ +struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); +/** Get the playback latency of a stream */ +struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +/** Set the callback function that is called whenever the state of the stream changes */ +void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); +/** Set the callback function that is called when new data may be written to the stream */ +void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +/** Set the callback function that is called when new data is available from the stream */ +void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 35001d3d..a14d0b06 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -23,1528 +23,52 @@ #include #endif -#include #include -#include -#include -#include -#include -#include -#include "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" +#include "polyplib-subscribe.h" +#include "polyplib-internal.h" #include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { struct pa_context *c = userdata; enum pa_subscription_event_type e; uint32_t index; assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); + pa_context_ref(c); + if (pa_tagstruct_getu32(t, &e) < 0 || pa_tagstruct_getu32(t, &index) < 0 || !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; + pa_context_fail(c, PA_ERROR_PROTOCOL); + goto finish; } - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) + if (c->subscribe_callback) c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); +finish: + pa_context_unref(c); } -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { +struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { + struct pa_operation *o; struct pa_tagstruct *t; uint32_t tag; assert(c); - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; + o = pa_operation_new(c, NULL); + o->callback = cb; + o->userdata = userdata; - if (!cb) - return; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); pa_tagstruct_putu32(t, tag = c->ctag++); + pa_tagstruct_putu32(t, cb ? m : 0); pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; + pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o); - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); + return pa_operation_ref(o); } -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index a0dd9f9c..56384915 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibsubscribehfoo +#define foopolyplibsubscribehfoo /* $Id$ */ @@ -22,157 +22,17 @@ USA. ***/ -#include +#include -#include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" +#include "polyplib-context.h" +#include "cdecl.h" -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +PA_C_DECL_BEGIN -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; +struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +PA_C_DECL_END #endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c deleted file mode 100644 index 35001d3d..00000000 --- a/polyp/polyplib.c +++ /dev/null @@ -1,1550 +0,0 @@ -/* $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 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 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 "polyplib.h" -#include "native-common.h" -#include "pdispatch.h" -#include "pstream.h" -#include "dynarray.h" -#include "socket-client.h" -#include "pstream-util.h" -#include "authkey.h" -#include "util.h" -#include "xmalloc.h" - -#define DEFAULT_MAXLENGTH 204800 -#define DEFAULT_TLENGTH 10240 -#define DEFAULT_PREBUF 4096 -#define DEFAULT_MINREQ 1024 -#define DEFAULT_FRAGSIZE 1024 - -#define DEFAULT_TIMEOUT (5*60) -#define DEFAULT_SERVER "/tmp/polypaudio/native" -#define DEFAULT_PORT "4713" - -struct pa_context { - char *name; - struct pa_mainloop_api* mainloop; - struct pa_socket_client *client; - struct pa_pstream *pstream; - struct pa_pdispatch *pdispatch; - struct pa_dynarray *record_streams, *playback_streams; - struct pa_stream *first_stream; - uint32_t ctag; - uint32_t error; - enum { - CONTEXT_UNCONNECTED, - CONTEXT_CONNECTING, - CONTEXT_AUTHORIZING, - CONTEXT_SETTING_NAME, - CONTEXT_READY, - CONTEXT_DEAD - } state; - - void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata); - void *connect_complete_userdata; - - void (*drain_complete_callback)(struct pa_context*c, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_context*c, void *userdata); - void *die_userdata; - - void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata); - void *stat_userdata; - - void (*play_sample_callback)(struct pa_context*c, int success, void *userdata); - void *play_sample_userdata; - - void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata); - void *remove_sample_userdata; - - void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata); - void *get_server_info_userdata; - - void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata); - void *get_sink_info_userdata; - - void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata); - void *get_source_info_userdata; - - void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); - void *subscribe_userdata; - enum pa_subscription_mask subscribe_mask; - - void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata); - void *get_client_info_userdata; - - void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata); - void *get_module_info_userdata; - - uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; -}; - -struct pa_stream { - struct pa_context *context; - struct pa_stream *next, *previous; - - char *name; - struct pa_buffer_attr buffer_attr; - struct pa_sample_spec sample_spec; - uint32_t channel; - int channel_valid; - uint32_t device_index; - enum pa_stream_direction direction; - - enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state; - uint32_t requested_bytes; - - void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata); - void *read_userdata; - - void (*write_callback)(struct pa_stream *p, size_t length, void *userdata); - void *write_userdata; - - void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata); - void *create_complete_userdata; - - void (*drain_complete_callback)(struct pa_stream *s, void *userdata); - void *drain_complete_userdata; - - void (*die_callback)(struct pa_stream*c, void *userdata); - void *die_userdata; - - void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); - void *get_latency_userdata; - - void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata); - void *finish_sample_userdata; -}; - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); - -static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_ERROR] = { NULL }, - [PA_COMMAND_REPLY] = { NULL }, - [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL }, - [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL }, - [PA_COMMAND_EXIT] = { NULL }, - [PA_COMMAND_REQUEST] = { command_request }, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed }, - [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event }, -}; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) { - struct pa_context *c; - assert(mainloop && name); - - c = pa_xmalloc(sizeof(struct pa_context)); - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - assert(c->playback_streams); - c->record_streams = pa_dynarray_new(); - assert(c->record_streams); - c->first_stream = NULL; - c->error = PA_ERROR_OK; - c->state = CONTEXT_UNCONNECTED; - c->ctag = 0; - - c->connect_complete_callback = NULL; - c->connect_complete_userdata = NULL; - - c->drain_complete_callback = NULL; - c->drain_complete_userdata = NULL; - - c->die_callback = NULL; - c->die_userdata = NULL; - - c->stat_callback = NULL; - c->stat_userdata = NULL; - - c->play_sample_callback = NULL; - c->play_sample_userdata = NULL; - - c->remove_sample_callback = NULL; - c->remove_sample_userdata = NULL; - - c->get_server_info_callback = NULL; - c->get_server_info_userdata = NULL; - - c->get_sink_info_callback = NULL; - c->get_sink_info_userdata = NULL; - - c->get_source_info_callback = NULL; - c->get_source_info_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->get_client_info_callback = NULL; - c->get_client_info_userdata = NULL; - - c->get_module_info_callback = NULL; - c->get_module_info_userdata = NULL; - - pa_check_for_sigpipe(); - return c; -} - -void pa_context_free(struct pa_context *c) { - assert(c); - - while (c->first_stream) - pa_stream_free(c->first_stream); - - if (c->client) - pa_socket_client_free(c->client); - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - if (c->pstream) - pa_pstream_free(c->pstream); - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_xfree(c->name); - pa_xfree(c); -} - -static void stream_dead(struct pa_stream *s) { - assert(s); - - if (s->state == STREAM_DEAD) - return; - - if (s->state == STREAM_READY) { - s->state = STREAM_DEAD; - if (s->die_callback) - s->die_callback(s, s->die_userdata); - } else - s->state = STREAM_DEAD; -} - -static void context_dead(struct pa_context *c) { - struct pa_stream *s; - assert(c); - - if (c->state == CONTEXT_DEAD) - return; - - if (c->pdispatch) - pa_pdispatch_free(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) - pa_pstream_free(c->pstream); - c->pstream = NULL; - - if (c->client) - pa_socket_client_free(c->client); - c->client = NULL; - - for (s = c->first_stream; s; s = s->next) - stream_dead(s); - - if (c->state == CONTEXT_READY) { - c->state = CONTEXT_DEAD; - if (c->die_callback) - c->die_callback(c, c->die_userdata); - } else - c->state = CONTEXT_DEAD; -} - -static void pstream_die_callback(struct pa_pstream *p, void *userdata) { - struct pa_context *c = userdata; - assert(p && c); - c->error = PA_ERROR_CONNECTIONTERMINATED; - context_dead(c); -} - -static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { - struct pa_context *c = userdata; - assert(p && packet && c); - - if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) { - fprintf(stderr, "polyp.c: invalid packet.\n"); - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - } -} - -static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - assert(p && chunk && c && chunk->memblock && chunk->memblock->data); - - if (!(s = pa_dynarray_get(c->record_streams, channel))) - return; - - if (s->read_callback) - s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); -} - -static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) { - assert(c && t); - - if (command == PA_COMMAND_ERROR) { - if (pa_tagstruct_getu32(t, &c->error) < 0) { - c->error = PA_ERROR_PROTOCOL; - return -1; - } - - return 0; - } - - c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL; - return -1; -} - -static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME)); - - if (command != PA_COMMAND_REPLY) { - handle_error(c, command, t); - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - if (c->state == CONTEXT_AUTHORIZING) { - struct pa_tagstruct *t; - c->state = CONTEXT_SETTING_NAME; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, c->name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - } else { - assert(c->state == CONTEXT_SETTING_NAME); - - c->state = CONTEXT_READY; - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 1, c->connect_complete_userdata); - } - - return; -} - -static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) { - struct pa_context *c = userdata; - struct pa_tagstruct *t; - uint32_t tag; - assert(client && c && c->state == CONTEXT_CONNECTING); - - pa_socket_client_free(client); - c->client = NULL; - - if (!io) { - c->error = PA_ERROR_CONNECTIONREFUSED; - context_dead(c); - - if (c->connect_complete_callback) - c->connect_complete_callback(c, 0, c->connect_complete_userdata); - - return; - } - - c->pstream = pa_pstream_new(c->mainloop, io); - assert(c->pstream); - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - assert(c->pdispatch); - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_AUTH); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie)); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c); - c->state = CONTEXT_AUTHORIZING; -} - -static struct sockaddr *resolve_server(const char *server, size_t *len) { - struct sockaddr *sa; - struct addrinfo hints, *result = NULL; - char *port; - assert(server && len); - - if ((port = strrchr(server, ':'))) - port++; - if (!port) - port = DEFAULT_PORT; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = 0; - - if (getaddrinfo(server, port, &hints, &result) != 0) - return NULL; - assert(result); - - sa = pa_xmalloc(*len = result->ai_addrlen); - memcpy(sa, result->ai_addr, *len); - - freeaddrinfo(result); - - return sa; -} - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) { - assert(c && c->state == CONTEXT_UNCONNECTED); - - if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) { - c->error = PA_ERROR_AUTHKEY; - return -1; - } - - if (!server) - if (!(server = getenv("POLYP_SERVER"))) - server = DEFAULT_SERVER; - - assert(!c->client); - - if (*server == '/') { - if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } else { - struct sockaddr* sa; - size_t sa_len; - - if (!(sa = resolve_server(server, &sa_len))) { - c->error = PA_ERROR_INVALIDSERVER; - return -1; - } - - c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len); - pa_xfree(sa); - - if (!c->client) { - c->error = PA_ERROR_CONNECTIONREFUSED; - return -1; - } - } - - c->connect_complete_callback = complete; - c->connect_complete_userdata = userdata; - - pa_socket_client_set_callback(c->client, on_connection, c); - c->state = CONTEXT_CONNECTING; - - return 0; -} - -int pa_context_is_dead(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_DEAD; -} - -int pa_context_is_ready(struct pa_context *c) { - assert(c); - return c->state == CONTEXT_READY; -} - -int pa_context_errno(struct pa_context *c) { - assert(c); - return c->error; -} - -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) { - assert(c); - c->die_callback = cb; - c->die_userdata = userdata; -} - -static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_stream *s; - uint32_t channel; - assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - return; - - c->error = PA_ERROR_KILLED; - stream_dead(s); -} - -static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s; - struct pa_context *c = userdata; - uint32_t bytes, channel; - assert(pd && command == PA_COMMAND_REQUEST && t && c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - return; - - if (s->state != STREAM_READY) - return; - - s->requested_bytes += bytes; - - if (s->requested_bytes && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); -} - -static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s && s->state == STREAM_CREATING); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - if (s->create_complete_callback) - s->create_complete_callback(s, 0, s->create_complete_userdata); - - return; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - s->state = STREAM_READY; - if (s->create_complete_callback) - s->create_complete_callback(s, 1, s->create_complete_userdata); -} - -static void create_stream(struct pa_stream *s, const char *dev) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s); - - s->state = STREAM_CREATING; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, s->buffer_attr.maxlength); - if (s->direction == PA_STREAM_PLAYBACK) { - pa_tagstruct_putu32(t, s->buffer_attr.tlength); - pa_tagstruct_putu32(t, s->buffer_attr.prebuf); - pa_tagstruct_putu32(t, s->buffer_attr.minreq); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); -} - -static struct pa_stream *internal_stream_new(struct pa_context *c) { - struct pa_stream *s; - - s = pa_xmalloc(sizeof(struct pa_stream)); - s->context = c; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->die_callback = NULL; - s->die_userdata = NULL; - s->create_complete_callback = NULL; - s->create_complete_userdata = NULL; - s->get_latency_callback = NULL; - s->get_latency_userdata = NULL; - s->finish_sample_callback = NULL; - s->finish_sample_userdata = NULL; - - s->name = NULL; - s->state = STREAM_CREATING; - s->requested_bytes = 0; - s->channel = 0; - s->channel_valid = 0; - s->device_index = (uint32_t) -1; - - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->next = c->first_stream; - if (s->next) - s->next->previous = s; - s->previous = NULL; - c->first_stream = s; - - return s; -} - -struct pa_stream* pa_stream_new( - struct pa_context *c, - enum pa_stream_direction dir, - const char *dev, - const char *name, - const struct pa_sample_spec *ss, - const struct pa_buffer_attr *attr, - void (*complete) (struct pa_stream*s, int success, void *userdata), - void *userdata) { - - struct pa_stream *s; - - assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD)); - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = complete; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = dir; - s->sample_spec = *ss; - if (attr) - s->buffer_attr = *attr; - else { - s->buffer_attr.maxlength = DEFAULT_MAXLENGTH; - s->buffer_attr.tlength = DEFAULT_TLENGTH; - s->buffer_attr.prebuf = DEFAULT_PREBUF; - s->buffer_attr.minreq = DEFAULT_MINREQ; - s->buffer_attr.fragsize = DEFAULT_FRAGSIZE; - } - - create_stream(s, dev); - - return s; -} - -void pa_stream_free(struct pa_stream *s) { - assert(s && s->context); - - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - pa_xfree(s->name); - - if (s->channel_valid && s->context->state == CONTEXT_READY) { - struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM)); - pa_tagstruct_putu32(t, s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - } - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - if (s->next) - s->next->previous = s->previous; - if (s->previous) - s->previous->next = s->next; - else - s->context->first_stream = s->next; - - pa_xfree(s); -} - -void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) { - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_write(struct pa_stream *s, const void *data, size_t length) { - struct pa_memchunk chunk; - assert(s && s->context && data && length && s->state == STREAM_READY); - - chunk.memblock = pa_memblock_new(length); - assert(chunk.memblock && chunk.memblock->data); - memcpy(chunk.memblock->data, data, length); - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk); - pa_memblock_unref(chunk.memblock); - - /*fprintf(stderr, "Sent %u bytes\n", length);*/ - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; -} - -size_t pa_stream_writable_size(struct pa_stream *s) { - assert(s && s->state == STREAM_READY); - return s->requested_bytes; -} - -void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) { - assert(s && cb); - s->read_callback = cb; - s->read_userdata = userdata; -} - -int pa_stream_is_dead(struct pa_stream *s) { - return s->state == STREAM_DEAD; -} - -int pa_stream_is_ready(struct pa_stream*s) { - return s->state == STREAM_READY; -} - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) { - assert(s); - s->die_callback = cb; - s->die_userdata = userdata; -} - -int pa_context_is_pending(struct pa_context *c) { - assert(c); - - if (c->state != CONTEXT_READY) - return 0; - - return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch); -} - -struct pa_context* pa_stream_get_context(struct pa_stream *p) { - assert(p); - return p->context; -} - -static void set_dispatch_callbacks(struct pa_context *c); - -static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(struct pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(struct pa_context *c) { - assert(c && c->state == CONTEXT_READY); - - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(c->pdispatch)) { - pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c); - return; - } - - if (pa_pstream_is_pending(c->pstream)) { - pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); - return; - } - - assert(c->drain_complete_callback); - c->drain_complete_callback(c, c->drain_complete_userdata); -} - -int pa_context_drain( - struct pa_context *c, - void (*complete) (struct pa_context*c, void *userdata), - void *userdata) { - - assert(c && c->state == CONTEXT_READY); - - if (complete == NULL) { - c->drain_complete_callback = NULL; - pa_pstream_set_drain_callback(c->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL); - return 0; - } - - if (!pa_context_is_pending(c)) - return -1; - - c->drain_complete_callback = complete; - c->drain_complete_userdata = userdata; - - set_dispatch_callbacks(c); - - return 0; -} - -static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - stream_dead(s); - return; - } - - if (s->state != STREAM_READY) - return; - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->drain_complete_callback) { - void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback; - s->drain_complete_callback = NULL; - temp(s, s->drain_complete_userdata); - } -} - - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(s && s->state == STREAM_READY); - - if (!complete) { - s->drain_complete_callback = NULL; - return; - } - - s->drain_complete_callback = complete; - s->drain_complete_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - - pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM); - pa_tagstruct_putu32(t, tag = s->context->ctag++); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s); -} - -void pa_context_exit(struct pa_context *c) { - struct pa_tagstruct *t; - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_EXIT); - pa_tagstruct_putu32(t, c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - uint32_t total, count; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &count) < 0 || - pa_tagstruct_getu32(t, &total) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->stat_callback) - c->stat_callback(c, count, total, c->stat_userdata); -} - -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - c->stat_callback = cb; - c->stat_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_STAT); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); -} - -static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - uint32_t latency; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); - return; - } - - if (pa_tagstruct_getu32(t, &latency) < 0 || - !pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->get_latency_callback) - s->get_latency_callback(s, latency, s->get_latency_userdata); -} - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { - uint32_t tag; - struct pa_tagstruct *t; - - p->get_latency_callback = cb; - p->get_latency_userdata = userdata; - - if (cb == NULL) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); -} - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_stream *s; - struct pa_tagstruct *t; - uint32_t tag; - - s = internal_stream_new(c); - assert(s); - - s->create_complete_callback = cb; - s->create_complete_userdata = userdata; - s->name = pa_xstrdup(name); - s->state = STREAM_CREATING; - s->direction = PA_STREAM_UPLOAD; - s->sample_spec = *ss; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_sample_spec(t, ss); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s); - - return s; -} - -static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_stream *s = userdata; - assert(pd && s); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(s->context, command, t) < 0) { - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 0, s->finish_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - s->context->error = PA_ERROR_PROTOCOL; - context_dead(s->context); - return; - } - - if (s->finish_sample_callback) - s->finish_sample_callback(s, 1, s->finish_sample_userdata); -} - -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(p); - - p->finish_sample_callback = cb; - p->finish_sample_userdata = userdata; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM); - pa_tagstruct_putu32(t, tag = p->context->ctag++); - pa_tagstruct_putu32(t, p->channel); - pa_pstream_send_tagstruct(p->context->pstream, t); - pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p); -} - -static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 0, c->play_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->play_sample_callback) - c->play_sample_callback(c, 1, c->play_sample_userdata); -} - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name && *name && (!dev || *dev)); - - c->play_sample_callback = cb; - c->play_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, (uint32_t) -1); - pa_tagstruct_puts(t, dev ? dev : ""); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c); -} - -static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 0, c->remove_sample_userdata); - return; - } - - if (!pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->remove_sample_callback) - c->remove_sample_callback(c, 1, c->remove_sample_userdata); -} - -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c && name); - - c->remove_sample_callback = cb; - c->remove_sample_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c); -} - -static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - struct pa_server_info i; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, NULL, c->get_server_info_userdata); - return; - } - - if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_server_info_callback) - c->get_server_info_callback(c, &i, c->get_server_info_userdata); -} - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_server_info_callback = cb; - c->get_server_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c); -} - -static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - 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_getu32(t, &i.latency) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata); - } - - if (c->get_sink_info_callback) - c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata); -} - -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_source_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata); - } - - if (c->get_source_info_callback) - c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata); -} - -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { - struct pa_tagstruct *t; - assert(c); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; - c->subscribe_mask = m; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); - pa_tagstruct_putu32(t, c->ctag++); - pa_tagstruct_putu32(t, cb ? m : 0); - pa_pstream_send_tagstruct(c->pstream, t); -} - -static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - enum pa_subscription_event_type e; - uint32_t index; - assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &index) < 0 || - !pa_tagstruct_eof(t)) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback) - c->subscribe_callback(c, e, index, c->subscribe_userdata); -} - -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_sink_info_callback = cb; - c->get_sink_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c); -} - -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_source_info_callback = cb; - c->get_source_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_tagstruct_puts(t, ""); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c); -} - -static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_client_info i; - - 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) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata); - } - - if (c->get_client_info_callback) - c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata); -} - - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_client_info_callback = cb; - c->get_client_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c); -} - -static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { - struct pa_context *c = userdata; - assert(pd && c); - - if (command != PA_COMMAND_REPLY) { - if (handle_error(c, command, t) < 0) { - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata); - return; - } - - while (!pa_tagstruct_eof(t)) { - struct pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_getu32(t, &i.auto_unload) < 0) { - c->error = PA_ERROR_PROTOCOL; - context_dead(c); - return; - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata); - } - - if (c->get_module_info_callback) - c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata); -} - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_tagstruct_putu32(t, index); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} - -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) { - struct pa_tagstruct *t; - uint32_t tag; - assert(c); - - c->get_module_info_callback = cb; - c->get_module_info_userdata = userdata; - - if (!cb) - return; - - t = pa_tagstruct_new(NULL, 0); - assert(t); - pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST); - pa_tagstruct_putu32(t, tag = c->ctag++); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c); -} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index a0dd9f9c..b9e5637c 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,157 +22,13 @@ USA. ***/ -#include - +#include "mainloop-api.h" #include "sample.h" #include "polyplib-def.h" -#include "mainloop-api.h" - -#ifdef __cplusplus -//extern "C" { -#endif - -struct pa_context; -struct pa_stream; - -struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name); -void pa_context_unref(struct pa_context *c); -struct pa_context* pa_context_ref(struct pa_context *c); - -int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata); -int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata); -void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata); - -int pa_context_is_dead(struct pa_context *c); -int pa_context_is_ready(struct pa_context *c); -int pa_context_errno(struct pa_context *c); - -int pa_context_is_pending(struct pa_context *c); - -struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_unref(struct pa_stream *s); -struct pa_stream *pa_stream_ref(struct pa_stream *s); - -void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata); - -void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); - -void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata); -void pa_stream_write(struct pa_stream *p, const void *data, size_t length); -size_t pa_stream_writable_size(struct pa_stream *p); - -void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); - -int pa_stream_is_dead(struct pa_stream *p); -int pa_stream_is_ready(struct pa_stream*p); - -void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); - -struct pa_context* pa_stream_get_context(struct pa_stream *p); - -uint32_t pa_stream_get_index(struct pa_stream *s); - -struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata); -void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata); - -void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -struct pa_sink_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t volume; - uint32_t monitor_source; - const char *monitor_source_name; - uint32_t latency; -}; - -void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata); - -struct pa_source_info { - const char *name; - uint32_t index; - const char *description; - struct pa_sample_spec sample_spec; - uint32_t owner_module; - uint32_t monitor_of_sink; - const char *monitor_of_sink_name; -}; - -void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata); - -struct pa_server_info { - const char *user_name; - const char *host_name; - const char *server_version; - const char *server_name; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata); - -struct pa_module_info { - uint32_t index; - const char*name, *argument; - uint32_t n_used, auto_unload; -}; - -void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata); - -struct pa_client_info { - uint32_t index; - const char *name; - uint32_t owner_module; - const char *protocol_name; -}; - -void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata); - -struct pa_sink_input_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t sink; - struct pa_sample_spec sample_spec; - uint32_t volume; - uint32_t latency; -}; - -void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata); - -struct pa_source_output_info { - uint32_t index; - const char *name; - uint32_t owner_module; - uint32_t owner_client; - uint32_t source; - struct pa_sample_spec sample_spec; -}; - -void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); -void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata); - -void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); -void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata); - -void pa_context_exit(struct pa_context *c); -void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata); - -void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); - -#ifdef __cplusplus -} -#endif +#include "polyplib-context.h" +#include "polyplib-stream.h" +#include "polyplib-introspect.h" +#include "polyplib-subscribe.h" +#include "polyplib-scache.h" #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 5b1cd626..8f5558a4 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -135,10 +135,3 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, } } -uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { - uint64_t p = a; - p *= b; - p /= PA_VOLUME_NORM; - - return (uint32_t) p; -} diff --git a/polyp/sample-util.h b/polyp/sample-util.h index 73101ab4..66f40a16 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -26,8 +26,6 @@ #include "memblock.h" #include "memchunk.h" -#define PA_VOLUME_NORM (0x100) -#define PA_VOLUME_MUTE (0) struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec); void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec); @@ -43,6 +41,4 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume); -uint32_t pa_volume_multiply(uint32_t a, uint32_t b); - #endif diff --git a/polyp/sample.c b/polyp/sample.c index e4c4bd52..4f93f2b7 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -96,3 +96,11 @@ void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) { assert(pa_sample_spec_valid(spec)); snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate); } + +uint32_t pa_volume_multiply(uint32_t a, uint32_t b) { + uint64_t p = a; + p *= b; + p /= PA_VOLUME_NORM; + + return (uint32_t) p; +} diff --git a/polyp/sample.h b/polyp/sample.h index 25027879..a7cde093 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -25,9 +25,9 @@ #include #include -#ifdef __cplusplus -extern "C" { -#endif +#include "cdecl.h" + +PA_C_DECL_BEGIN enum pa_sample_format { PA_SAMPLE_U8, @@ -49,10 +49,11 @@ enum pa_sample_format { #endif #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE +/** A sample format and attribute specification */ struct pa_sample_spec { - enum pa_sample_format format; - uint32_t rate; - uint8_t channels; + enum pa_sample_format format; /**< The sample format */ + uint32_t rate; /**< The sample rate. (e.g. 44100) */ + uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ }; size_t pa_bytes_per_second(const struct pa_sample_spec *spec); @@ -64,8 +65,10 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec); -#ifdef __cplusplus -} -#endif +#define PA_VOLUME_NORM (0x100) +#define PA_VOLUME_MUTE (0) +uint32_t pa_volume_multiply(uint32_t a, uint32_t b); + +PA_C_DECL_END #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index e8cb2f92..dffbfe7d 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -120,7 +120,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc if ((r = connect(c->fd, sa, len)) < 0) { if (errno != EINPROGRESS) { - fprintf(stderr, "connect(): %s\n", strerror(errno)); + /*fprintf(stderr, "connect(): %s\n", strerror(errno));*/ return -1; } diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 2a89210e..7b9e2a72 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -23,6 +23,8 @@ ***/ #include +#include + #include "mainloop-api.h" #include "iochannel.h" diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index aefd03c4..bcd7f456 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -48,6 +48,4 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le int pa_tagstruct_eof(struct pa_tagstruct*t); const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l); - - #endif diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 8ff3054d..7d8b4821 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -52,25 +52,36 @@ void *pa_xrealloc(void *ptr, size_t size) { return p; } -char *pa_xstrdup(const char *s) { - if (!s) +void* pa_xmemdup(const void *p, size_t l) { + if (!p) return NULL; else { - char *r = strdup(s); - if (!r) - oom(); - + char *r = pa_xmalloc(l); + memcpy(r, p, l); return r; } } +char *pa_xstrdup(const char *s) { + if (!s) + return NULL; + + return pa_xmemdup(s, strlen(s)+1); +} + char *pa_xstrndup(const char *s, size_t l) { if (!s) return NULL; else { - char *r = strndup(s, l); - if (!r) - oom(); + char *r; + size_t t = strlen(s); + + if (t > l) + t = l; + + r = pa_xmemdup(s, t+1); + r[t] = 0; return r; } } + diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index 45209b05..eaf8f708 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -12,4 +12,6 @@ void *pa_xrealloc(void *ptr, size_t size); char *pa_xstrdup(const char *s); char *pa_xstrndup(const char *s, size_t l); +void* pa_xmemdup(const void *p, size_t l); + #endif -- cgit