mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-12-30 11:08:50 -05:00
allow sending meta/policy events to clients
This commit is contained in:
parent
4bd9737725
commit
823431e447
17 changed files with 369 additions and 2 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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? */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue