diff options
25 files changed, 172 insertions, 55 deletions
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index 9e335374c..3b962b90e 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1209,12 +1209,17 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t new_stat } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SINK_SUSPENDED: { diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 312b2596a..69da88dab 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1064,12 +1064,17 @@ static int source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t ne } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SOURCE_SUSPENDED: { diff --git a/src/modules/bluetooth/module-bluez4-device.c b/src/modules/bluetooth/module-bluez4-device.c index 85eb7986b..79d75c11b 100644 --- a/src/modules/bluetooth/module-bluez4-device.c +++ b/src/modules/bluetooth/module-bluez4-device.c @@ -413,7 +413,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); @@ -487,7 +487,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 5e189ba24..c3acc1dc6 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -915,7 +915,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); @@ -1092,7 +1092,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index 893c41eeb..c8065d823 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -514,7 +514,7 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, p } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index bbd416b6f..f7649a365 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -719,13 +719,18 @@ static int sink_set_state_in_main_thread_cb(pa_sink *sink, pa_sink_state_t state } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; bool running; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + running = new_state == PA_SINK_RUNNING; pa_atomic_store(&u->thread_info.running, running); diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c index 36029b389..43375999d 100644 --- a/src/modules/module-equalizer-sink.c +++ b/src/modules/module-equalizer-sink.c @@ -288,7 +288,7 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, p } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-esound-sink.c b/src/modules/module-esound-sink.c index 9fea2da74..3f6b8116b 100644 --- a/src/modules/module-esound-sink.c +++ b/src/modules/module-esound-sink.c @@ -169,12 +169,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SINK_SUSPENDED: diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c index de866d96a..d677381d8 100644 --- a/src/modules/module-ladspa-sink.c +++ b/src/modules/module-ladspa-sink.c @@ -395,7 +395,7 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, p } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-null-sink.c b/src/modules/module-null-sink.c index 16b0b6870..baaf06477 100644 --- a/src/modules/module-null-sink.c +++ b/src/modules/module-null-sink.c @@ -103,7 +103,7 @@ static int sink_process_msg( } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-null-source.c b/src/modules/module-null-source.c index ae67206a3..0e4c8d2f2 100644 --- a/src/modules/module-null-source.c +++ b/src/modules/module-null-source.c @@ -103,7 +103,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-pipe-sink.c b/src/modules/module-pipe-sink.c index b2378059b..fc01206b6 100644 --- a/src/modules/module-pipe-sink.c +++ b/src/modules/module-pipe-sink.c @@ -136,7 +136,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c index 56e7a85fd..f53b6b150 100644 --- a/src/modules/module-remap-sink.c +++ b/src/modules/module-remap-sink.c @@ -115,7 +115,7 @@ static int sink_set_state_in_main_thread(pa_sink *s, pa_sink_state_t state, pa_s } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-sine-source.c b/src/modules/module-sine-source.c index 39fb71ab3..803fae5e9 100644 --- a/src/modules/module-sine-source.c +++ b/src/modules/module-sine-source.c @@ -103,7 +103,7 @@ static int source_process_msg( } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-solaris.c b/src/modules/module-solaris.c index e68f2a93d..ef42b3d9a 100644 --- a/src/modules/module-solaris.c +++ b/src/modules/module-solaris.c @@ -396,12 +396,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SINK_SUSPENDED: @@ -457,12 +462,17 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SOURCE_SUSPENDED: diff --git a/src/modules/module-tunnel-sink-new.c b/src/modules/module-tunnel-sink-new.c index 313903372..802e6a59a 100644 --- a/src/modules/module-tunnel-sink-new.c +++ b/src/modules/module-tunnel-sink-new.c @@ -434,12 +434,17 @@ static int sink_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t of } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + if (!u->stream || pa_stream_get_state(u->stream) != PA_STREAM_READY) return 0; diff --git a/src/modules/module-tunnel-source-new.c b/src/modules/module-tunnel-source-new.c index d0a5414ad..b41f53e2f 100644 --- a/src/modules/module-tunnel-source-new.c +++ b/src/modules/module-tunnel-source-new.c @@ -433,12 +433,17 @@ static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + if (!u->stream || pa_stream_get_state(u->stream) != PA_STREAM_READY) return 0; diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c index 68ad20076..e13455235 100644 --- a/src/modules/module-virtual-sink.c +++ b/src/modules/module-virtual-sink.c @@ -127,7 +127,7 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, p } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c index 7c5e246cf..2c3d54ba5 100644 --- a/src/modules/module-virtual-surround-sink.c +++ b/src/modules/module-virtual-surround-sink.c @@ -155,7 +155,7 @@ static int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, p } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index d2551bcfc..42a6e3b03 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -666,7 +666,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; bool do_trigger = false; bool quick = true; @@ -674,6 +674,11 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SINK_SUSPENDED: @@ -749,7 +754,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off } /* Called from the IO thread. */ -static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state) { +static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; bool do_trigger = false; bool quick = true; @@ -757,6 +762,11 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_ pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SOURCE_SUSPENDED: diff --git a/src/modules/raop/raop-sink.c b/src/modules/raop/raop-sink.c index baa346641..818cdfe01 100644 --- a/src/modules/raop/raop-sink.c +++ b/src/modules/raop/raop-sink.c @@ -221,12 +221,17 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse } /* Called from the IO thread. */ -static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state) { +static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state, pa_suspend_cause_t new_suspend_cause) { struct userdata *u; pa_assert(s); pa_assert_se(u = s->userdata); + /* It may be that only the suspend cause is changing, in which case there's + * nothing to do. */ + if (new_state == s->thread_info.state) + return 0; + switch (new_state) { case PA_SINK_SUSPENDED: pa_log_debug("RAOP: SUSPENDED"); diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 2c9334931..2174354f2 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -69,6 +69,11 @@ struct sink_message_set_port { int ret; }; +struct set_state_data { + pa_sink_state_t state; + pa_suspend_cause_t suspend_cause; +}; + static void sink_free(pa_object *s); static void pa_sink_volume_change_push(pa_sink *s); @@ -429,19 +434,49 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t * current approach of not setting any suspend cause works well enough. */ if (s->set_state_in_main_thread) { - ret = s->set_state_in_main_thread(s, state, suspend_cause); - /* set_state_in_main_thread() is allowed to fail only when resuming. */ - pa_assert(ret >= 0 || resuming); + if ((ret = s->set_state_in_main_thread(s, state, suspend_cause)) < 0) { + /* set_state_in_main_thread() is allowed to fail only when resuming. */ + pa_assert(resuming); + + /* If resuming fails, we set the state to SUSPENDED and + * suspend_cause to 0. */ + state = PA_SINK_SUSPENDED; + suspend_cause = 0; + state_changed = false; + suspend_cause_changed = suspend_cause != s->suspend_cause; + resuming = false; + + /* We know the state isn't changing. If the suspend cause isn't + * changing either, then there's nothing more to do. */ + if (!suspend_cause_changed) + return ret; + } } - if (ret >= 0 && s->asyncmsgq && state_changed) - if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) { + if (s->asyncmsgq) { + struct set_state_data data = { .state = state, .suspend_cause = suspend_cause }; + + if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, &data, 0, NULL)) < 0) { /* SET_STATE is allowed to fail only when resuming. */ pa_assert(resuming); if (s->set_state_in_main_thread) s->set_state_in_main_thread(s, PA_SINK_SUSPENDED, 0); + + /* If resuming fails, we set the state to SUSPENDED and + * suspend_cause to 0. */ + state = PA_SINK_SUSPENDED; + suspend_cause = 0; + state_changed = false; + suspend_cause_changed = suspend_cause != s->suspend_cause; + resuming = false; + + /* We know the state isn't changing. If the suspend cause isn't + * changing either, then there's nothing more to do. */ + if (!suspend_cause_changed) + return ret; } + } if (suspend_cause_changed) { char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; @@ -452,9 +487,6 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t s->suspend_cause = suspend_cause; } - if (ret < 0) - goto finish; - if (state_changed) { pa_log_debug("%s: state: %s -> %s", s->name, pa_sink_state_to_string(s->state), pa_sink_state_to_string(state)); s->state = state; @@ -481,7 +513,6 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t i->suspend(i, state == PA_SINK_SUSPENDED); } -finish: if ((suspending || resuming || suspend_cause_changed) && s->monitor_source && state != PA_SINK_UNLINKED) pa_source_sync_suspend(s->monitor_source); @@ -2846,19 +2877,19 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse return 0; case PA_SINK_MESSAGE_SET_STATE: { - + struct set_state_data *data = userdata; bool suspend_change = - (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) || - (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED); + (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(data->state)) || + (PA_SINK_IS_OPENED(s->thread_info.state) && data->state == PA_SINK_SUSPENDED); if (s->set_state_in_io_thread) { int r; - if ((r = s->set_state_in_io_thread(s, PA_PTR_TO_UINT(userdata))) < 0) + if ((r = s->set_state_in_io_thread(s, data->state, data->suspend_cause)) < 0) return r; } - s->thread_info.state = PA_PTR_TO_UINT(userdata); + s->thread_info.state = data->state; if (s->thread_info.state == PA_SINK_SUSPENDED) { s->thread_info.rewind_nbytes = 0; diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index e1ea52495..3e9191d27 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -148,7 +148,7 @@ struct pa_sink { * are updated only after all the callback calls. In case of failure, the * state is set to SUSPENDED and the suspend cause is set to 0. */ int (*set_state_in_main_thread)(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */ - int (*set_state_in_io_thread)(pa_sink *s, pa_sink_state_t state); /* may be NULL */ + int (*set_state_in_io_thread)(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */ /* Sink drivers that support hardware volume may set this * callback. This is called when the current volume needs to be diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index dd56eb082..e04463c65 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -61,6 +61,11 @@ struct source_message_set_port { int ret; }; +struct set_state_data { + pa_source_state_t state; + pa_suspend_cause_t suspend_cause; +}; + static void source_free(pa_object *o); static void pa_source_volume_change_push(pa_source *s); @@ -383,19 +388,49 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca * current approach of not setting any suspend cause works well enough. */ if (s->set_state_in_main_thread) { - ret = s->set_state_in_main_thread(s, state, suspend_cause); - /* set_state_in_main_thread() is allowed to fail only when resuming. */ - pa_assert(ret >= 0 || resuming); + if ((ret = s->set_state_in_main_thread(s, state, suspend_cause)) < 0) { + /* set_state_in_main_thread() is allowed to fail only when resuming. */ + pa_assert(resuming); + + /* If resuming fails, we set the state to SUSPENDED and + * suspend_cause to 0. */ + state = PA_SOURCE_SUSPENDED; + suspend_cause = 0; + state_changed = false; + suspend_cause_changed = suspend_cause != s->suspend_cause; + resuming = false; + + /* We know the state isn't changing. If the suspend cause isn't + * changing either, then there's nothing more to do. */ + if (!suspend_cause_changed) + return ret; + } } - if (ret >= 0 && s->asyncmsgq && state_changed) - if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) { + if (s->asyncmsgq) { + struct set_state_data data = { .state = state, .suspend_cause = suspend_cause }; + + if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_STATE, &data, 0, NULL)) < 0) { /* SET_STATE is allowed to fail only when resuming. */ pa_assert(resuming); if (s->set_state_in_main_thread) s->set_state_in_main_thread(s, PA_SOURCE_SUSPENDED, 0); + + /* If resuming fails, we set the state to SUSPENDED and + * suspend_cause to 0. */ + state = PA_SOURCE_SUSPENDED; + suspend_cause = 0; + state_changed = false; + suspend_cause_changed = suspend_cause != s->suspend_cause; + resuming = false; + + /* We know the state isn't changing. If the suspend cause isn't + * changing either, then there's nothing more to do. */ + if (!suspend_cause_changed) + return ret; } + } if (suspend_cause_changed) { char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; @@ -406,9 +441,6 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca s->suspend_cause = suspend_cause; } - if (ret < 0) - goto finish; - if (state_changed) { pa_log_debug("%s: state: %s -> %s", s->name, pa_source_state_to_string(s->state), pa_source_state_to_string(state)); s->state = state; @@ -435,7 +467,6 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca o->suspend(o, state == PA_SOURCE_SUSPENDED); } -finish: return ret; } @@ -2220,19 +2251,19 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_ return 0; case PA_SOURCE_MESSAGE_SET_STATE: { - + struct set_state_data *data = userdata; bool suspend_change = - (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(PA_PTR_TO_UINT(userdata))) || - (PA_SOURCE_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SOURCE_SUSPENDED); + (s->thread_info.state == PA_SOURCE_SUSPENDED && PA_SOURCE_IS_OPENED(data->state)) || + (PA_SOURCE_IS_OPENED(s->thread_info.state) && data->state == PA_SOURCE_SUSPENDED); if (s->set_state_in_io_thread) { int r; - if ((r = s->set_state_in_io_thread(s, PA_PTR_TO_UINT(userdata))) < 0) + if ((r = s->set_state_in_io_thread(s, data->state, data->suspend_cause)) < 0) return r; } - s->thread_info.state = PA_PTR_TO_UINT(userdata); + s->thread_info.state = data->state; if (suspend_change) { pa_source_output *o; diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index c4fda7965..96327165d 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -149,7 +149,7 @@ struct pa_source { * are updated only after all the callback calls. In case of failure, the * state is set to SUSPENDED and the suspend cause is set to 0. */ int (*set_state_in_main_thread)(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */ - int (*set_state_in_io_thread)(pa_source *s, pa_source_state_t state); /* may be NULL */ + int (*set_state_in_io_thread)(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause); /* may be NULL */ /* Called when the volume is queried. Called from main loop * context. If this is NULL a PA_SOURCE_MESSAGE_GET_VOLUME message |