[pulseaudio-discuss] [PATCH 02/11] Allow router modules to intercept profile switch requests

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Sat Nov 23 21:57:59 PST 2013


A router might want, for example, to move streams elsewhere when the
current sink or source disappears due to a profile switch.
---
 src/modules/bluetooth/module-bluetooth-device.c |  8 ++++----
 src/modules/bluetooth/module-bluetooth-policy.c |  2 +-
 src/modules/dbus/iface-card.c                   |  2 +-
 src/modules/module-card-restore.c               |  2 +-
 src/modules/module-switch-on-port-available.c   |  2 +-
 src/pulsecore/card.c                            | 13 ++++++++++++-
 src/pulsecore/card.h                            |  2 +-
 src/pulsecore/cli-command.c                     |  2 +-
 src/pulsecore/protocol-native.c                 |  2 +-
 src/pulsecore/router.c                          | 11 +++++++++++
 src/pulsecore/router.h                          | 13 +++++++++++++
 11 files changed, 47 insertions(+), 12 deletions(-)

diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 34745fd..5562f6d 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -537,7 +537,7 @@ static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t o
 
             pa_log_debug("Switching the profile to off due to IO thread failure.");
 
-            pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
+            pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false, false) >= 0);
             break;
         }
     }
@@ -1809,7 +1809,7 @@ static pa_hook_result_t transport_state_changed_cb(pa_bluetooth_discovery *y, pa
     pa_assert(u);
 
     if (t == u->transport && t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED)
-        pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
+        pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false, false) >= 0);
 
     if (t->device == u->device)
         handle_transport_state_change(u, t);
@@ -2054,7 +2054,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
 off:
     stop_thread(u);
 
-    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
+    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false, false) >= 0);
 
     return -PA_ERR_IO;
 }
@@ -2561,7 +2561,7 @@ int pa__init(pa_module *m) {
 off:
     stop_thread(u);
 
-    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false) >= 0);
+    pa_assert_se(pa_card_set_profile(u->card, pa_hashmap_get(u->card->profiles, "off"), false, false) >= 0);
 
     return 0;
 
diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c
index a5e9985..a7733e0 100644
--- a/src/modules/bluetooth/module-bluetooth-policy.c
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
@@ -195,7 +195,7 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof
 
     pa_log_debug("Setting card '%s' to profile '%s'", card->name, selected_profile->name);
 
-    if (pa_card_set_profile(card, selected_profile, false) != 0)
+    if (pa_card_set_profile(card, selected_profile, false, false) != 0)
         pa_log_warn("Could not set profile '%s'", selected_profile->name);
 
     return PA_HOOK_OK;
diff --git a/src/modules/dbus/iface-card.c b/src/modules/dbus/iface-card.c
index b77a5e4..d4b080b 100644
--- a/src/modules/dbus/iface-card.c
+++ b/src/modules/dbus/iface-card.c
@@ -336,7 +336,7 @@ static void handle_set_active_profile(DBusConnection *conn, DBusMessage *msg, DB
         return;
     }
 
