mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-04 13:29:59 -05:00
replace sink/source SET_STATE handlers with callbacks
There are no behaviour changes, the code from almost all the SET_STATE handlers is moved with minimal changes to the newly introduced set_state_in_io_thread() callback. The only exception is module-tunnel, which has to call pa_sink_render() after pa_sink.thread_info.state has been updated. The set_state_in_io_thread() callback is called before updating that variable, so moving the SET_STATE handler code to the callback isn't possible. The purpose of this change is to make it easier to get state change handling right in modules. Hooking to the SET_STATE messages in modules required care in calling pa_sink/source_process_msg() at the right time (or not calling it at all, as was the case on resume failures), and there were a few bugs (fixed before this patch). Now the core takes care of ordering things correctly. Another motivation for this change is that there was some talk about adding a suspend_cause variable to pa_sink/source.thread_info. The variable would be updated in the core SET_STATE handler, but that would not work with the old design, because in case of resume failures modules didn't call the core message handler.
This commit is contained in:
parent
73b8a57078
commit
b2537a8f38
25 changed files with 874 additions and 658 deletions
|
|
@ -891,48 +891,6 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
|
|||
|
||||
switch (code) {
|
||||
|
||||
case PA_SOURCE_MESSAGE_SET_STATE:
|
||||
|
||||
switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
|
||||
|
||||
case PA_SOURCE_SUSPENDED:
|
||||
/* Ignore if transition is PA_SOURCE_INIT->PA_SOURCE_SUSPENDED */
|
||||
if (!PA_SOURCE_IS_OPENED(u->source->thread_info.state))
|
||||
break;
|
||||
|
||||
/* Stop the device if the sink is suspended as well */
|
||||
if (!u->sink || u->sink->state == PA_SINK_SUSPENDED)
|
||||
transport_release(u);
|
||||
|
||||
if (u->read_smoother)
|
||||
pa_smoother_pause(u->read_smoother, pa_rtclock_now());
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_IDLE:
|
||||
case PA_SOURCE_RUNNING:
|
||||
if (u->source->thread_info.state != PA_SOURCE_SUSPENDED)
|
||||
break;
|
||||
|
||||
/* Resume the device if the sink was suspended as well */
|
||||
if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
|
||||
if (!setup_transport_and_stream(u))
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We don't resume the smoother here. Instead we
|
||||
* wait until the first packet arrives */
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_UNLINKED:
|
||||
case PA_SOURCE_INIT:
|
||||
case PA_SOURCE_INVALID_STATE:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_MESSAGE_GET_LATENCY: {
|
||||
int64_t wi, ri;
|
||||
|
||||
|
|
@ -956,6 +914,53 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
|
|||
return pa_source_process_msg(o, code, data, offset, chunk);
|
||||
}
|
||||
|
||||
/* Called from the IO thread. */
|
||||
static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) {
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
switch (new_state) {
|
||||
|
||||
case PA_SOURCE_SUSPENDED:
|
||||
/* Ignore if transition is PA_SOURCE_INIT->PA_SOURCE_SUSPENDED */
|
||||
if (!PA_SOURCE_IS_OPENED(u->source->thread_info.state))
|
||||
break;
|
||||
|
||||
/* Stop the device if the sink is suspended as well */
|
||||
if (!u->sink || u->sink->state == PA_SINK_SUSPENDED)
|
||||
transport_release(u);
|
||||
|
||||
if (u->read_smoother)
|
||||
pa_smoother_pause(u->read_smoother, pa_rtclock_now());
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_IDLE:
|
||||
case PA_SOURCE_RUNNING:
|
||||
if (u->source->thread_info.state != PA_SOURCE_SUSPENDED)
|
||||
break;
|
||||
|
||||
/* Resume the device if the sink was suspended as well */
|
||||
if (!u->sink || !PA_SINK_IS_OPENED(u->sink->thread_info.state))
|
||||
if (!setup_transport_and_stream(u))
|
||||
return -1;
|
||||
|
||||
/* We don't resume the smoother here. Instead we
|
||||
* wait until the first packet arrives */
|
||||
|
||||
break;
|
||||
|
||||
case PA_SOURCE_UNLINKED:
|
||||
case PA_SOURCE_INIT:
|
||||
case PA_SOURCE_INVALID_STATE:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
static void source_set_volume_cb(pa_source *s) {
|
||||
uint16_t gain;
|
||||
|
|
@ -1044,6 +1049,7 @@ static int add_source(struct userdata *u) {
|
|||
|
||||
u->source->userdata = u;
|
||||
u->source->parent.process_msg = source_process_msg;
|
||||
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
|
||||
|
||||
if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
pa_source_set_set_volume_callback(u->source, source_set_volume_cb);
|
||||
|
|
@ -1061,45 +1067,6 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
|
|||
|
||||
switch (code) {
|
||||
|
||||
case PA_SINK_MESSAGE_SET_STATE:
|
||||
|
||||
switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
|
||||
|
||||
case PA_SINK_SUSPENDED:
|
||||
/* Ignore if transition is PA_SINK_INIT->PA_SINK_SUSPENDED */
|
||||
if (!PA_SINK_IS_OPENED(u->sink->thread_info.state))
|
||||
break;
|
||||
|
||||
/* Stop the device if the source is suspended as well */
|
||||
if (!u->source || u->source->state == PA_SOURCE_SUSPENDED)
|
||||
/* We deliberately ignore whether stopping
|
||||
* actually worked. Since the stream_fd is
|
||||
* closed it doesn't really matter */
|
||||
transport_release(u);
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_IDLE:
|
||||
case PA_SINK_RUNNING:
|
||||
if (u->sink->thread_info.state != PA_SINK_SUSPENDED)
|
||||
break;
|
||||
|
||||
/* Resume the device if the source was suspended as well */
|
||||
if (!u->source || !PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
|
||||
if (!setup_transport_and_stream(u))
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_UNLINKED:
|
||||
case PA_SINK_INIT:
|
||||
case PA_SINK_INVALID_STATE:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_MESSAGE_GET_LATENCY: {
|
||||
int64_t wi, ri;
|
||||
|
||||
|
|
@ -1124,6 +1091,50 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
|
|||
return pa_sink_process_msg(o, code, data, offset, chunk);
|
||||
}
|
||||
|
||||
/* Called from the IO thread. */
|
||||
static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) {
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert_se(u = s->userdata);
|
||||
|
||||
switch (new_state) {
|
||||
|
||||
case PA_SINK_SUSPENDED:
|
||||
/* Ignore if transition is PA_SINK_INIT->PA_SINK_SUSPENDED */
|
||||
if (!PA_SINK_IS_OPENED(u->sink->thread_info.state))
|
||||
break;
|
||||
|
||||
/* Stop the device if the source is suspended as well */
|
||||
if (!u->source || u->source->state == PA_SOURCE_SUSPENDED)
|
||||
/* We deliberately ignore whether stopping
|
||||
* actually worked. Since the stream_fd is
|
||||
* closed it doesn't really matter */
|
||||
transport_release(u);
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_IDLE:
|
||||
case PA_SINK_RUNNING:
|
||||
if (u->sink->thread_info.state != PA_SINK_SUSPENDED)
|
||||
break;
|
||||
|
||||
/* Resume the device if the source was suspended as well */
|
||||
if (!u->source || !PA_SOURCE_IS_OPENED(u->source->thread_info.state))
|
||||
if (!setup_transport_and_stream(u))
|
||||
return -1;
|
||||
|
||||
break;
|
||||
|
||||
case PA_SINK_UNLINKED:
|
||||
case PA_SINK_INIT:
|
||||
case PA_SINK_INVALID_STATE:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
static void sink_set_volume_cb(pa_sink *s) {
|
||||
uint16_t gain;
|
||||
|
|
@ -1213,6 +1224,7 @@ static int add_sink(struct userdata *u) {
|
|||
|
||||
u->sink->userdata = u;
|
||||
u->sink->parent.process_msg = sink_process_msg;
|
||||
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
|
||||
|
||||
if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_AUDIO_GATEWAY) {
|
||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue