From 823431e44732a0824658c82de29aaa92f8f39f79 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 12 Feb 2009 03:18:05 +0100 Subject: allow sending meta/policy events to clients --- src/pulsecore/client.c | 29 ++++++++++++++++++ src/pulsecore/client.h | 10 +++++++ src/pulsecore/core.h | 3 ++ src/pulsecore/native-common.h | 4 +++ src/pulsecore/protocol-native.c | 66 +++++++++++++++++++++++++++++++++++++++++ src/pulsecore/sink-input.c | 29 ++++++++++++++++++ src/pulsecore/sink-input.h | 12 ++++++++ src/pulsecore/source-output.c | 28 +++++++++++++++++ src/pulsecore/source-output.h | 12 ++++++++ 9 files changed, 193 insertions(+) (limited to 'src/pulsecore') diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c index 6f3e08e2..7ca7b97c 100644 --- a/src/pulsecore/client.c +++ b/src/pulsecore/client.c @@ -73,6 +73,7 @@ pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) { c->userdata = NULL; c->kill = NULL; + c->send_event = NULL; pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0); @@ -144,3 +145,31 @@ void pa_client_update_proplist(pa_client *c, pa_update_mode_t mode, pa_proplist pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED], c); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->index); } + +void pa_client_send_event(pa_client *c, const char *event, pa_proplist *data) { + pa_proplist *pl = NULL; + pa_client_send_event_hook_data hook_data; + + pa_assert(c); + pa_assert(event); + + if (!c->send_event) + return; + + if (!data) + data = pl = pa_proplist_new(); + + hook_data.client = c; + hook_data.data = data; + hook_data.event = event; + + if (pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CLIENT_SEND_EVENT], &hook_data) < 0) + goto finish; + + c->send_event(c, event, data); + +finish: + + if (pl) + pa_proplist_free(pl); +} diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h index 8ac80dd9..845a8bab 100644 --- a/src/pulsecore/client.h +++ b/src/pulsecore/client.h @@ -48,6 +48,8 @@ struct pa_client { void *userdata; void (*kill)(pa_client *c); + + void (*send_event)(pa_client *c, const char *name, pa_proplist *data); }; typedef struct pa_client_new_data { @@ -73,4 +75,12 @@ void pa_client_set_name(pa_client *c, const char *name); void pa_client_update_proplist(pa_client *c, pa_update_mode_t mode, pa_proplist *p); +void pa_client_send_event(pa_client *c, const char *event, pa_proplist *data); + +typedef struct pa_client_send_event_hook_data { + pa_client *client; + const char *event; + pa_proplist *data; +} pa_client_send_event_hook_data; + #endif diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 1407b1b8..aca96bba 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -73,6 +73,7 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED, PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED, PA_CORE_HOOK_SINK_INPUT_SET_VOLUME, + PA_CORE_HOOK_SINK_INPUT_SEND_EVENT, PA_CORE_HOOK_SOURCE_OUTPUT_NEW, PA_CORE_HOOK_SOURCE_OUTPUT_FIXATE, PA_CORE_HOOK_SOURCE_OUTPUT_PUT, @@ -82,10 +83,12 @@ typedef enum pa_core_hook { PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH, PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED, PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED, + PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT, PA_CORE_HOOK_CLIENT_NEW, PA_CORE_HOOK_CLIENT_PUT, PA_CORE_HOOK_CLIENT_UNLINK, PA_CORE_HOOK_CLIENT_PROPLIST_CHANGED, + PA_CORE_HOOK_CLIENT_SEND_EVENT, PA_CORE_HOOK_CARD_NEW, PA_CORE_HOOK_CARD_PUT, PA_CORE_HOOK_CARD_UNLINK, diff --git a/src/pulsecore/native-common.h b/src/pulsecore/native-common.h index b31a5da1..6951e10a 100644 --- a/src/pulsecore/native-common.h +++ b/src/pulsecore/native-common.h @@ -157,6 +157,10 @@ enum { PA_COMMAND_GET_CARD_INFO_LIST, PA_COMMAND_SET_CARD_PROFILE, + PA_COMMAND_CLIENT_EVENT, + PA_COMMAND_PLAYBACK_STREAM_EVENT, + PA_COMMAND_RECORD_STREAM_EVENT, + PA_COMMAND_MAX }; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 65b2bb97..c3032618 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -207,6 +207,7 @@ static void sink_input_moved_cb(pa_sink_input *i); static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes); static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes); static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes); +static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl); static void native_connection_send_memblock(pa_native_connection *c); static void playback_stream_request_bytes(struct playback_stream*s); @@ -216,6 +217,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend); static void source_output_moved_cb(pa_source_output *o); static pa_usec_t source_output_get_latency_cb(pa_source_output *o); +static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl); static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); @@ -636,6 +638,7 @@ static record_stream* record_stream_new( s->source_output->get_latency = source_output_get_latency_cb; s->source_output->moved = source_output_moved_cb; s->source_output->suspend = source_output_suspend_cb; + s->source_output->send_event = source_output_send_event_cb; s->source_output->userdata = s; fix_record_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, fragsize); @@ -1048,6 +1051,7 @@ static playback_stream* playback_stream_new( s->sink_input->kill = sink_input_kill_cb; s->sink_input->moved = sink_input_moved_cb; s->sink_input->suspend = sink_input_suspend_cb; + s->sink_input->send_event = sink_input_send_event_cb; s->sink_input->userdata = s; start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; @@ -1493,6 +1497,27 @@ static void sink_input_kill_cb(pa_sink_input *i) { playback_stream_unlink(s); } +/* Called from main context */ +static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) { + playback_stream *s; + pa_tagstruct *t; + + pa_sink_input_assert_ref(i); + s = PLAYBACK_STREAM(i->userdata); + playback_stream_assert_ref(s); + + if (s->connection->version < 15) + return; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, event); + pa_tagstruct_put_proplist(t, pl); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + /* Called from main context */ static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) { playback_stream *s; @@ -1594,6 +1619,27 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) { return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); } +/* Called from main context */ +static void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) { + record_stream *s; + pa_tagstruct *t; + + pa_source_output_assert_ref(o); + s = RECORD_STREAM(o->userdata); + record_stream_assert_ref(s); + + if (s->connection->version < 15) + return; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_putu32(t, s->index); + pa_tagstruct_puts(t, event); + pa_tagstruct_put_proplist(t, pl); + pa_pstream_send_tagstruct(s->connection->pstream, t); +} + /* Called from main context */ static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) { record_stream *s; @@ -4188,6 +4234,25 @@ static void client_kill_cb(pa_client *c) { pa_log_info("Connection killed."); } +static void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) { + pa_tagstruct *t; + pa_native_connection *c; + + pa_assert(client); + c = PA_NATIVE_CONNECTION(client->userdata); + pa_native_connection_assert_ref(c); + + if (c->version < 15) + return; + + t = pa_tagstruct_new(NULL, 0); + pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT); + pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ + pa_tagstruct_puts(t, event); + pa_tagstruct_put_proplist(t, pl); + pa_pstream_send_tagstruct(c->pstream, t); +} + /*** module entry points ***/ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) { @@ -4265,6 +4330,7 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati c->client = client; c->client->kill = client_kill_cb; + c->client->send_event = client_send_event_cb; c->client->userdata = c; c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 9c0bf76a..22419ee5 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -122,6 +122,7 @@ static void reset_callbacks(pa_sink_input *i) { i->get_latency = NULL; i->state_change = NULL; i->may_move_to = NULL; + i->send_event = NULL; } /* Called from main context */ @@ -1446,3 +1447,31 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) { return ret; } + +/* Called from main context */ +void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) { + pa_proplist *pl = NULL; + pa_sink_input_send_event_hook_data hook_data; + + pa_sink_input_assert_ref(i); + pa_assert(event); + + if (!i->send_event) + return; + + if (!data) + data = pl = pa_proplist_new(); + + hook_data.sink_input = i; + hook_data.data = data; + hook_data.event = event; + + if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0) + goto finish; + + i->send_event(i, event, data); + +finish: + if (pl) + pa_proplist_free(pl); +} diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 20e2cfa4..b4f05319 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -171,6 +171,10 @@ struct pa_sink_input { * be allowed */ pa_bool_t (*may_move_to) (pa_sink_input *i, pa_sink *s); /* may be NULL */ + /* If non-NULL this function is used to dispatch asynchronous + * control events. */ + void (*send_event)(pa_sink_input *i, const char *event, pa_proplist* data); + struct { pa_sink_input_state_t state; pa_atomic_t drained; @@ -217,6 +221,12 @@ enum { PA_SINK_INPUT_MESSAGE_MAX }; +typedef struct pa_sink_input_send_event_hook_data { + pa_sink_input *sink_input; + const char *event; + pa_proplist *data; +} pa_sink_input_send_event_hook_data; + typedef struct pa_sink_input_new_data { pa_proplist *proplist; @@ -298,6 +308,8 @@ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_p pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); +void pa_sink_input_send_event(pa_sink_input *i, const char *name, pa_proplist *data); + int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save); pa_bool_t pa_sink_input_may_move(pa_sink_input *i); /* may this sink input move at all? */ pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest); /* may this sink input move to this sink? */ diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c index f2f2593c..382fb88c 100644 --- a/src/pulsecore/source-output.c +++ b/src/pulsecore/source-output.c @@ -92,6 +92,7 @@ static void reset_callbacks(pa_source_output *o) { o->get_latency = NULL; o->state_change = NULL; o->may_move_to = NULL; + o->send_event = NULL; } /* Called from main context */ @@ -867,3 +868,30 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int return -PA_ERR_NOTIMPLEMENTED; } + +void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) { + pa_proplist *pl = NULL; + pa_source_output_send_event_hook_data hook_data; + + pa_source_output_assert_ref(o); + pa_assert(event); + + if (!o->send_event) + return; + + if (!data) + data = pl = pa_proplist_new(); + + hook_data.source_output = o; + hook_data.data = data; + hook_data.event = event; + + if (pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT], &hook_data) < 0) + goto finish; + + o->send_event(o, event, data); + +finish: + if (pl) + pa_proplist_free(pl); +} diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index aba2510b..9369568c 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -143,6 +143,10 @@ struct pa_source_output { * will not be allowed */ pa_bool_t (*may_move_to) (pa_source_output *o, pa_source *s); /* may be NULL */ + /* If non-NULL this function is used to dispatch asynchronous + * control events. */ + void (*send_event)(pa_source_output *o, const char *event, pa_proplist* data); + struct { pa_source_output_state_t state; @@ -177,6 +181,12 @@ enum { PA_SOURCE_OUTPUT_MESSAGE_MAX }; +typedef struct pa_source_output_send_event_hook_data { + pa_source_output *source_output; + const char *event; + pa_proplist *data; +} pa_source_output_send_event_hook_data; + typedef struct pa_source_output_new_data { pa_proplist *proplist; pa_sink_input *direct_on_input; @@ -233,6 +243,8 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); +void pa_source_output_send_event(pa_source_output *o, const char *name, pa_proplist *data); + pa_bool_t pa_source_output_may_move(pa_source_output *o); pa_bool_t pa_source_output_may_move_to(pa_source_output *o, pa_source *dest); int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t save); -- cgit