[pulseaudio-commits] 3 commits - src/daemon src/Makefile.am src/modules

Colin Guthrie colin at kemper.freedesktop.org
Tue Oct 25 05:01:33 PDT 2011


 src/Makefile.am                          |   14 -
 src/daemon/default.pa.in                 |    4 
 src/modules/module-cork-music-on-phone.c |  237 -----------------------
 src/modules/module-role-cork.c           |  312 +++++++++++++++++++++++++++++++
 4 files changed, 321 insertions(+), 246 deletions(-)

New commits:
commit a3678d241b9acc259518225a89eac26ce718f93e
Author: Colin Guthrie <colin at mageia.org>
Date:   Mon Oct 24 23:51:20 2011 +0200

    role-cork: Allow module-role-cork to act globally.
    
    Allow a module argument to specify that we should act globally
    rather than just within a given sink.
    
    The default value is to not opporate globally thus retaining the
    current behaviour.

diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
index 0802a11..a4270a4 100644
--- a/src/modules/module-role-cork.c
+++ b/src/modules/module-role-cork.c
@@ -41,11 +41,13 @@ PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(TRUE);
 PA_MODULE_USAGE(
         "trigger_roles=<Comma separated list of roles which will trigger a cork> "
-        "cork_roles=<Comma separated list of roles which will be corked>");
+        "cork_roles=<Comma separated list of roles which will be corked> "
+        "global=<Should we operate globally or only inside the same device?>");
 
 static const char* const valid_modargs[] = {
     "trigger_roles",
     "cork_roles",
+    "global",
     NULL
 };
 
@@ -54,6 +56,7 @@ struct userdata {
     pa_hashmap *cork_state;
     pa_idxset *trigger_roles;
     pa_idxset *cork_roles;
+    pa_bool_t global:1;
     pa_hook_slot
         *sink_input_put_slot,
         *sink_input_unlink_slot,
@@ -89,7 +92,7 @@ static pa_bool_t shall_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignor
     return FALSE;
 }
 
-static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
+static inline void apply_cork_to_sink(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
     pa_sink_input *j;
     uint32_t idx, role_idx;
     const char *cork_role;
@@ -139,6 +142,17 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
     }
 }
 
+static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
+    pa_assert(u);
+
+    if (u->global) {
+        uint32_t idx;
+        PA_IDXSET_FOREACH(s, u->core->sinks, idx)
+            apply_cork_to_sink(u, s, ignore, cork);
+    } else
+        apply_cork_to_sink(u, s, ignore, cork);
+}
+
 static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, pa_bool_t create) {
     pa_bool_t cork = FALSE;
     const char *role;
@@ -192,6 +206,7 @@ int pa__init(pa_module *m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
     const char *roles;
+    pa_bool_t global = FALSE;
 
     pa_assert(m);
 
@@ -234,6 +249,12 @@ int pa__init(pa_module *m) {
         pa_idxset_put(u->cork_roles, pa_xstrdup("video"), NULL);
     }
 
+    if (pa_modargs_get_value_boolean(ma, "global", &global) < 0) {
+        pa_log("Invalid boolean parameter: global");
+        goto fail;
+    }
+    u->global = global;
+
     u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
     u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_unlink_cb, u);
     u->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_start_cb, u);

commit 679b7ef895df7c5375de5d5b8776cd6647bf5862
Author: Colin Guthrie <colin at mageia.org>
Date:   Mon Oct 24 23:35:38 2011 +0200

    role-cork: Make module-role-cork more generic.
    
    Operate on a list of 'trigger roles' and 'cork roles'. i.e.
    react to any stream with a role in the trigger list and apply a
    cork to any stream with the a role in the cork list.
    
    The trigger roles default to 'phone' and the cork roles default
    to both 'music' and 'video' thus achieving the same functionality
    as currently when called without any arguments.

diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
index af412cf..0802a11 100644
--- a/src/modules/module-role-cork.c
+++ b/src/modules/module-role-cork.c
@@ -39,14 +39,21 @@ PA_MODULE_AUTHOR("Lennart Poettering");
 PA_MODULE_DESCRIPTION("Mute & cork streams with certain roles while others exist");
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE(
+        "trigger_roles=<Comma separated list of roles which will trigger a cork> "
+        "cork_roles=<Comma separated list of roles which will be corked>");
 
 static const char* const valid_modargs[] = {
+    "trigger_roles",
+    "cork_roles",
     NULL
 };
 
 struct userdata {
     pa_core *core;
     pa_hashmap *cork_state;
+    pa_idxset *trigger_roles;
+    pa_idxset *cork_roles;
     pa_hook_slot
         *sink_input_put_slot,
         *sink_input_unlink_slot,
@@ -54,9 +61,12 @@ struct userdata {
         *sink_input_move_finish_slot;
 };
 
-static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
+static pa_bool_t shall_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore) {
     pa_sink_input *j;
-    uint32_t idx;
+    uint32_t idx, role_idx;
+    const char *trigger_role;
+
+    pa_assert(u);
     pa_sink_assert_ref(s);
 
     for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
@@ -68,9 +78,11 @@ static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
         if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
             continue;
 
-        if (pa_streq(role, "phone")) {
-            pa_log_debug("Found a phone stream that will trigger the auto-cork.");
-            return TRUE;
+        PA_IDXSET_FOREACH(trigger_role, u->trigger_roles, role_idx) {
+            if (pa_streq(role, trigger_role)) {
+                pa_log_debug("Found a '%s' stream that will trigger the auto-cork.", trigger_role);
+                return TRUE;
+            }
         }
     }
 
@@ -79,7 +91,9 @@ static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
 
 static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
     pa_sink_input *j;
-    uint32_t idx;
+    uint32_t idx, role_idx;
+    const char *cork_role;
+    pa_bool_t trigger = FALSE;
 
     pa_assert(u);
     pa_sink_assert_ref(s);
@@ -94,8 +108,11 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
         if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
             continue;
 
-        if (!pa_streq(role, "video") &&
-            !pa_streq(role, "music"))
+        PA_IDXSET_FOREACH(cork_role, u->cork_roles, role_idx) {
+            if ((trigger = pa_streq(role, cork_role)))
+                break;
+        }
+        if (!trigger)
             continue;
 
         corked = (pa_sink_input_get_state(j) == PA_SINK_INPUT_CORKED);
@@ -103,7 +120,7 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
         corked_here = !!pa_hashmap_get(u->cork_state, j);
 
         if (cork && !corked && !muted) {
-            pa_log_debug("Found a music/video stream that should be corked/muted.");
+            pa_log_debug("Found a '%s' stream that should be corked/muted.", cork_role);
             if (!corked_here)
                 pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
             pa_sink_input_set_mute(j, TRUE, FALSE);
@@ -112,7 +129,7 @@ static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa
             pa_hashmap_remove(u->cork_state, j);
 
             if (corked_here && (corked || muted)) {
-                pa_log_debug("Found a music/video stream that should be uncorked/unmuted.");
+                pa_log_debug("Found a '%s' stream that should be uncorked/unmuted.", cork_role);
                 if (muted)
                     pa_sink_input_set_mute(j, FALSE, FALSE);
                 if (corked)
@@ -135,15 +152,10 @@ static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, pa_bool_t
     if (!(role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
         return PA_HOOK_OK;
 
-    if (!pa_streq(role, "phone") &&
-        !pa_streq(role, "music") &&
-        !pa_streq(role, "video"))
-        return PA_HOOK_OK;
-
     if (!i->sink)
         return PA_HOOK_OK;
 
-    cork = shall_cork(i->sink, create ? NULL : i);
+    cork = shall_cork(u, i->sink, create ? NULL : i);
     apply_cork(u, i->sink, create ? NULL : i, cork);
 
     return PA_HOOK_OK;
@@ -179,6 +191,7 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *
 int pa__init(pa_module *m) {
     pa_modargs *ma = NULL;
     struct userdata *u;
+    const char *roles;
 
     pa_assert(m);
 
@@ -192,6 +205,35 @@ int pa__init(pa_module *m) {
     u->core = m->core;
     u->cork_state = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
+    u->trigger_roles = pa_idxset_new(NULL, NULL);
+    roles = pa_modargs_get_value(ma, "trigger_roles", NULL);
+    if (roles) {
+        const char *split_state = NULL;
+        char *n = NULL;
+        while ((n = pa_split(roles, ",", &split_state)))
+            if (n[0] != '\0')
+                pa_idxset_put(u->trigger_roles, pa_xstrdup(n), NULL);
+    }
+    if (pa_idxset_isempty(u->trigger_roles)) {
+        pa_log_debug("Using role 'phone' as trigger role.");
+        pa_idxset_put(u->trigger_roles, pa_xstrdup("phone"), NULL);
+    }
+
+    u->cork_roles = pa_idxset_new(NULL, NULL);
+    roles = pa_modargs_get_value(ma, "cork_roles", NULL);
+    if (roles) {
+        const char *split_state = NULL;
+        char *n = NULL;
+        while ((n = pa_split(roles, ",", &split_state)))
+            if (n[0] != '\0')
+                pa_idxset_put(u->cork_roles, pa_xstrdup(n), NULL);
+    }
+    if (pa_idxset_isempty(u->cork_roles)) {
+        pa_log_debug("Using roles 'music' and 'video' as cork roles.");
+        pa_idxset_put(u->cork_roles, pa_xstrdup("music"), NULL);
+        pa_idxset_put(u->cork_roles, pa_xstrdup("video"), NULL);
+    }
+
     u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
     u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_unlink_cb, u);
     u->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_start_cb, u);
@@ -214,12 +256,24 @@ fail:
 
 void pa__done(pa_module *m) {
     struct userdata* u;
+    char *role;
 
     pa_assert(m);
 
     if (!(u = m->userdata))
         return;
 
+    if (u->trigger_roles) {
+        while ((role = pa_idxset_steal_first(u->trigger_roles, NULL)))
+            pa_xfree(role);
+        pa_idxset_free(u->trigger_roles, NULL, NULL);
+    }
+    if (u->trigger_roles) {
+        while ((role = pa_idxset_steal_first(u->cork_roles, NULL)))
+            pa_xfree(role);
+        pa_idxset_free(u->cork_roles, NULL, NULL);
+    }
+
     if (u->sink_input_put_slot)
         pa_hook_slot_free(u->sink_input_put_slot);
     if (u->sink_input_unlink_slot)

commit 3c5cc345472302b9511c19244b3eceb4a3674d8c
Author: Colin Guthrie <colin at mageia.org>
Date:   Mon Oct 24 22:55:45 2011 +0200

    role-cork: Rename module-cork-music-on-phone to module-role-cork.
    
    This module will be extended to be a bit more generic so the
    old name will soon be obsolete.

diff --git a/src/Makefile.am b/src/Makefile.am
index ac1d227..cc3e13b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1006,7 +1006,7 @@ modlibexec_LTLIBRARIES += \
 		module-tunnel-source.la \
 		module-position-event-sounds.la \
 		module-augment-properties.la \
-		module-cork-music-on-phone.la \
+		module-role-cork.la \
 		module-loopback.la \
 		module-virtual-sink.la \
 		module-virtual-source.la \
@@ -1298,7 +1298,7 @@ SYMDEF_FILES = \
 		module-gconf-symdef.h \
 		module-position-event-sounds-symdef.h \
 		module-augment-properties-symdef.h \
-		module-cork-music-on-phone-symdef.h \
+		module-role-cork-symdef.h \
 		module-console-kit-symdef.h \
 		module-dbus-protocol-symdef.h \
 		module-loopback-symdef.h \
@@ -1670,11 +1670,11 @@ module_augment_properties_la_LIBADD = $(MODULE_LIBADD)
 #module_augment_properties_la_CFLAGS = $(AM_CFLAGS) -DDESKTOPFILEDIR=\"$(datadir)/applications\"
 module_augment_properties_la_CFLAGS = $(AM_CFLAGS) -DDESKTOPFILEDIR=\"/usr/share/applications\"
 
-# Cork music streams while a phone stream is active
-module_cork_music_on_phone_la_SOURCES = modules/module-cork-music-on-phone.c
-module_cork_music_on_phone_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_cork_music_on_phone_la_LIBADD = $(MODULE_LIBADD)
-module_cork_music_on_phone_la_CFLAGS = $(AM_CFLAGS)
+# Cork certain streams while others are active (e.g. cork music when phone streams appear)
+module_role_cork_la_SOURCES = modules/module-role-cork.c
+module_role_cork_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_role_cork_la_LIBADD = $(MODULE_LIBADD)
+module_role_cork_la_CFLAGS = $(AM_CFLAGS)
 
 # Device description restore module
 module_device_manager_la_SOURCES = modules/module-device-manager.c
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index c6ec29c..f2f22e8 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -154,8 +154,8 @@ load-module module-console-kit
 ### Enable positioned event sounds
 load-module module-position-event-sounds
 
-### Cork music streams when a phone stream is active
-load-module module-cork-music-on-phone
+### Cork music/video streams when a phone stream is active
+load-module module-role-cork
 
 ### Modules to allow autoloading of filters (such as echo cancellation)
 ### on demand. module-filter-heuristics tries to determine what filters
diff --git a/src/modules/module-cork-music-on-phone.c b/src/modules/module-cork-music-on-phone.c
deleted file mode 100644
index 4c9c178..0000000
--- a/src/modules/module-cork-music-on-phone.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/***
-  This file is part of PulseAudio.
-
-  Copyright 2009 Lennart Poettering
-
-  PulseAudio is free software; you can redistribute it and/or modify
-  it under the terms of the GNU Lesser General Public License as published
-  by the Free Software Foundation; either version 2.1 of the License,
-  or (at your option) any later version.
-
-  PulseAudio is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public License
-  along with PulseAudio; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-  USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <pulse/xmalloc.h>
-
-#include <pulsecore/macro.h>
-#include <pulsecore/hashmap.h>
-#include <pulsecore/hook-list.h>
-#include <pulsecore/core.h>
-#include <pulsecore/core-util.h>
-#include <pulsecore/sink-input.h>
-#include <pulsecore/modargs.h>
-
-#include "module-cork-music-on-phone-symdef.h"
-
-PA_MODULE_AUTHOR("Lennart Poettering");
-PA_MODULE_DESCRIPTION("Mute or cork music while a phone stream exists");
-PA_MODULE_VERSION(PACKAGE_VERSION);
-PA_MODULE_LOAD_ONCE(TRUE);
-
-static const char* const valid_modargs[] = {
-    NULL
-};
-
-struct userdata {
-    pa_core *core;
-    pa_hashmap *cork_state;
-    pa_hook_slot
-        *sink_input_put_slot,
-        *sink_input_unlink_slot,
-        *sink_input_move_start_slot,
-        *sink_input_move_finish_slot;
-};
-
-static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
-    pa_sink_input *j;
-    uint32_t idx;
-    pa_sink_assert_ref(s);
-
-    for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
-        const char *role;
-
-        if (j == ignore)
-            continue;
-
-        if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
-            continue;
-
-        if (pa_streq(role, "phone")) {
-            pa_log_debug("Found a phone stream that will trigger the auto-cork.");
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
-    pa_sink_input *j;
-    uint32_t idx;
-
-    pa_assert(u);
-    pa_sink_assert_ref(s);
-
-    for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
-        pa_bool_t corked, muted, corked_here;
-        const char *role;
-
-        if (j == ignore)
-            continue;
-
-        if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
-            continue;
-
-        if (!pa_streq(role, "video") &&
-            !pa_streq(role, "music"))
-            continue;
-
-        corked = (pa_sink_input_get_state(j) == PA_SINK_INPUT_CORKED);
-        muted = pa_sink_input_get_mute(j);
-        corked_here = !!pa_hashmap_get(u->cork_state, j);
-
-        if (cork && !corked && !muted) {
-            pa_log_debug("Found a music/video stream that should be corked/muted.");
-            if (!corked_here)
-                pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
-            pa_sink_input_set_mute(j, TRUE, FALSE);
-            pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_CORK, NULL);
-        } else if (!cork) {
-            pa_hashmap_remove(u->cork_state, j);
-
-            if (corked_here && (corked || muted)) {
-                pa_log_debug("Found a music/video stream that should be uncorked/unmuted.");
-                if (muted)
-                    pa_sink_input_set_mute(j, FALSE, FALSE);
-                if (corked)
-                    pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_UNCORK, NULL);
-            }
-        }
-    }
-}
-
-static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, pa_bool_t create) {
-    pa_bool_t cork = FALSE;
-    const char *role;
-
-    pa_assert(u);
-    pa_sink_input_assert_ref(i);
-
-    if (!create)
-        pa_hashmap_remove(u->cork_state, i);
-
-    if (!(role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
-        return PA_HOOK_OK;
-
-    if (!pa_streq(role, "phone") &&
-        !pa_streq(role, "music") &&
-        !pa_streq(role, "video"))
-        return PA_HOOK_OK;
-
-    if (!i->sink)
-        return PA_HOOK_OK;
-
-    cork = shall_cork(i->sink, create ? NULL : i);
-    apply_cork(u, i->sink, create ? NULL : i, cork);
-
-    return PA_HOOK_OK;
-}
-
-static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-    pa_core_assert_ref(core);
-    pa_sink_input_assert_ref(i);
-
-    return process(u, i, TRUE);
-}
-
-static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-    pa_sink_input_assert_ref(i);
-
-    return process(u, i, FALSE);
-}
-
-static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-    pa_core_assert_ref(core);
-    pa_sink_input_assert_ref(i);
-
-    return process(u, i, FALSE);
-}
-
-static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
-    pa_core_assert_ref(core);
-    pa_sink_input_assert_ref(i);
-
-    return process(u, i, TRUE);
-}
-
-int pa__init(pa_module *m) {
-    pa_modargs *ma = NULL;
-    struct userdata *u;
-
-    pa_assert(m);
-
-    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
-        pa_log("Failed to parse module arguments");
-        goto fail;
-    }
-
-    m->userdata = u = pa_xnew(struct userdata, 1);
-
-    u->core = m->core;
-    u->cork_state = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
-
-    u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
-    u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_unlink_cb, u);
-    u->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_start_cb, u);
-    u->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_finish_cb, u);
-
-    pa_modargs_free(ma);
-
-    return 0;
-
-fail:
-    pa__done(m);
-
-    if (ma)
-        pa_modargs_free(ma);
-
-    return -1;
-
-
-}
-
-void pa__done(pa_module *m) {
-    struct userdata* u;
-
-    pa_assert(m);
-
-    if (!(u = m->userdata))
-        return;
-
-    if (u->sink_input_put_slot)
-        pa_hook_slot_free(u->sink_input_put_slot);
-    if (u->sink_input_unlink_slot)
-        pa_hook_slot_free(u->sink_input_unlink_slot);
-    if (u->sink_input_move_start_slot)
-        pa_hook_slot_free(u->sink_input_move_start_slot);
-    if (u->sink_input_move_finish_slot)
-        pa_hook_slot_free(u->sink_input_move_finish_slot);
-
-    if (u->cork_state)
-        pa_hashmap_free(u->cork_state, NULL, NULL);
-
-    pa_xfree(u);
-
-}
diff --git a/src/modules/module-role-cork.c b/src/modules/module-role-cork.c
new file mode 100644
index 0000000..af412cf
--- /dev/null
+++ b/src/modules/module-role-cork.c
@@ -0,0 +1,237 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2009 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/macro.h>
+#include <pulsecore/hashmap.h>
+#include <pulsecore/hook-list.h>
+#include <pulsecore/core.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/sink-input.h>
+#include <pulsecore/modargs.h>
+
+#include "module-role-cork-symdef.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("Mute & cork streams with certain roles while others exist");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+
+static const char* const valid_modargs[] = {
+    NULL
+};
+
+struct userdata {
+    pa_core *core;
+    pa_hashmap *cork_state;
+    pa_hook_slot
+        *sink_input_put_slot,
+        *sink_input_unlink_slot,
+        *sink_input_move_start_slot,
+        *sink_input_move_finish_slot;
+};
+
+static pa_bool_t shall_cork(pa_sink *s, pa_sink_input *ignore) {
+    pa_sink_input *j;
+    uint32_t idx;
+    pa_sink_assert_ref(s);
+
+    for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
+        const char *role;
+
+        if (j == ignore)
+            continue;
+
+        if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        if (pa_streq(role, "phone")) {
+            pa_log_debug("Found a phone stream that will trigger the auto-cork.");
+            return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+static void apply_cork(struct userdata *u, pa_sink *s, pa_sink_input *ignore, pa_bool_t cork) {
+    pa_sink_input *j;
+    uint32_t idx;
+
+    pa_assert(u);
+    pa_sink_assert_ref(s);
+
+    for (j = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); j; j = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
+        pa_bool_t corked, muted, corked_here;
+        const char *role;
+
+        if (j == ignore)
+            continue;
+
+        if (!(role = pa_proplist_gets(j->proplist, PA_PROP_MEDIA_ROLE)))
+            continue;
+
+        if (!pa_streq(role, "video") &&
+            !pa_streq(role, "music"))
+            continue;
+
+        corked = (pa_sink_input_get_state(j) == PA_SINK_INPUT_CORKED);
+        muted = pa_sink_input_get_mute(j);
+        corked_here = !!pa_hashmap_get(u->cork_state, j);
+
+        if (cork && !corked && !muted) {
+            pa_log_debug("Found a music/video stream that should be corked/muted.");
+            if (!corked_here)
+                pa_hashmap_put(u->cork_state, j, PA_INT_TO_PTR(1));
+            pa_sink_input_set_mute(j, TRUE, FALSE);
+            pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_CORK, NULL);
+        } else if (!cork) {
+            pa_hashmap_remove(u->cork_state, j);
+
+            if (corked_here && (corked || muted)) {
+                pa_log_debug("Found a music/video stream that should be uncorked/unmuted.");
+                if (muted)
+                    pa_sink_input_set_mute(j, FALSE, FALSE);
+                if (corked)
+                    pa_sink_input_send_event(j, PA_STREAM_EVENT_REQUEST_UNCORK, NULL);
+            }
+        }
+    }
+}
+
+static pa_hook_result_t process(struct userdata *u, pa_sink_input *i, pa_bool_t create) {
+    pa_bool_t cork = FALSE;
+    const char *role;
+
+    pa_assert(u);
+    pa_sink_input_assert_ref(i);
+
+    if (!create)
+        pa_hashmap_remove(u->cork_state, i);
+
+    if (!(role = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_ROLE)))
+        return PA_HOOK_OK;
+
+    if (!pa_streq(role, "phone") &&
+        !pa_streq(role, "music") &&
+        !pa_streq(role, "video"))
+        return PA_HOOK_OK;
+
+    if (!i->sink)
+        return PA_HOOK_OK;
+
+    cork = shall_cork(i->sink, create ? NULL : i);
+    apply_cork(u, i->sink, create ? NULL : i, cork);
+
+    return PA_HOOK_OK;
+}
+
+static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
+    pa_core_assert_ref(core);
+    pa_sink_input_assert_ref(i);
+
+    return process(u, i, TRUE);
+}
+
+static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
+    pa_sink_input_assert_ref(i);
+
+    return process(u, i, FALSE);
+}
+
+static pa_hook_result_t sink_input_move_start_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
+    pa_core_assert_ref(core);
+    pa_sink_input_assert_ref(i);
+
+    return process(u, i, FALSE);
+}
+
+static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
+    pa_core_assert_ref(core);
+    pa_sink_input_assert_ref(i);
+
+    return process(u, i, TRUE);
+}
+
+int pa__init(pa_module *m) {
+    pa_modargs *ma = NULL;
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    m->userdata = u = pa_xnew(struct userdata, 1);
+
+    u->core = m->core;
+    u->cork_state = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
+
+    u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
+    u->sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_unlink_cb, u);
+    u->sink_input_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_start_cb, u);
+    u->sink_input_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_move_finish_cb, u);
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
+    pa__done(m);
+
+    if (ma)
+        pa_modargs_free(ma);
+
+    return -1;
+
+
+}
+
+void pa__done(pa_module *m) {
+    struct userdata* u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        return;
+
+    if (u->sink_input_put_slot)
+        pa_hook_slot_free(u->sink_input_put_slot);
+    if (u->sink_input_unlink_slot)
+        pa_hook_slot_free(u->sink_input_unlink_slot);
+    if (u->sink_input_move_start_slot)
+        pa_hook_slot_free(u->sink_input_move_start_slot);
+    if (u->sink_input_move_finish_slot)
+        pa_hook_slot_free(u->sink_input_move_finish_slot);
+
+    if (u->cork_state)
+        pa_hashmap_free(u->cork_state, NULL, NULL);
+
+    pa_xfree(u);
+
+}



More information about the pulseaudio-commits mailing list