[pulseaudio-discuss] [RFC PATCH 3/4] alsa-card: Switch profile when the active one becomes unavailable
João Paulo Rechi Vita
jprvita at gmail.com
Wed Aug 8 05:00:51 UTC 2018
When the active profile of a card becomes unavailable and no other
module changes it to a better profile (i.e. there are no available ports
that module-switch-on-port-available could switch to) the card will be
stuck on an unavailable profile with a non-working sink/source and any
active streams connected to that sink/source will remain connected.
This commit switches to a different profile when the active profile
becomes unavailble, looking for a profile with availability yes or
unknown with the highest priority, and ultimately fall-backing to the
OFF profile.
With this fix a card that only has one port can have the streams
connected to its sink/source moved away by module-rescue-stream when
that port becomes unavailable. This has been seen on machines with AMD
graphics, where the HDMI port lives on a separate ALSA card that only
has that port.
---
src/modules/alsa/module-alsa-card.c | 54 +++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 041d53121..1fc5216fc 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -735,6 +735,57 @@ static pa_hook_result_t source_output_unlink_hook_callback(pa_core *c, pa_source
return PA_HOOK_OK;
}
+static pa_card_profile *find_best_profile(pa_card *card) {
+ pa_card_profile *profile = NULL;
+ pa_card_profile *best_profile = NULL;
+ void *state;
+
+ pa_assert(card);
+ best_profile = pa_hashmap_get(card->profiles, "off");
+
+ PA_HASHMAP_FOREACH(profile, card->profiles, state) {
+ if (profile->available == PA_AVAILABLE_NO)
+ continue;
+
+ if (!pa_card_profile_has_available_ports(profile, PA_DIRECTION_OUTPUT, PA_AVAILABLE_YES))
+ continue;
+
+ if (profile->priority > best_profile->priority)
+ best_profile = profile;
+ }
+
+ if (pa_safe_streq(best_profile->name, "off")) {
+ PA_HASHMAP_FOREACH(profile, card->profiles, state) {
+ if (profile->available == PA_AVAILABLE_NO)
+ continue;
+
+ if (!pa_card_profile_has_available_ports(profile, PA_DIRECTION_OUTPUT, PA_AVAILABLE_UNKNOWN))
+ continue;
+
+ if (profile->priority > best_profile->priority)
+ best_profile = profile;
+ }
+ }
+
+ return best_profile;
+}
+
+static pa_hook_result_t card_profile_available_changed(pa_core *c, pa_card_profile *profile, struct userdata *u) {
+ pa_card *card;
+
+ pa_assert(profile);
+ pa_assert_se(card = profile->card);
+
+ if (profile->available != PA_AVAILABLE_NO)
+ return PA_HOOK_OK;
+
+ if (!pa_safe_streq(profile->name, card->active_profile->name))
+ return PA_HOOK_OK;
+
+ pa_log_debug("Active profile %s on card %s became unavailable, switching to another profile", profile->name, card->name);
+ return pa_card_set_profile(card, find_best_profile(card), false);
+}
+
int pa__init(pa_module *m) {
pa_card_new_data data;
bool ignore_dB = false;
@@ -912,6 +963,9 @@ int pa__init(pa_module *m) {
init_jacks(u);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED], PA_HOOK_NORMAL,
+ (pa_hook_cb_t) card_profile_available_changed, u);
+
pa_card_choose_initial_profile(u->card);
/* If the "profile" modarg is given, we have to override whatever the usual
--
2.18.0
More information about the pulseaudio-discuss
mailing list