[pulseaudio-discuss] Audio APP (sink-input) bind to the sink with only unplugged hdmi-audio ports on it
Hui Wang
hui.wang at canonical.com
Sun Sep 30 08:53:13 UTC 2018
The tentative fix of this problem like this:
When a port is unplugged, it is caught by
module-switch-on-port-available.c, here we check if the sink of this
port is default_sink or not, if it is default_sink, it means the sink of
this port is still the highest priority one, no need to move
sink-inputs, otherwise, try to move all sink-inputs of this sink to
default_sink temporarily.
To restore the sink-inputs to its original sink, it depends on
module-stream-restore.c, but we don't let it restore unconditionally, if
the target sink has at least one port with avaialbe_yes/unknow, let it
restore.
So supposing one sink has speaker, the other sink has hdmi-audio, when
unplugging the hdmi cable, the audio will route to speaker, after
plugging the hdmi cable again, when app build new sink-input, it will
restore the sound to original sink.
diff --git a/src/modules/module-stream-restore.c
b/src/modules/module-stream-restore.c
index 228e9e4..2dd825f 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -1424,6 +1424,7 @@ static void subscribe_callback(pa_core *c,
pa_subscription_event_type_t t, uint3
static pa_hook_result_t sink_input_new_hook_callback(pa_core *c,
pa_sink_input_new_data *new_data, struct userdata *u) {
char *name;
struct entry *e;
+ bool good = 0;
pa_assert(c);
pa_assert(new_data);
@@ -1450,6 +1451,21 @@ static pa_hook_result_t
sink_input_new_hook_callback(pa_core *c, pa_sink_input_n
s = pa_idxset_first(card->sinks, NULL);
}
+ /* if all ports on this sink are all available_no, we don't set
this sink temporarily */
+ if (s) {
+ pa_device_port *i;
+ void *state_p;
+ PA_HASHMAP_FOREACH(i, s->ports, state_p) {
+ if (i->available != PA_AVAILABLE_NO) {
+ good = 1;
+ break;
+ }
+ }
+ }
+
+ if (!good)
+ s = NULL;
+
/* It might happen that a stream and a sink are set up at the
same time, in which case we want to make sure we don't
interfere with that */
diff --git a/src/modules/module-switch-on-port-available.c
b/src/modules/module-switch-on-port-available.c
index 321db36..acd3252 100644
--- a/src/modules/module-switch-on-port-available.c
+++ b/src/modules/module-switch-on-port-available.c
@@ -272,6 +272,63 @@ static void switch_from_port(pa_device_port *port) {
switch_to_port(best_port);
}
+/* This function refers to sink_put_hook_callback() in the
module-switch-on-connect.c */
+static void move_input_to_default_sink(pa_core *c, pa_sink *ori_sink,
pa_sink *new_sink)
+{
+ pa_sink_input *i;
+ uint32_t idx;
+
+ /* Now move all old inputs over */
+ if (pa_idxset_size(ori_sink->inputs) <= 0) {
+ pa_log_debug("No sink inputs to move away.");
+ return;
+ }
+
+ PA_IDXSET_FOREACH(i, ori_sink->inputs, idx) {
+ /* don't check i->save_sink here, since we have to move input
temporarily */
+ if (!PA_SINK_INPUT_IS_LINKED(i->state))
+ continue;
+
+ if (pa_sink_input_move_to(i, new_sink, false) < 0)
+ pa_log_info("Failed to move sink input %u \"%s\" to %s.",
i->index,
+ pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)),
new_sink->name);
+ else
+ pa_log_info("Successfully moved sink input %u \"%s\" to
%s.", i->index,
+ pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_APPLICATION_NAME)),
new_sink->name);
+ }
+}
+
+static void check_and_move_sink_inputs_to_default_sink(pa_core *c,
pa_device_port *port)
+{
+ struct port_pointers pp = find_port_pointers(port);
+ pa_sink *def_sink, *p_sink = pp.sink;
+
+ switch (port->direction) {
+ case PA_DIRECTION_OUTPUT:
+ def_sink = c->default_sink;
+
+ /* check if there is better sinks to move to, before here,the
default_sink is already
+ re-selected when the port is changing unavailble, if p_sink
equals default_sink,
+ it means there is no better sinks to replace the sink
containing this port */
+ if (p_sink != def_sink) {
+ void *state_p;
+ pa_device_port *i;
+
+ /* check if all ports on this sink are available_no, if not,
don't need to move the input */
+ PA_HASHMAP_FOREACH(i, p_sink->ports, state_p) {
+ if (i->available != PA_AVAILABLE_NO)
+ return;
+ }
+
+ /* now the default sink is the best sink already */
+ move_input_to_default_sink(c, pp.sink, def_sink);
+ }
+ break;
+
+ case PA_DIRECTION_INPUT:
+ break;
+ }
+}
static pa_hook_result_t port_available_hook_callback(pa_core *c,
pa_device_port *port, void* userdata) {
pa_assert(port);
@@ -295,6 +352,7 @@ static pa_hook_result_t
port_available_hook_callback(pa_core *c, pa_device_port
break;
case PA_AVAILABLE_NO:
switch_from_port(port);
+ check_and_move_sink_inputs_to_default_sink(c, port);
break;
default:
break;
On 2018年09月30日 15:03, Hui Wang wrote:
> This issue is also reported to:
> https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/579
>
> Recently we found a weird issue on many laptops with the ubuntu 18.04,
> it uses the pulseaudio-11.1 (I guess the PA of the latest version also
> has this problem). The issue is like this:
>
> 1. boot the system up without plugging a hdmi monitor
> 2. run an audio app to play sound (e.g. $speaker-test)
> 3. the sound outputs from analog-speaker
> 4. plug a monitor with audio capability (through DP or HDMI port)
> 5. the sound still outputs from analog-speaker
> 6. open sound-setting (gnome-control-center --> choose sound), you will
> see two output devies: speaker and HDMI audio
> 7. choose HDMI audio, the sound will switch to HDIM audio from speaker
> (pa will remember speaker-test prefer to use hdmi-audio sink)
> 8. unplug the monitor, the default-sink is switching to analog-speaker,
> but the sound of speaker-test still route to hdmi-audio sink
> 9. run other sound apps, they all route sound to default sink
> (analog-speaker), but speaker-test always routes to hdmi-audio sink,
> as a result, speaker-test can't output sound anymore unless we
> replug a monitor with audio capability then the speaker-test output
> from hdmi-audio again.
> 10. if we want the speaker-test to route to analog-speaker, two ways:
> run pacmd move-sink-input or plug a monitor, after two audio devices
> (hdmi audio and speaker) show up in the sound-setting, select
> analog-speaker manually.
>
> This issue only happens on the laptops with 2 audio cards, analog
> devices on one card, hdmi audio on the other card. This kind of
> laptops are very common, like I+A (Intel graphic + Amd Graphic),
> I+N(Intel + Nvidia), and A AMD.
>
> This issue will not happen on the laptops with only Intel graphic
> card, since both analog and hdmi audio belong to one sound card. When
> hdmi monitor is unplugged, the hdmi sink will be removed from PA, then
> all sink-inputs will route to the only left sink: analog-sink.
>
> This issue will not happen on BT or USB audio. Unlike hdmi audio, BT
> and USB audio cards will be removed totally from PA when they are
> unpluged/unconnected, so they don't have this issue as well.
>
> The root cause of this issue is although the hdmi monitor is
> unplugged, the hdmi-sink still exists, and sink-input is selected by
> user to bind to this sink, so the pa doesn't care about if this sink
> has valid port or not, it bind the sink-input to this sink
> unconditionally.
>
> Maybe we could improve it like this: if the user selected sink only
> has available_no ports, the pa will switch all sink-inputs of this
> sink to other sinks (like default_sink) temporarily, once the selected
> sink has availble ports, all sink-inputs switch back to this sink.
>
> Any good ideas?
>
> Thanks,
>
> Hui.
>
>
> _______________________________________________
> pulseaudio-discuss mailing list
> pulseaudio-discuss at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss
More information about the pulseaudio-discuss
mailing list