diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c index 9941c1a75..8cea4e06b 100644 --- a/src/modules/module-protocol-pulse/pulse-server.c +++ b/src/modules/module-protocol-pulse/pulse-server.c @@ -2244,6 +2244,7 @@ struct pending_sample { struct client *client; struct sample_play *play; struct spa_hook listener; + uint32_t tag; unsigned int done:1; }; @@ -2254,29 +2255,57 @@ static void pending_sample_free(struct pending_sample *ps) sample_play_destroy(ps->play); } +static void sample_play_ready(void *data, uint32_t index) +{ + struct pending_sample *ps = data; + struct client *client = ps->client; + struct impl *impl = client->impl; + struct message *reply; + + pw_log_info(NAME" %p: [%s] PLAY_SAMPLE tag:%u sink_index:%u", + impl, client->name, ps->tag, index); + + reply = reply_new(client, ps->tag); + if (client->version >= 13) + message_put(reply, + TAG_U32, index, + TAG_INVALID); + + send_message(client, reply); +} + static void sample_play_done(void *data) { struct pending_sample *ps = data; struct client *client = ps->client; struct impl *impl = client->impl; + pw_log_info(NAME" %p: sample done tag:%u", client, ps->tag); ps->done = true; pw_loop_signal_event(impl->loop, client->cleanup); } +static void sample_play_error(void *data, int err) +{ + struct pending_sample *ps = data; + struct client *client = ps->client; + reply_error(client, COMMAND_PLAY_SAMPLE, ps->tag, err); +} + static const struct sample_play_events sample_play_events = { VERSION_SAMPLE_PLAY_EVENTS, + .ready = sample_play_ready, + .error = sample_play_error, .done = sample_play_done, }; static int do_play_sample(struct client *client, uint32_t command, uint32_t tag, struct message *m) { struct impl *impl = client->impl; - uint32_t sink_index, volume, idx; + uint32_t sink_index, volume; struct sample *sample; struct sample_play *play; const char *sink_name, *name; struct pw_properties *props = NULL; - struct message *reply; struct pending_sample *ps; int res; @@ -2316,18 +2345,11 @@ static int do_play_sample(struct client *client, uint32_t command, uint32_t tag, ps = play->user_data; ps->client = client; ps->play = play; + ps->tag = tag; sample_play_add_listener(play, &ps->listener, &sample_play_events, ps); spa_list_append(&client->samples, &ps->link); - idx = 0; - - reply = reply_new(client, tag); - if (client->version >= 13) - message_put(reply, - TAG_U32, idx, - TAG_INVALID); - - return send_message(client, reply); + return 0; error_errno: res = -errno; diff --git a/src/modules/module-protocol-pulse/sample.c b/src/modules/module-protocol-pulse/sample.c index c528a12e5..f620dcd15 100644 --- a/src/modules/module-protocol-pulse/sample.c +++ b/src/modules/module-protocol-pulse/sample.c @@ -38,27 +38,52 @@ struct sample_play_events { #define VERSION_SAMPLE_PLAY_EVENTS 0 uint32_t version; + void (*ready) (void *data, uint32_t id); + + void (*error) (void *data, int err); + void (*done) (void *data); }; +#define sample_play_emit_ready(p,i) spa_hook_list_call(&p->hooks, struct sample_play_events, ready, 0, i) +#define sample_play_emit_error(p,e) spa_hook_list_call(&p->hooks, struct sample_play_events, error, 0, e) #define sample_play_emit_done(p) spa_hook_list_call(&p->hooks, struct sample_play_events, done, 0) struct sample_play { struct spa_list link; struct sample *sample; struct pw_stream *stream; + uint32_t index; struct spa_hook listener; struct pw_context *context; struct pw_loop *main_loop; - uint32_t index; + uint32_t offset; uint32_t stride; struct spa_hook_list hooks; void *user_data; }; - static void sample_free(struct sample *sample); +static void sample_play_stream_state_changed(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) +{ + struct sample_play *p = data; + + switch (state) { + case PW_STREAM_STATE_UNCONNECTED: + case PW_STREAM_STATE_ERROR: + sample_play_emit_error(p, -EIO); + break; + case PW_STREAM_STATE_PAUSED: + p->index = pw_stream_get_node_id(p->stream); + sample_play_emit_ready(p, p->index); + break; + default: + break; + } +} + static void sample_play_stream_destroy(void *data) { struct sample_play *p = data; @@ -80,11 +105,11 @@ static void sample_play_stream_process(void *data) uint32_t size; uint8_t *d; - if (p->index >= s->length) { + if (p->offset >= s->length) { pw_stream_flush(p->stream, true); return; } - size = s->length - p->index; + size = s->length - p->offset; if ((b = pw_stream_dequeue_buffer(p->stream)) == NULL) { pw_log_warn("out of buffers: %m"); @@ -97,9 +122,9 @@ static void sample_play_stream_process(void *data) size = SPA_MIN(size, buf->datas[0].maxsize); - memcpy(d, p->sample->buffer + p->index, size); + memcpy(d, p->sample->buffer + p->offset, size); - p->index += size; + p->offset += size; buf->datas[0].chunk->offset = 0; buf->datas[0].chunk->stride = p->stride; @@ -116,6 +141,7 @@ static void sample_play_stream_drained(void *data) struct pw_stream_events sample_play_stream_events = { PW_VERSION_STREAM_EVENTS, + .state_changed = sample_play_stream_state_changed, .destroy = sample_play_stream_destroy, .process = sample_play_stream_process, .drained = sample_play_stream_drained,