diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index d6b8a3fb6..0f4ebe2a4 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -761,13 +761,20 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { } /* Called from main thread */ -static void source_output_suspend_cb(pa_source_output *o, bool suspended) { +static void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause) { struct userdata *u; + bool suspended; pa_source_output_assert_ref(o); pa_assert_ctl_context(); pa_assert_se(u = o->userdata); + /* State has not changed, nothing to do */ + if (old_state == o->source->state) + return; + + suspended = (o->source->state == PA_SOURCE_SUSPENDED); + /* If the source has been suspended, we need to handle this like * a source change when the source is resumed */ if (suspended) { @@ -1160,13 +1167,20 @@ static bool sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { } /* Called from main thread */ -static void sink_input_suspend_cb(pa_sink_input *i, bool suspended) { +static void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause) { struct userdata *u; + bool suspended; pa_sink_input_assert_ref(i); pa_assert_ctl_context(); pa_assert_se(u = i->userdata); + /* State has not changed, nothing to do */ + if (old_state == i->sink->state) + return; + + suspended = (i->sink->state == PA_SINK_SUSPENDED); + /* If the sink has been suspended, we need to handle this like * a sink change when the sink is resumed. Because the sink * is suspended, we can set the variables directly. */ diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 7c1631e52..72457418a 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -241,7 +241,7 @@ enum { static bool sink_input_process_underrun_cb(pa_sink_input *i); static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); static void sink_input_kill_cb(pa_sink_input *i); -static void sink_input_suspend_cb(pa_sink_input *i, bool suspend); +static void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause); static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest); 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); @@ -253,7 +253,7 @@ static void playback_stream_request_bytes(struct playback_stream*s); static void source_output_kill_cb(pa_source_output *o); static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); -static void source_output_suspend_cb(pa_source_output *o, bool suspend); +static void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause); static void source_output_moving_cb(pa_source_output *o, pa_source *dest); 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); @@ -1618,11 +1618,19 @@ static void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_pro } /* Called from main context */ -static void sink_input_suspend_cb(pa_sink_input *i, bool suspend) { +static void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause) { playback_stream *s; pa_tagstruct *t; + bool suspend; pa_sink_input_assert_ref(i); + + /* State has not changed, nothing to do */ + if (old_state == i->sink->state) + return; + + suspend = (i->sink->state == PA_SINK_SUSPENDED); + s = PLAYBACK_STREAM(i->userdata); playback_stream_assert_ref(s); @@ -1756,11 +1764,19 @@ static void source_output_send_event_cb(pa_source_output *o, const char *event, } /* Called from main context */ -static void source_output_suspend_cb(pa_source_output *o, bool suspend) { +static void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause) { record_stream *s; pa_tagstruct *t; + bool suspend; pa_source_output_assert_ref(o); + + /* State has not changed, nothing to do */ + if (old_state == o->source->state) + return; + + suspend = (o->source->state == PA_SOURCE_SUSPENDED); + s = RECORD_STREAM(o->userdata); record_stream_assert_ref(s); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 6bf406ccc..f7f923744 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -179,8 +179,9 @@ struct pa_sink_input { void (*detach) (pa_sink_input *i); /* may be NULL */ /* If non-NULL called whenever the sink this input is attached - * to suspends or resumes. Called from main context */ - void (*suspend) (pa_sink_input *i, bool b); /* may be NULL */ + * to suspends or resumes or if the suspend cause changes. + * Called from main context */ + void (*suspend) (pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause); /* may be NULL */ /* If non-NULL called whenever the sink this input is attached * to suspends or resumes. Called from IO context */ diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d9851ce59..e8549f988 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -400,6 +400,8 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t bool suspend_cause_changed; bool suspending; bool resuming; + pa_sink_state_t old_state; + pa_suspend_cause_t old_suspend_cause; pa_assert(s); pa_assert_ctl_context(); @@ -469,6 +471,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t } } + old_suspend_cause = s->suspend_cause; if (suspend_cause_changed) { char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; char new_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; @@ -478,6 +481,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t s->suspend_cause = suspend_cause; } + old_state = s->state; 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; @@ -490,7 +494,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t } } - if (suspending || resuming) { + if (suspending || resuming || suspend_cause_changed) { pa_sink_input *i; uint32_t idx; @@ -501,7 +505,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t (i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND)) pa_sink_input_kill(i); else if (i->suspend) - i->suspend(i, state == PA_SINK_SUSPENDED); + i->suspend(i, old_state, old_suspend_cause); } if ((suspending || resuming || suspend_cause_changed) && s->monitor_source && state != PA_SINK_UNLINKED) diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 9cbc28628..16853c064 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -150,8 +150,9 @@ struct pa_source_output { void (*detach) (pa_source_output *o); /* may be NULL */ /* If non-NULL called whenever the source this output is attached - * to suspends or resumes. Called from main context */ - void (*suspend) (pa_source_output *o, bool b); /* may be NULL */ + * to suspends or resumes or if the suspend cause changes. + * Called from main context */ + void (*suspend) (pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause); /* may be NULL */ /* If non-NULL called whenever the source this output is attached * to suspends or resumes. Called from IO context */ diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index 3324415ed..854b07e74 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -354,6 +354,8 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca bool suspend_cause_changed; bool suspending; bool resuming; + pa_source_state_t old_state; + pa_suspend_cause_t old_suspend_cause; pa_assert(s); pa_assert_ctl_context(); @@ -423,6 +425,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca } } + old_suspend_cause = s->suspend_cause; if (suspend_cause_changed) { char old_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; char new_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]; @@ -432,6 +435,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca s->suspend_cause = suspend_cause; } + old_state = s->state; 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; @@ -444,7 +448,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca } } - if (suspending || resuming) { + if (suspending || resuming || suspend_cause_changed) { pa_source_output *o; uint32_t idx; @@ -455,7 +459,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state, pa_suspend_ca (o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND)) pa_source_output_kill(o); else if (o->suspend) - o->suspend(o, state == PA_SOURCE_SUSPENDED); + o->suspend(o, old_state, old_suspend_cause); } return ret;