summaryrefslogtreecommitdiff
path: root/src/modules/alsa/module-alsa-card.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/alsa/module-alsa-card.c')
-rw-r--r--src/modules/alsa/module-alsa-card.c79
1 files changed, 74 insertions, 5 deletions
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index 08e655e..0fe8893 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -104,6 +104,15 @@ static const char* const valid_modargs[] = {
#define DEFAULT_DEVICE_ID "0"
+#define PULSE_MODARGS "PULSE_MODARGS"
+
+/* dynamic profile priority bonus, for all alsa profiles, the original priority
+ needs to be less than 0x7fff (32767), then could apply the rule of priority
+ bonus. So far there are 2 kinds of alsa profiles, one is from alsa ucm, the
+ other is from mixer profile-sets, their priorities are all far less than 0x7fff
+*/
+#define PROFILE_PRIO_BONUS 0x8000
+
struct userdata {
pa_core *core;
pa_module *module;
@@ -459,9 +468,19 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
* as available (well, "unknown" to be precise, but there's little
* practical difference).
*
- * When all output ports are unavailable, we know that all sinks are
- * unavailable, and therefore the profile is marked unavailable as well.
- * The same applies to input ports as well, of course.
+ * A profile will be marked unavailable:
+ * only contains output ports and all ports are unavailable
+ * only contains input ports and all ports are unavailable
+ * contains both input and output ports and all ports are unavailable
+ *
+ * A profile will be awarded priority bonus:
+ * only contains output ports and at least one port is available
+ * only contains input ports and at least one port is available
+ * contains both output and input ports and at least one output port
+ * and one input port are available
+ *
+ * The rest profiles will not be marked unavailable and will not be
+ * awarded priority bonus
*
* If there are no output ports at all, but the profile contains at least
* one sink, then the output is considered to be available. */
@@ -476,6 +495,7 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
bool found_available_output_port = false;
pa_available_t available = PA_AVAILABLE_UNKNOWN;
+ profile->priority &= ~PROFILE_PRIO_BONUS;
PA_HASHMAP_FOREACH(port, u->card->ports, state2) {
if (!pa_hashmap_get(port->profiles, profile->name))
continue;
@@ -493,8 +513,15 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) {
}
}
- if ((has_input_port && !found_available_input_port) || (has_output_port && !found_available_output_port))
- available = PA_AVAILABLE_NO;
+ if ((has_input_port && found_available_input_port && !has_output_port) ||
+ (has_output_port && found_available_output_port && !has_input_port) ||
+ (has_input_port && found_available_input_port && has_output_port && found_available_output_port))
+ profile->priority |= PROFILE_PRIO_BONUS;
+
+ if ((has_input_port && !found_available_input_port && has_output_port && !found_available_output_port) ||
+ (has_input_port && !found_available_input_port && !has_output_port) ||
+ (has_output_port && !found_available_output_port && !has_input_port))
+ available = PA_AVAILABLE_NO;
/* We want to update the active profile's status last, so logic that
* may change the active profile based on profile availability status
@@ -822,6 +849,7 @@ int pa__init(pa_module *m) {
const char *description;
const char *profile_str = NULL;
char *fn = NULL;
+ char *udev_args = NULL;
bool namereg_fail = false;
int err = -PA_MODULE_ERR_UNSPECIFIED, rval;
@@ -851,6 +879,47 @@ int pa__init(pa_module *m) {
goto fail;
}
+#ifdef HAVE_UDEV
+ udev_args = pa_udev_get_property(u->alsa_card_index, PULSE_MODARGS);
+#endif
+
+ if (udev_args) {
+ bool udev_modargs_success = true;
+ pa_modargs *temp_ma = pa_modargs_new(udev_args, valid_modargs);
+
+ if (temp_ma) {
+ /* do not try to replace device_id */
+
+ if (pa_modargs_remove_key(temp_ma, "device_id") == 0) {
+ pa_log_warn("Unexpected 'device_id' module argument override ignored from udev " PULSE_MODARGS "='%s'", udev_args);
+ }
+
+ /* Implement modargs override by copying original module arguments
+ * over udev entry arguments ignoring duplicates. */
+
+ if (pa_modargs_merge_missing(temp_ma, u->modargs, valid_modargs) == 0) {
+ /* swap module arguments */
+ pa_modargs *old_ma = u->modargs;
+ u->modargs = temp_ma;
+ temp_ma = old_ma;
+
+ pa_log_info("Applied module arguments override from udev " PULSE_MODARGS "='%s'", udev_args);
+ } else {
+ pa_log("Failed to apply module arguments override from udev " PULSE_MODARGS "='%s'", udev_args);
+ udev_modargs_success = false;
+ }
+
+ pa_modargs_free(temp_ma);
+ } else {
+ pa_log("Failed to parse module arguments from udev " PULSE_MODARGS "='%s'", udev_args);
+ udev_modargs_success = false;
+ }
+ pa_xfree(udev_args);
+
+ if (!udev_modargs_success)
+ goto fail;
+ }
+
if (pa_modargs_get_value_boolean(u->modargs, "ignore_dB", &ignore_dB) < 0) {
pa_log("Failed to parse ignore_dB argument.");
goto fail;