card: handle sticky profile flag

New card database entry version 5 for card profile is sticky flag.
New messaging API handlers set-profile-sticky and get-profile-sticky.

When card profile is sticky, always restore it even if it is unavailable,
and prevent switching from it when ports become unavailable.

Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/568>
This commit is contained in:
Igor V. Kovalenko 2020-12-16 00:35:05 +03:00 committed by PulseAudio Marge Bot
parent 79cb1369fc
commit e576bd924f
5 changed files with 133 additions and 5 deletions

View file

@ -67,7 +67,7 @@ struct userdata {
bool restore_bluetooth_profile;
};
#define ENTRY_VERSION 4
#define ENTRY_VERSION 5
struct port_info {
char *name;
@ -80,6 +80,7 @@ struct entry {
pa_hashmap *ports; /* Port name -> struct port_info */
char *preferred_input_port;
char *preferred_output_port;
bool profile_is_sticky; /* since version 5; must be restored together with profile name */
};
static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
@ -153,7 +154,8 @@ static struct entry *entry_from_card(pa_card *card) {
pa_assert(card);
entry = entry_new();
if (card->save_profile)
entry->profile_is_sticky = card->profile_is_sticky;
if (card->save_profile || entry->profile_is_sticky)
entry->profile = pa_xstrdup(card->active_profile->name);
PA_HASHMAP_FOREACH(port, card->ports, state) {
@ -189,6 +191,9 @@ static bool entrys_equal(struct entry *a, struct entry *b) {
if (!pa_safe_streq(a->preferred_output_port, b->preferred_output_port))
return false;
if (a->profile_is_sticky != b->profile_is_sticky)
return false;
return true;
}
@ -217,6 +222,8 @@ static bool entry_write(struct userdata *u, const char *name, const struct entry
pa_tagstruct_puts(t, e->preferred_input_port);
pa_tagstruct_puts(t, e->preferred_output_port);
pa_tagstruct_put_boolean(t, e->profile_is_sticky);
key.data = (char *) name;
key.size = strlen(name);
@ -342,6 +349,14 @@ static struct entry* entry_read(struct userdata *u, const char *name) {
e->preferred_output_port = pa_xstrdup(preferred_output_port);
}
if (version >= 5) {
bool profile_is_sticky;
if (pa_tagstruct_get_boolean(t, &profile_is_sticky) < 0)
goto fail;
e->profile_is_sticky = profile_is_sticky;
}
if (!pa_tagstruct_eof(t))
goto fail;
@ -437,11 +452,12 @@ static pa_hook_result_t card_profile_changed_callback(pa_core *c, pa_card *card,
pa_assert(card);
if (!card->save_profile)
if (!card->save_profile && !card->profile_is_sticky)
return PA_HOOK_OK;
if ((entry = entry_read(u, card->name))) {
pa_xfree(entry->profile);
entry->profile_is_sticky = card->profile_is_sticky;
entry->profile = pa_xstrdup(card->active_profile->name);
pa_log_info("Storing card profile for card %s.", card->name);
} else {
@ -565,12 +581,18 @@ static pa_hook_result_t card_choose_initial_profile_callback(pa_core *core, pa_c
goto finish;
}
card->profile_is_sticky = e->profile_is_sticky;
pa_log_info("Profile '%s' was previously %s for card %s.",
e->profile,
card->profile_is_sticky ? "sticky" : "automatically selected",
card->name);
if (e->profile[0]) {
pa_card_profile *profile;
profile = pa_hashmap_get(card->profiles, e->profile);
if (profile) {
if (profile->available != PA_AVAILABLE_NO) {
if (profile->available != PA_AVAILABLE_NO || card->profile_is_sticky) {
pa_log_info("Restoring profile '%s' for card %s.", profile->name, card->name);
pa_card_set_profile(card, profile, true);
} else