-    if ((r = pa_card_set_profile(c->card, pa_dbusiface_card_profile_get_profile(new_active), true)) < 0) {
+    if ((r = pa_card_set_profile(c->card, pa_dbusiface_card_profile_get_profile(new_active), true, false)) < 0) {
         pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
                            "Internal error in PulseAudio: pa_card_set_profile() failed with error code %i.", r);
         return;
diff --git a/src/modules/module-card-restore.c b/src/modules/module-card-restore.c
index 3134067..cc55008 100644
--- a/src/modules/module-card-restore.c
+++ b/src/modules/module-card-restore.c
@@ -413,7 +413,7 @@ static pa_hook_result_t card_profile_added_callback(pa_core *c, pa_card_profile
         return PA_HOOK_OK;
 
     if (pa_safe_streq(entry->profile, profile->name)) {
-        if (pa_card_set_profile(profile->card, profile, true) >= 0)
+        if (pa_card_set_profile(profile->card, profile, true, false) >= 0)
             pa_log_info("Restored profile '%s' for card %s.", profile->name, profile->card->name);
     }
 
diff --git a/src/modules/module-switch-on-port-available.c b/src/modules/module-switch-on-port-available.c
index 2c7ad17..2ba5397 100644
--- a/src/modules/module-switch-on-port-available.c
+++ b/src/modules/module-switch-on-port-available.c
@@ -121,7 +121,7 @@ static int try_to_switch_profile(pa_device_port *port) {
         return -1;
     }
 
-    if (pa_card_set_profile(port->card, best_profile, false) != 0) {
+    if (pa_card_set_profile(port->card, best_profile, false, false) != 0) {
         pa_log_debug("Could not set profile %s", best_profile->name);
         return -1;
     }
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index 8ca6e54..e61f6df 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -32,6 +32,7 @@
 
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
+#include <pulsecore/router.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/device-port.h>
@@ -250,7 +251,7 @@ void pa_card_free(pa_card *c) {
     pa_xfree(c);
 }
 
-int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) {
+int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save, bool bypass_router) {
     int r;
 
     pa_assert(c);
@@ -267,6 +268,16 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) {
         return 0;
     }
 
+    if (!bypass_router && c->core->router)
+        /* pa_router_set_card_profile() will probably call
+         * pa_card_set_profile() with bypass_router=true (to avoid an infinite
+         * loop), so there will be a bit of recursion going on. The purpose of
+         * this is to allow the router to be in full control of all profile
+         * switching in the system. The router can do something before and/or
+         * after the profile switch, or even reject the profile switch request
+         * altogether. */
+        return pa_router_set_card_profile(c->core->router, c, profile, save);
+
     if ((r = c->set_profile(c, profile)) < 0)
         return r;
 
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
index 5318150..e2132ee 100644
--- a/src/pulsecore/card.h
+++ b/src/pulsecore/card.h
@@ -115,7 +115,7 @@ void pa_card_free(pa_card *c);
 
 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);
+int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save, bool bypass_router);
 
 int pa_card_suspend(pa_card *c, bool suspend, pa_suspend_cause_t cause);
 
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 44b5d84..d390a74 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1661,7 +1661,7 @@ static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *b
         return -1;
     }
 
-    if (pa_card_set_profile(card, profile, true) < 0) {
+    if (pa_card_set_profile(card, profile, true, false) < 0) {
         pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
         return -1;
     }
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index e195ba8..dd38cc4 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4736,7 +4736,7 @@ static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_
 
     CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY);
 
-    if ((ret = pa_card_set_profile(card, profile, true)) < 0) {
+    if ((ret = pa_card_set_profile(card, profile, true, false)) < 0) {
         pa_pstream_send_error(c->pstream, tag, -ret);
         return;
     }
diff --git a/src/pulsecore/router.c b/src/pulsecore/router.c
index 5d51f66..509aef5 100644
--- a/src/pulsecore/router.c
+++ b/src/pulsecore/router.c
@@ -89,3 +89,14 @@ void pa_router_remove_node(pa_router *router, pa_node *node) {
     if (router->remove_node)
         router->remove_node(router, node);
 }
+
+int pa_router_set_card_profile(pa_router *router, pa_card *card, pa_card_profile *profile, bool save) {
+    pa_assert(router);
+    pa_assert(card);
+    pa_assert(profile);
+
+    if (router->set_card_profile)
+        return router->set_card_profile(router, card, profile, save);
+    else
+        return pa_card_set_profile(card, profile, save, true);
+}
diff --git a/src/pulsecore/router.h b/src/pulsecore/router.h
index e8e7546..e27bb4a 100644
--- a/src/pulsecore/router.h
+++ b/src/pulsecore/router.h
@@ -35,6 +35,17 @@ struct pa_router {
 
     /* Called when a node goes away. May be NULL. */
     void (*remove_node)(pa_router *router, pa_node *node);
+
+    /* Called when someone requests a card profile change. May be NULL, in
+     * which case the profile change will happen normally. If this callback is
+     * set, then the implementation is responsible for calling
+     * pa_card_set_profile() (with bypass_router=true to avoid an infinite
+     * loop), if it wants any profile change to happen.
+     *
+     * If the implementation wants to report failure, then the return value
+     * must be a negative error code (meaning not just simple -1, but some of
+     * the PA_ERR_* constants). */
+    int (*set_card_profile)(pa_router *router, pa_card *card, pa_card_profile *profile, bool save);
 };
 
 pa_router *pa_router_new(pa_core *core);
@@ -44,4 +55,6 @@ void pa_router_free(pa_router *router);
 void pa_router_add_node(pa_router *router, pa_node *node);
 void pa_router_remove_node(pa_router *router, pa_node *node);
 
+int pa_router_set_card_profile(pa_router *router, pa_card *card, pa_card_profile *profile, bool save);
+
 #endif
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list