[pulseaudio-commits] 3 commits - src/modules src/pulsecore
Arun Raghavan
arun at kemper.freedesktop.org
Thu May 5 02:46:49 UTC 2016
src/modules/module-card-restore.c | 68 ++++++++
src/modules/module-switch-on-port-available.c | 209 +++++++++++++++++++++++++-
src/pulsecore/card.c | 46 +++++
src/pulsecore/card.h | 12 +
src/pulsecore/core.h | 1
5 files changed, 328 insertions(+), 8 deletions(-)
New commits:
commit 23c15c3b52a958887c1f8cad3c94879a8770ef0e
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Fri Mar 4 15:23:32 2016 +0200
switch-on-port-available: prefer ports that have been selected by the user
Let's assume that there are two output ports, and they are on
different profiles:
* Integrated speakers (priority: 10000, available)
* HDMI (priority: 5900, not available)
Then the user plugs in an HDMI monitor with speakers. Since the HDMI
priority is lower than the speaker priority, we don't route to HDMI by
default. However, the user manually switches the profile to use the
HDMI output.
Then the user plugs out the monitor, so we switch back to speakers.
When the monitor is plugged back in, the user needs to manually switch
the audio output again. That should be improved: if the user preferred
to the HDMI output over the speakers, we should remember that and
automatically switch to HDMI whenever it becomes available.
The lack of automatic switching is even worse when the monitor goes to
a sleep mode after some period of inactivity. The monitor audio may
become unavailable, and PulseAudio can't distinguish that from the
case where the monitor is physically unplugged. Even worse, the
monitor may become unavailable for a short while when adjusting the
display parameters (for example, media center software may adjust the
display parameters to match the media that is being played back). In
these cases we clearly should switch automatically back to HDMI when
it becomes available again.
This patch fixes the problem by setting pa_card.preferred_input_port
and pa_card.preferred_output_port when the user changes the card
profile or a port, and switching to the preferred port when it becomes
available.
BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=93946
diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c
index 2453644..b9a0f3b 100644
--- a/src/modules/module-switch-on-port-available.c
+++ b/src/modules/module-switch-on-port-available.c
@@ -29,7 +29,37 @@
#include "module-switch-on-port-available-symdef.h"
-static bool profile_good_for_output(pa_card_profile *profile, unsigned prio) {
+struct card_info {
+ struct userdata *userdata;
+ pa_card *card;
+
+ /* We need to cache the active profile, because we want to compare the old
+ * and new profiles in the PROFILE_CHANGED hook. Without this we'd only
+ * have access to the new profile. */
+ pa_card_profile *active_profile;
+};
+
+struct userdata {
+ pa_hashmap *card_infos; /* pa_card -> struct card_info */
+};
+
+static void card_info_new(struct userdata *u, pa_card *card) {
+ struct card_info *info;
+
+ info = pa_xnew0(struct card_info, 1);
+ info->userdata = u;
+ info->card = card;
+ info->active_profile = card->active_profile;
+
+ pa_hashmap_put(u->card_infos, card, info);
+}
+
+static void card_info_free(struct card_info *info) {
+ pa_hashmap_remove(info->userdata->card_infos, info->card);
+ pa_xfree(info);
+}
+
+static bool profile_good_for_output(pa_card_profile *profile, pa_device_port *port) {
pa_card *card;
pa_sink *sink;
uint32_t idx;
@@ -47,19 +77,21 @@ static bool profile_good_for_output(pa_card_profile *profile, unsigned prio) {
if (card->active_profile->max_source_channels != profile->max_source_channels)
return false;
- /* Try not to switch to HDMI sinks from analog when HDMI is becoming available */
+ if (port == card->preferred_output_port)
+ return true;
+
PA_IDXSET_FOREACH(sink, card->sinks, idx) {
if (!sink->active_port)
continue;
- if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= prio))
+ if ((sink->active_port->available != PA_AVAILABLE_NO) && (sink->active_port->priority >= port->priority))
return false;
}
return true;
}
-static bool profile_good_for_input(pa_card_profile *profile, unsigned prio) {
+static bool profile_good_for_input(pa_card_profile *profile, pa_device_port *port) {
pa_card *card;
pa_source *source;
uint32_t idx;
@@ -77,11 +109,14 @@ static bool profile_good_for_input(pa_card_profile *profile, unsigned prio) {
if (card->active_profile->max_sink_channels != profile->max_sink_channels)
return false;
+ if (port == card->preferred_input_port)
+ return true;
+
PA_IDXSET_FOREACH(source, card->sources, idx) {
if (!source->active_port)
continue;
- if ((source->active_port->available != PA_AVAILABLE_NO) && (source->active_port->priority >= prio))
+ if ((source->active_port->available != PA_AVAILABLE_NO) && (source->active_port->priority >= port->priority))
return false;
}
@@ -105,12 +140,12 @@ static int try_to_switch_profile(pa_device_port *port) {
switch (port->direction) {
case PA_DIRECTION_OUTPUT:
name = profile->output_name;
- good = profile_good_for_output(profile, port->priority);
+ good = profile_good_for_output(profile, port);
break;
case PA_DIRECTION_INPUT:
name = profile->input_name;
- good = profile_good_for_input(profile, port->priority);
+ good = profile_good_for_input(profile, port);
break;
}
@@ -324,9 +359,142 @@ static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data
return PA_HOOK_OK;
}
+static pa_hook_result_t card_put_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
+ card_info_new(u, card);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t card_unlink_hook_callback(pa_core *core, pa_card *card, struct userdata *u) {
+ card_info_free(pa_hashmap_get(u->card_infos, card));
+
+ return PA_HOOK_OK;
+}
+
+static void update_preferred_input_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
+ pa_source *source;
+
+ /* If the profile change didn't affect input, it doesn't indicate change in
+ * the user's input port preference. */
+ if (pa_safe_streq(old_profile->input_name, new_profile->input_name))
+ return;
+
+ /* If there are more than one source, we don't know which of those the user
+ * prefers. If there are no sources, then the user doesn't seem to care
+ * about input at all. */
+ if (pa_idxset_size(card->sources) != 1) {
+ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
+ return;
+ }
+
+ /* If the profile change modified the set of sinks, then it's unclear
+ * whether the user wanted to activate some specific input port, or was the
+ * input change only a side effect of activating some output. If the new
+ * profile contains no sinks, though, then we know the user only cares
+ * about input. */
+ if (pa_idxset_size(card->sinks) > 0 && !pa_safe_streq(old_profile->output_name, new_profile->output_name)) {
+ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, NULL);
+ return;
+ }
+
+ source = pa_idxset_first(card->sources, NULL);
+
+ /* We know the user wanted to activate this source. The user might not have
+ * wanted to activate the port that was selected by default, but if that's
+ * the case, the user will change the port manually, and we'll update the
+ * port preference at that time. If no port change occurs, we can assume
+ * that the user likes the port that is now active. */
+ pa_card_set_preferred_port(card, PA_DIRECTION_INPUT, source->active_port);
+}
+
+static void update_preferred_output_port(pa_card *card, pa_card_profile *old_profile, pa_card_profile *new_profile) {
+ pa_sink *sink;
+
+ /* If the profile change didn't affect output, it doesn't indicate change in
+ * the user's output port preference. */
+ if (pa_safe_streq(old_profile->output_name, new_profile->output_name))
+ return;
+
+ /* If there are more than one sink, we don't know which of those the user
+ * prefers. If there are no sinks, then the user doesn't seem to care about
+ * output at all. */
+ if (pa_idxset_size(card->sinks) != 1) {
+ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
+ return;
+ }
+
+ /* If the profile change modified the set of sources, then it's unclear
+ * whether the user wanted to activate some specific output port, or was
+ * the output change only a side effect of activating some input. If the
+ * new profile contains no sources, though, then we know the user only
+ * cares about output. */
+ if (pa_idxset_size(card->sources) > 0 && !pa_safe_streq(old_profile->input_name, new_profile->input_name)) {
+ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, NULL);
+ return;
+ }
+
+ sink = pa_idxset_first(card->sinks, NULL);
+
+ /* We know the user wanted to activate this sink. The user might not have
+ * wanted to activate the port that was selected by default, but if that's
+ * the case, the user will change the port manually, and we'll update the
+ * port preference at that time. If no port change occurs, we can assume
+ * that the user likes the port that is now active. */
+ pa_card_set_preferred_port(card, PA_DIRECTION_OUTPUT, sink->active_port);
+}
+
+static pa_hook_result_t card_profile_changed_callback(pa_core *core, pa_card *card, struct userdata *u) {
+ struct card_info *info;
+ pa_card_profile *old_profile;
+ pa_card_profile *new_profile;
+
+ info = pa_hashmap_get(u->card_infos, card);
+ old_profile = info->active_profile;
+ new_profile = card->active_profile;
+ info->active_profile = new_profile;
+
+ /* This profile change wasn't initiated by the user, so it doesn't signal
+ * a change in the user's port preferences. */
+ if (!card->save_profile)
+ return PA_HOOK_OK;
+
+ update_preferred_input_port(card, old_profile, new_profile);
+ update_preferred_output_port(card, old_profile, new_profile);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t source_port_changed_callback(pa_core *core, pa_source *source, void *userdata) {
+ if (!source->save_port)
+ return PA_HOOK_OK;
+
+ pa_card_set_preferred_port(source->card, PA_DIRECTION_INPUT, source->active_port);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_port_changed_callback(pa_core *core, pa_sink *sink, void *userdata) {
+ if (!sink->save_port)
+ return PA_HOOK_OK;
+
+ pa_card_set_preferred_port(sink->card, PA_DIRECTION_OUTPUT, sink->active_port);
+
+ return PA_HOOK_OK;
+}
+
int pa__init(pa_module*m) {
+ struct userdata *u;
+ pa_card *card;
+ uint32_t idx;
+
pa_assert(m);
+ u = m->userdata = pa_xnew0(struct userdata, 1);
+ u->card_infos = pa_hashmap_new(NULL, NULL);
+
+ PA_IDXSET_FOREACH(card, m->core->cards, idx)
+ card_info_new(u, card);
+
/* Make sure we are after module-device-restore, so we can overwrite that suggestion if necessary */
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_NEW],
PA_HOOK_NORMAL, (pa_hook_cb_t) sink_new_hook_callback, NULL);
@@ -334,8 +502,35 @@ int pa__init(pa_module*m) {
PA_HOOK_NORMAL, (pa_hook_cb_t) source_new_hook_callback, NULL);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED],
PA_HOOK_LATE, (pa_hook_cb_t) port_available_hook_callback, NULL);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT],
+ PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_UNLINK],
+ PA_HOOK_NORMAL, (pa_hook_cb_t) card_unlink_hook_callback, u);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED],
+ PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SOURCE_PORT_CHANGED],
+ PA_HOOK_NORMAL, (pa_hook_cb_t) source_port_changed_callback, NULL);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED],
+ PA_HOOK_NORMAL, (pa_hook_cb_t) sink_port_changed_callback, NULL);
handle_all_unavailable(m->core);
return 0;
}
+
+void pa__done(pa_module *module) {
+ struct userdata *u;
+ struct card_info *info;
+
+ pa_assert(module);
+
+ if (!(u = module->userdata))
+ return;
+
+ while ((info = pa_hashmap_last(u->card_infos)))
+ card_info_free(info);
+
+ pa_hashmap_free(u->card_infos);
+
+ pa_xfree(u);
+}
commit c4058b8d00a51d8c600d950c8ec8967ab9c6f7ea
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Fri Mar 4 15:23:31 2016 +0200
card-restore: restore preferred ports
diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
index 2660a2b..7545aa5 100644
--- a/src/modules/module-card-restore.c
+++ b/src/modules/module-card-restore.c
@@ -64,7 +64,7 @@ struct userdata {
pa_database *database;
};
-#define ENTRY_VERSION 3
+#define ENTRY_VERSION 4
struct port_info {
char *name;
@@ -75,6 +75,8 @@ struct port_info {
struct entry {
char *profile;
pa_hashmap *ports; /* Port name -> struct port_info */
+ char *preferred_input_port;
+ char *preferred_output_port;
};
static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
@@ -131,6 +133,8 @@ static struct port_info *port_info_new(pa_device_port *port) {
static void entry_free(struct entry* e) {
pa_assert(e);
+ pa_xfree(e->preferred_output_port);
+ pa_xfree(e->preferred_input_port);
pa_xfree(e->profile);
pa_hashmap_free(e->ports);
@@ -176,6 +180,12 @@ static bool entrys_equal(struct entry *a, struct entry *b) {
return false;
}
+ if (!pa_safe_streq(a->preferred_input_port, b->preferred_input_port))
+ return false;
+
+ if (!pa_safe_streq(a->preferred_output_port, b->preferred_output_port))
+ return false;
+
return true;
}
@@ -201,6 +211,9 @@ static bool entry_write(struct userdata *u, const char *name, const struct entry
pa_tagstruct_puts(t, p_info->profile);
}
+ pa_tagstruct_puts(t, e->preferred_input_port);
+ pa_tagstruct_puts(t, e->preferred_output_port);
+
key.data = (char *) name;
key.size = strlen(name);
@@ -314,6 +327,18 @@ static struct entry* entry_read(struct userdata *u, const char *name) {
}
}
+ if (version >= 4) {
+ const char *preferred_input_port;
+ const char *preferred_output_port;
+
+ if (pa_tagstruct_gets(t, &preferred_input_port) < 0
+ || pa_tagstruct_gets(t, &preferred_output_port) < 0)
+ goto fail;
+
+ e->preferred_input_port = pa_xstrdup(preferred_input_port);
+ e->preferred_output_port = pa_xstrdup(preferred_output_port);
+ }
+
if (!pa_tagstruct_eof(t))
goto fail;
@@ -547,6 +572,46 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new
if (!p->preferred_profile && p_info->profile)
pa_device_port_set_preferred_profile(p, p_info->profile);
}
+
+ if (e->preferred_input_port) {
+ p = pa_hashmap_get(new_data->ports, e->preferred_input_port);
+ if (p)
+ pa_card_new_data_set_preferred_port(new_data, PA_DIRECTION_INPUT, p);
+ }
+
+ if (e->preferred_output_port) {
+ p = pa_hashmap_get(new_data->ports, e->preferred_output_port);
+ if (p)
+ pa_card_new_data_set_preferred_port(new_data, PA_DIRECTION_OUTPUT, p);
+ }
+
+ entry_free(e);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t card_preferred_port_changed_callback(pa_core *core, pa_card_preferred_port_changed_hook_data *data,
+ struct userdata *u) {
+ struct entry *e;
+ pa_card *card;
+
+ card = data->card;
+
+ e = entry_read(u, card->name);
+ if (!e)
+ e = entry_from_card(card);
+
+ if (data->direction == PA_DIRECTION_INPUT) {
+ pa_xfree(e->preferred_input_port);
+ e->preferred_input_port = pa_xstrdup(card->preferred_input_port ? card->preferred_input_port->name : NULL);
+ } else {
+ pa_xfree(e->preferred_output_port);
+ e->preferred_output_port = pa_xstrdup(card->preferred_output_port ? card->preferred_output_port->name : NULL);
+ }
+
+ if (entry_write(u, card->name, e))
+ trigger_save(u);
+
entry_free(e);
return PA_HOOK_OK;
@@ -570,6 +635,7 @@ int pa__init(pa_module*m) {
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) card_new_hook_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) card_put_hook_callback, u);
+ pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_preferred_port_changed_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_changed_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_ADDED], PA_HOOK_NORMAL, (pa_hook_cb_t) card_profile_added_callback, u);
pa_module_hook_connect(m, &m->core->hooks[PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED],
commit 04040c522f5f62dda50ac927e92453381d419f09
Author: Tanu Kaskinen <tanuk at iki.fi>
Date: Fri Mar 4 15:23:30 2016 +0200
card: add preferred_{input, output}_port
I will modify module-switch-on-port-available so that it will keep
track of which input and output port the user prefers on the card,
based on the user's profile and port switches. The preference needs
to be saved on disk, for which I will use module-card-restore.
To facilitate communication between the two modules, this patch adds
preferred_input_port and preferred_output_port fields to pa_card, and
a hook for monitoring the variable changes. It would be nice if the
two modules would communicate directly with each other, but
implementing that would be somewhat complicated, so I chose this time
for adding the functionality to the core. In theory some other routing
module might want to manage the new variables instead of
module-switch-on-port-available, but admittedly that's not very likely
to happen...
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index b6cbbf7..0eaccff 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -103,6 +103,15 @@ void pa_card_new_data_set_profile(pa_card_new_data *data, const char *profile) {
data->active_profile = pa_xstrdup(profile);
}
+void pa_card_new_data_set_preferred_port(pa_card_new_data *data, pa_direction_t direction, pa_device_port *port) {
+ pa_assert(data);
+
+ if (direction == PA_DIRECTION_INPUT)
+ data->preferred_input_port = port;
+ else
+ data->preferred_output_port = port;
+}
+
void pa_card_new_data_done(pa_card_new_data *data) {
pa_assert(data);
@@ -169,6 +178,9 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
PA_HASHMAP_FOREACH(port, c->ports, state)
port->card = c;
+ c->preferred_input_port = data->preferred_input_port;
+ c->preferred_output_port = data->preferred_output_port;
+
if (data->active_profile)
if ((c->active_profile = pa_hashmap_get(c->profiles, data->active_profile)))
c->save_profile = data->save_profile;
@@ -309,6 +321,40 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) {
return 0;
}
+void pa_card_set_preferred_port(pa_card *c, pa_direction_t direction, pa_device_port *port) {
+ pa_device_port *old_port;
+ const char *old_port_str;
+ const char *new_port_str;
+ pa_card_preferred_port_changed_hook_data data;
+
+ pa_assert(c);
+
+ if (direction == PA_DIRECTION_INPUT) {
+ old_port = c->preferred_input_port;
+ old_port_str = c->preferred_input_port ? c->preferred_input_port->name : "(unset)";
+ } else {
+ old_port = c->preferred_output_port;
+ old_port_str = c->preferred_output_port ? c->preferred_output_port->name : "(unset)";
+ }
+
+ if (port == old_port)
+ return;
+
+ new_port_str = port ? port->name : "(unset)";
+
+ if (direction == PA_DIRECTION_INPUT) {
+ c->preferred_input_port = port;
+ pa_log_debug("%s: preferred_input_port: %s -> %s", c->name, old_port_str, new_port_str);
+ } else {
+ c->preferred_output_port = port;
+ pa_log_debug("%s: preferred_output_port: %s -> %s", c->name, old_port_str, new_port_str);
+ }
+
+ data.card = c;
+ data.direction = direction;
+ pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED], &data);
+}
+
int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause) {
pa_sink *sink;
pa_source *source;
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
index 30bfc0e..79966f3 100644
--- a/src/pulsecore/card.h
+++ b/src/pulsecore/card.h
@@ -79,6 +79,8 @@ struct pa_card {
pa_card_profile *active_profile;
pa_hashmap *ports;
+ pa_device_port *preferred_input_port;
+ pa_device_port *preferred_output_port;
bool save_profile:1;
@@ -98,12 +100,19 @@ typedef struct pa_card_new_data {
char *active_profile;
pa_hashmap *ports;
+ pa_device_port *preferred_input_port;
+ pa_device_port *preferred_output_port;
bool namereg_fail:1;
bool save_profile:1;
} pa_card_new_data;
+typedef struct {
+ pa_card *card;
+ pa_direction_t direction;
+} pa_card_preferred_port_changed_hook_data;
+
pa_card_profile *pa_card_profile_new(const char *name, const char *description, size_t extra);
void pa_card_profile_free(pa_card_profile *c);
@@ -113,6 +122,7 @@ void pa_card_profile_set_available(pa_card_profile *c, pa_available_t available)
pa_card_new_data *pa_card_new_data_init(pa_card_new_data *data);
void pa_card_new_data_set_name(pa_card_new_data *data, const char *name);
void pa_card_new_data_set_profile(pa_card_new_data *data, const char *profile);
+void pa_card_new_data_set_preferred_port(pa_card_new_data *data, pa_direction_t direction, pa_device_port *port);
void pa_card_new_data_done(pa_card_new_data *data);
pa_card *pa_card_new(pa_core *c, pa_card_new_data *data);
@@ -122,6 +132,8 @@ void pa_card_add_profile(pa_card *c, pa_card_profile *profile);
int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save);
+void pa_card_set_preferred_port(pa_card *c, pa_direction_t direction, pa_device_port *port);
+
int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause);
#endif
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 1a3c490..69ab4d0 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -120,6 +120,7 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_CARD_NEW,
PA_CORE_HOOK_CARD_PUT,
PA_CORE_HOOK_CARD_UNLINK,
+ PA_CORE_HOOK_CARD_PREFERRED_PORT_CHANGED,
PA_CORE_HOOK_CARD_PROFILE_CHANGED,
PA_CORE_HOOK_CARD_PROFILE_ADDED,
PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED,
More information about the pulseaudio-commits
mailing list