[pulseaudio-commits] 2 commits - src/modules src/pulsecore
Georg Chini
gchini at kemper.freedesktop.org
Wed Mar 29 05:13:18 UTC 2017
src/modules/echo-cancel/module-echo-cancel.c | 5 +--
src/modules/module-equalizer-sink.c | 2 -
src/modules/module-ladspa-sink.c | 2 -
src/modules/module-loopback.c | 13 +++++----
src/modules/module-remap-sink.c | 2 -
src/modules/module-remap-source.c | 3 --
src/modules/module-sine.c | 2 -
src/modules/module-suspend-on-idle.c | 4 +-
src/modules/module-virtual-sink.c | 2 -
src/modules/module-virtual-source.c | 5 +--
src/modules/module-virtual-surround-sink.c | 2 -
src/pulsecore/play-memblockq.c | 2 -
src/pulsecore/sink-input.c | 38 ++++++++++++++++++---------
src/pulsecore/sound-file-stream.c | 2 -
src/pulsecore/source-output.c | 24 +++++++++--------
15 files changed, 63 insertions(+), 45 deletions(-)
New commits:
commit f4f01f6833b30841e026febe0d831b7b3489b981
Author: Georg Chini <georg at chini.tk>
Date: Wed Mar 29 07:11:50 2017 +0200
loopback: Fix corking logic of module-loopback
When moving from a user suspended source or sink to an idle suspended source or sink
the sink input or source output would not be uncorked because we did not check for
the suspend cause.
Uncorking also would not be possible in that situation because the state change callback
of the source output or sink input is called before the new source or sink is attached,
leading to a crash of pulseaudio due to a cork() call without valid source or sink.
The previous patch fixes this problem, therefore sink input or source output can now also
be uncorked when the destination is idle suspended.
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 4456b559..5dcefbaa 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -565,8 +565,10 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
set_source_output_latency(u, dest);
update_effective_source_latency(u, dest, u->sink_input->sink);
+ /* Uncork the sink input unless the destination is suspended for other
+ * reasons than idle. */
if (pa_source_get_state(dest) == PA_SOURCE_SUSPENDED)
- pa_sink_input_cork(u->sink_input, true);
+ pa_sink_input_cork(u->sink_input, (dest->suspend_cause != PA_SUSPEND_IDLE));
else
pa_sink_input_cork(u->sink_input, false);
@@ -904,8 +906,10 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
set_sink_input_latency(u, dest);
update_effective_source_latency(u, u->source_output->source, dest);
+ /* Uncork the source output unless the destination is suspended for other
+ * reasons than idle */
if (pa_sink_get_state(dest) == PA_SINK_SUSPENDED)
- pa_source_output_cork(u->source_output, true);
+ pa_source_output_cork(u->source_output, (dest->suspend_cause != PA_SUSPEND_IDLE));
else
pa_source_output_cork(u->source_output, false);
commit 3650346f7041505fd0a28d939d05ac01e26e9b0c
Author: Georg Chini <georg at chini.tk>
Date: Wed Mar 29 07:10:28 2017 +0200
sink-input/source-output: Don't crash when cork() is called without valid sink or source
If pa_sink_input_cork() or pa_source_output_cork() were called without a sink
or source attached, the calls would crash pulseaudio.
This patch fixes the problem, so that a source output or sink input can still
be corked or uncorked while source or sink are invalid. This is needed to
correct the corking logic in module-loopback.
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 706b3022..14a148a3 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -1322,12 +1322,11 @@ static void sink_input_detach_cb(pa_sink_input *i) {
}
}
-/* Called from source I/O thread context. */
+/* Called from source I/O thread context except when cork() is called without valid source. */
static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
struct userdata *u;
pa_source_output_assert_ref(o);
- pa_source_output_assert_io_context(o);
pa_assert_se(u = o->userdata);
pa_log_debug("Source output %d state %d", o->index, state);
@@ -1345,7 +1344,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-equalizer-sink.c b/src/modules/module-equalizer-sink.c
index 9c25f3f5..eb461815 100644
--- a/src/modules/module-equalizer-sink.c
+++ b/src/modules/module-equalizer-sink.c
@@ -860,7 +860,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-ladspa-sink.c b/src/modules/module-ladspa-sink.c
index c11fa5e7..6dd29873 100644
--- a/src/modules/module-ladspa-sink.c
+++ b/src/modules/module-ladspa-sink.c
@@ -633,7 +633,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 12ab1209..4456b559 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -496,15 +496,14 @@ static void source_output_detach_cb(pa_source_output *o) {
}
}
-/* Called from input thread context */
+/* Called from input thread context except when cork() is called without valid source. */
static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
struct userdata *u;
pa_source_output_assert_ref(o);
- pa_source_output_assert_io_context(o);
pa_assert_se(u = o->userdata);
- if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
+ if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT && o->source) {
u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
u->latency),
diff --git a/src/modules/module-remap-sink.c b/src/modules/module-remap-sink.c
index 8a21c3c1..1b1c5e15 100644
--- a/src/modules/module-remap-sink.c
+++ b/src/modules/module-remap-sink.c
@@ -283,7 +283,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-remap-source.c b/src/modules/module-remap-source.c
index 9b62c518..3aa8f115 100644
--- a/src/modules/module-remap-source.c
+++ b/src/modules/module-remap-source.c
@@ -222,12 +222,11 @@ static void source_output_kill_cb(pa_source_output *o) {
pa_module_unload_request(u->module, true);
}
-/* Called from output thread context */
+/* Called from output thread context except when cork() is called without valid source. */
static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
struct userdata *u;
pa_source_output_assert_ref(o);
- pa_source_output_assert_io_context(o);
pa_assert_se(u = o->userdata);
pa_log_debug("Source output %d state %d.", o->index, state);
diff --git a/src/modules/module-sine.c b/src/modules/module-sine.c
index d56fae54..45920717 100644
--- a/src/modules/module-sine.c
+++ b/src/modules/module-sine.c
@@ -112,7 +112,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT)
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink)
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c
index 268f0aec..90d356fe 100644
--- a/src/modules/module-suspend-on-idle.c
+++ b/src/modules/module-suspend-on-idle.c
@@ -284,7 +284,7 @@ static pa_hook_result_t sink_input_state_changed_hook_cb(pa_core *c, pa_sink_inp
pa_assert(u);
state = pa_sink_input_get_state(s);
- if (state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED)
+ if ((state == PA_SINK_INPUT_RUNNING || state == PA_SINK_INPUT_DRAINED) && s->sink)
if ((d = pa_hashmap_get(u->device_infos, s->sink)))
resume(d);
@@ -296,7 +296,7 @@ static pa_hook_result_t source_output_state_changed_hook_cb(pa_core *c, pa_sourc
pa_source_output_assert_ref(s);
pa_assert(u);
- if (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_RUNNING) {
+ if (pa_source_output_get_state(s) == PA_SOURCE_OUTPUT_RUNNING && s->source) {
struct device_info *d;
if (s->source->monitor_of)
diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index 02cc1ac1..3316e930 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -409,7 +409,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/modules/module-virtual-source.c b/src/modules/module-virtual-source.c
index 36edf785..0fab31e4 100644
--- a/src/modules/module-virtual-source.c
+++ b/src/modules/module-virtual-source.c
@@ -391,17 +391,16 @@ static void source_output_detach_cb(pa_source_output *o) {
pa_source_set_rtpoll(u->source, NULL);
}
-/* Called from output thread context */
+/* Called from output thread context except when cork() is called without valid source.*/
static void source_output_state_change_cb(pa_source_output *o, pa_source_output_state_t state) {
struct userdata *u;
pa_source_output_assert_ref(o);
- pa_source_output_assert_io_context(o);
pa_assert_se(u = o->userdata);
/* FIXME */
#if 0
- if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT) {
+ if (PA_SOURCE_OUTPUT_IS_LINKED(state) && o->thread_info.state == PA_SOURCE_OUTPUT_INIT && o->source) {
u->skip = pa_usec_to_bytes(PA_CLIP_SUB(pa_source_get_latency_within_thread(o->source),
u->latency),
diff --git a/src/modules/module-virtual-surround-sink.c b/src/modules/module-virtual-surround-sink.c
index 6c7120a0..4a53623c 100644
--- a/src/modules/module-virtual-surround-sink.c
+++ b/src/modules/module-virtual-surround-sink.c
@@ -421,7 +421,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT) {
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink) {
pa_log_debug("Requesting rewind due to state change.");
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index e087047a..c86bd15f 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -102,7 +102,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT)
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink)
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index b937383e..d6ef57d3 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -604,14 +604,26 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
if (i->state == state)
return;
- if (i->state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING && pa_sink_used_by(i->sink) == 0 &&
- !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec)) {
- /* We were uncorked and the sink was not playing anything -- let's try
- * to update the sample rate to avoid resampling */
- pa_sink_update_rate(i->sink, i->sample_spec.rate, pa_sink_input_is_passthrough(i));
- }
+ if (i->sink) {
+ if (i->state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING && pa_sink_used_by(i->sink) == 0 &&
+ !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec)) {
+ /* We were uncorked and the sink was not playing anything -- let's try
+ * to update the sample rate to avoid resampling */
+ pa_sink_update_rate(i->sink, i->sample_spec.rate, pa_sink_input_is_passthrough(i));
+ }
+
+ pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
+ } else {
+ /* If the sink is not valid, pa_sink_input_set_state_within_thread() must be called directly */
+
+ pa_sink_input_set_state_within_thread(i, state);
- pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
+ for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev)
+ pa_sink_input_set_state_within_thread(ssync, state);
+
+ for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next)
+ pa_sink_input_set_state_within_thread(ssync, state);
+ }
update_n_corked(i, state);
i->state = state;
@@ -638,7 +650,8 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
}
- pa_sink_update_status(i->sink);
+ if (i->sink)
+ pa_sink_update_status(i->sink);
}
/* Called from main context */
@@ -1952,12 +1965,11 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, bool save) {
return 0;
}
-/* Called from IO thread context */
+/* Called from IO thread context except when cork() is called without a valid sink. */
void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
bool corking, uncorking;
pa_sink_input_assert_ref(i);
- pa_sink_input_assert_io_context(i);
if (state == i->thread_info.state)
return;
@@ -1978,7 +1990,8 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
/* This will tell the implementing sink input driver to rewind
* so that the unplayed already mixed data is not lost */
- pa_sink_input_request_rewind(i, 0, true, true, false);
+ if (i->sink)
+ pa_sink_input_request_rewind(i, 0, true, true, false);
/* Set the corked state *after* requesting rewind */
i->thread_info.state = state;
@@ -1996,7 +2009,8 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
/* OK, we're being uncorked. Make sure we're not rewound when
* the hw buffer is remixed and request a remix. */
- pa_sink_input_request_rewind(i, 0, false, true, true);
+ if (i->sink)
+ pa_sink_input_request_rewind(i, 0, false, true, true);
} else
/* We may not be corking or uncorking, but we still need to set the state. */
i->thread_info.state = state;
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index ddda456e..aeaa6085 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -129,7 +129,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
/* If we are added for the first time, ask for a rewinding so that
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
- i->thread_info.state == PA_SINK_INPUT_INIT)
+ i->thread_info.state == PA_SINK_INPUT_INIT && i->sink)
pa_sink_input_request_rewind(i, 0, false, true, true);
}
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 0ba19c82..7cbc5adf 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -524,14 +524,18 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
if (o->state == state)
return;
- if (o->state == PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_RUNNING && pa_source_used_by(o->source) == 0 &&
- !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec)) {
- /* We were uncorked and the source was not playing anything -- let's try
- * to update the sample rate to avoid resampling */
- pa_source_update_rate(o->source, o->sample_spec.rate, pa_source_output_is_passthrough(o));
- }
+ if (o->source) {
+ if (o->state == PA_SOURCE_OUTPUT_CORKED && state == PA_SOURCE_OUTPUT_RUNNING && pa_source_used_by(o->source) == 0 &&
+ !pa_sample_spec_equal(&o->sample_spec, &o->source->sample_spec)) {
+ /* We were uncorked and the source was not playing anything -- let's try
+ * to update the sample rate to avoid resampling */
+ pa_source_update_rate(o->source, o->sample_spec.rate, pa_source_output_is_passthrough(o));
+ }
- pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
+ pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
+ } else
+ /* If the source is not valid, pa_source_output_set_state_within_thread() must be called directly */
+ pa_source_output_set_state_within_thread(o, state);
update_n_corked(o, state);
o->state = state;
@@ -543,7 +547,8 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
}
- pa_source_update_status(o->source);
+ if (o->source)
+ pa_source_update_status(o->source);
}
/* Called from main context */
@@ -1584,10 +1589,9 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, bool save) {
return 0;
}
-/* Called from IO thread context */
+/* Called from IO thread context except when cork() is called without a valid source. */
void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) {
pa_source_output_assert_ref(o);
- pa_source_output_assert_io_context(o);
if (state == o->thread_info.state)
return;
More information about the pulseaudio-commits
mailing list