From cbfaf40b45f712c1cdcc6b7cb694f907ce0e7f8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 11 Aug 2004 15:11:26 +0000 Subject: info and subscription work git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@114 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/native-common.h | 28 ++++++++++++++++ polyp/polypaudio.pa | 8 ++--- polyp/polyplib-def.h | 4 ++- polyp/polyplib.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ polyp/polyplib.h | 8 +++-- polyp/protocol-native.c | 52 ++++++++++++++++++++++++++++++ polyp/scache.c | 7 ++++ polyp/scache.h | 1 + polyp/subscribe.c | 51 ++++++++++++++++++++++++++--- polyp/subscribe.h | 29 +---------------- 10 files changed, 232 insertions(+), 41 deletions(-) diff --git a/polyp/native-common.h b/polyp/native-common.h index 4a74ac44..5e69c805 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -87,4 +87,32 @@ enum { #define PA_NATIVE_COOKIE_LENGTH 256 #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, +}; + +enum pa_subscription_event_type { + PA_SUBSCRIPTION_EVENT_SINK = 0, + PA_SUBSCRIPTION_EVENT_SOURCE = 1, + PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, + PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, + PA_SUBSCRIPTION_EVENT_MODULE = 4, + PA_SUBSCRIPTION_EVENT_CLIENT = 5, + PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, + PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, + + PA_SUBSCRIPTION_EVENT_NEW = 0, + PA_SUBSCRIPTION_EVENT_CHANGE = 16, + PA_SUBSCRIPTION_EVENT_REMOVE = 32, + PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, +}; + +#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) + #endif diff --git a/polyp/polypaudio.pa b/polyp/polypaudio.pa index 8da20c62..d57f8127 100755 --- a/polyp/polypaudio.pa +++ b/polyp/polypaudio.pa @@ -23,8 +23,8 @@ #load module-alsa-sink #load module-alsa-source device=plughw:1,0 #load module-oss device="/dev/dsp" sink_name=output source_name=input -load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -load module-pipe-sink +#load module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +#load module-pipe-sink # Load audio drivers automatically on access @@ -32,8 +32,8 @@ load module-pipe-sink #autoload_source_add input module-oss device="/dev/dsp" sink_name=output source_name=input #autoload_sink_add output module-oss-mmap device="/dev/dsp" sink_name=output source_name=input #autoload_source_add input module-oss-mmap device="/dev/dsp" sink_name=output source_name=input -#autoload_sink_add output module-alsa-sink sink_name=output -#autoload_source_add input module-alsa-source source_name=input +autoload_sink_add output module-alsa-sink sink_name=output +autoload_source_add input module-alsa-source source_name=input # Load several protocols load module-esound-protocol-tcp diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index e5c786f2..d96c6899 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -28,6 +28,8 @@ extern "C" { #endif +#include "native-common.h" + enum pa_stream_direction { PA_STREAM_PLAYBACK, PA_STREAM_RECORD, @@ -41,7 +43,7 @@ struct pa_buffer_attr { uint32_t minreq; uint32_t fragsize; }; - + #ifdef __cplusplus } #endif diff --git a/polyp/polyplib.c b/polyp/polyplib.c index e14f8cf9..b77d24ea 100644 --- a/polyp/polyplib.c +++ b/polyp/polyplib.c @@ -98,6 +98,10 @@ struct pa_context { 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; + uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH]; }; @@ -140,6 +144,7 @@ struct pa_stream { 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 }, @@ -152,6 +157,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [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) { @@ -200,6 +206,9 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char * c->get_source_info_callback = NULL; c->get_source_info_userdata = NULL; + c->subscribe_callback = NULL; + c->subscribe_userdata = NULL; + pa_check_for_sigpipe(); return c; } @@ -1301,3 +1310,79 @@ void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_ 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); +} diff --git a/polyp/polyplib.h b/polyp/polyplib.h index cc1251e2..8708cd72 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -114,7 +114,7 @@ struct pa_sink_info { }; 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_id(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_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 { @@ -128,7 +128,7 @@ struct pa_source_info { }; 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_id(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_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 { @@ -140,7 +140,9 @@ struct pa_server_info { }; 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); - + +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 diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index abe6c8b7..caaa1396 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -43,6 +43,7 @@ #include "scache.h" #include "xmalloc.h" #include "util.h" +#include "subscribe.h" struct connection; struct pa_protocol_native; @@ -93,6 +94,7 @@ struct connection { struct pa_pdispatch *pdispatch; struct pa_idxset *record_streams, *output_streams; uint32_t rrobin_index; + struct pa_subscription *subscription; }; struct pa_protocol_native { @@ -131,6 +133,7 @@ static void command_remove_sample(struct pa_pdispatch *pd, uint32_t command, uin static void command_get_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_subscribe(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 }, @@ -159,6 +162,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_GET_SINK_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SOURCE_INFO_LIST] = { command_get_info_list }, [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info }, + [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, }; /* structure management */ @@ -301,6 +305,10 @@ static void connection_free(struct connection *c) { pa_pdispatch_free(c->pdispatch); pa_pstream_free(c->pstream); pa_client_free(c->client); + + if (c->subscription) + pa_subscription_free(c->subscription); + pa_xfree(c); } @@ -1076,6 +1084,49 @@ static void command_get_server_info(struct pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); } +static void subscription_cb(struct pa_core *core, enum pa_subscription_event_type e, uint32_t index, void *userdata) { + struct pa_tagstruct *t; + struct connection *c = userdata; + assert(c && core); + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); + pa_tagstruct_putu32(t, e); + pa_tagstruct_putu32(t, index); + pa_pstream_send_tagstruct(c->pstream, t); +} + +static void command_subscribe(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + enum pa_subscription_mask m; + assert(c && t); + + if (pa_tagstruct_getu32(t, &m) < 0 || + !pa_tagstruct_eof(t)) { + protocol_error(c); + return; + } + + if (!c->authorized) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); + return; + } + + if (c->subscription) + pa_subscription_free(c->subscription); + + if (m != 0) { + c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); + assert(c->subscription); + } else + c->subscription = NULL; + + pa_pstream_send_simple_ack(c->pstream, tag); + +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { @@ -1197,6 +1248,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo assert(c->record_streams && c->output_streams); c->rrobin_index = PA_IDXSET_INVALID; + c->subscription = NULL; pa_idxset_put(p->connections, c, NULL); } diff --git a/polyp/scache.c b/polyp/scache.c index fd7b74e5..9485a2b6 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -9,9 +9,11 @@ #include "sample-util.h" #include "play-memchunk.h" #include "xmalloc.h" +#include "subscribe.h" static void free_entry(struct pa_scache_entry *e) { assert(e); + pa_subscription_post(e->core, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_REMOVE, e->index); pa_xfree(e->name); if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); @@ -27,10 +29,12 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp put = 0; if (e->memchunk.memblock) pa_memblock_unref(e->memchunk.memblock); + assert(e->core == c); } else { put = 1; e = pa_xmalloc(sizeof(struct pa_scache_entry)); e->name = pa_xstrdup(name); + e->core = c; } e->volume = 0x100; @@ -61,6 +65,8 @@ void pa_scache_add_item(struct pa_core *c, const char *name, struct pa_sample_sp pa_idxset_put(c->scache_idxset, e, &e->index); pa_hashmap_put(c->scache_hashmap, e->name, e); + + pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } if (index) @@ -77,6 +83,7 @@ int pa_scache_remove_item(struct pa_core *c, const char *name) { pa_hashmap_remove(c->scache_hashmap, name); if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e) assert(0); + free_entry(e); return 0; } diff --git a/polyp/scache.h b/polyp/scache.h index a1454cea..15cd5d48 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -6,6 +6,7 @@ #include "sink.h" struct pa_scache_entry { + struct pa_core *core; uint32_t index; char *name; uint32_t volume; diff --git a/polyp/subscribe.c b/polyp/subscribe.c index 541657ae..104566d1 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -37,7 +37,7 @@ struct pa_subscription* pa_subscription_new(struct pa_core *c, enum pa_subscript s->next->prev = s; s->prev = NULL; c->subscriptions = s; - return NULL; + return s; } void pa_subscription_free(struct pa_subscription*s) { @@ -81,6 +81,49 @@ void pa_subscription_free_all(struct pa_core *c) { } } +/*static void dump_event(struct pa_subscription_event*e) { + switch (e->type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { + case PA_SUBSCRIPTION_EVENT_SINK: + fprintf(stderr, "SINK_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE: + fprintf(stderr, "SOURCE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SINK_INPUT: + fprintf(stderr, "SINK_INPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: + fprintf(stderr, "SOURCE_OUTPUT_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_MODULE: + fprintf(stderr, "MODULE_EVENT"); + break; + case PA_SUBSCRIPTION_EVENT_CLIENT: + fprintf(stderr, "CLIENT_EVENT"); + break; + default: + fprintf(stderr, "OTHER"); + break; + } + + switch (e->type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { + case PA_SUBSCRIPTION_EVENT_NEW: + fprintf(stderr, " NEW"); + break; + case PA_SUBSCRIPTION_EVENT_CHANGE: + fprintf(stderr, " CHANGE"); + break; + case PA_SUBSCRIPTION_EVENT_REMOVE: + fprintf(stderr, " REMOVE"); + break; + default: + fprintf(stderr, " OTHER"); + break; + } + + fprintf(stderr, " %u\n", e->index); +}*/ + static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void *userdata) { struct pa_core *c = userdata; struct pa_subscription *s; @@ -98,6 +141,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * struct pa_subscription *s; for (s = c->subscriptions; s; s = s->next) { + if (!s->dead && pa_subscription_match_flags(s->mask, e->type)) s->callback(c, e->type, e->index, s->userdata); } @@ -119,7 +163,7 @@ static void defer_cb(struct pa_mainloop_api *m, struct pa_defer_event *e, void * static void sched_event(struct pa_core *c) { assert(c); - + if (!c->subscription_defer_event) { c->subscription_defer_event = c->mainloop->defer_new(c->mainloop, defer_cb, c); assert(c->subscription_defer_event); @@ -147,6 +191,3 @@ void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, } -int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type t) { - return !!(m & (1 >> (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))); -} diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 1561249f..a88677d2 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -2,33 +2,8 @@ #define foosubscribehfoo #include "core.h" +#include "native-common.h" -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, -}; - -enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, - PA_SUBSCRIPTION_EVENT_SOURCE = 1, - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, - PA_SUBSCRIPTION_EVENT_MODULE = 4, - PA_SUBSCRIPTION_EVENT_CLIENT = 5, - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 7, - - PA_SUBSCRIPTION_EVENT_NEW = 0, - PA_SUBSCRIPTION_EVENT_CHANGE = 16, - PA_SUBSCRIPTION_EVENT_REMOVE = 32, - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32, -}; - struct pa_subscription; struct pa_subscription_event; @@ -38,6 +13,4 @@ void pa_subscription_free_all(struct pa_core *c); void pa_subscription_post(struct pa_core *c, enum pa_subscription_event_type t, uint32_t index); -int pa_subscription_match_flags(enum pa_subscription_mask m, enum pa_subscription_event_type e); - #endif -- cgit