[pulseaudio-discuss] [PATCH v2 01/10] Add PA_CORE_HOOK_CARD_SET_PROFILE

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Mon Dec 9 10:31:38 PST 2013


This hook allows router modules to "intercept" profile change
requests. A router might want, for example, to move streams elsewhere
when the current sink or source disappears due to a profile switch.
For more explanation, see the documentation that I added to core.h for
this hook.
---
 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                            | 18 +++++++++++++-
 src/pulsecore/card.h                            | 11 ++++++++-
 src/pulsecore/cli-command.c                     |  2 +-
 src/pulsecore/core.h                            | 31 +++++++++++++++++++++++++
 src/pulsecore/protocol-native.c                 |  2 +-
 10 files changed, 68 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 6e1f77a..e930a43 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -250,7 +250,7 @@ void pa_card_add_profile(pa_card *c, pa_card_profile *profile) {
     pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_PROFILE_ADDED], 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 r;
 
     pa_assert(c);
@@ -267,6 +267,22 @@ int pa_card_set_profile(pa_card *c, pa_card_profile *profile, bool save) {
         return 0;
     }
 
+    /* See the documentation of PA_CORE_HOOK_CARD_SET_PROFILE to understand
+     * what this is all about. */
+    if (!bypass_router) {
+        pa_card_set_profile_hook_data data = {
+            .profile = profile,
+            .save = save,
+            .ret = 0,
+            .ret_valid = false
+        };
+
+        pa_hook_fire(&c->core->hooks[PA_CORE_HOOK_CARD_SET_PROFILE], &data);
+
+        if (data.ret_valid)
+            return data.ret;
+    }
+
     if ((r = c->set_profile(c, profile)) < 0)
         return r;
 
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
index 5318150..7d59f59 100644
--- a/src/pulsecore/card.h
+++ b/src/pulsecore/card.h
@@ -99,6 +99,15 @@ typedef struct pa_card_new_data {
     bool save_profile:1;
 } pa_card_new_data;
 
+/* See the documentation of PA_CORE_HOOK_CARD_SET_PROFILE to understand this
+ * struct. */
+typedef struct {
+    pa_card_profile *profile;
+    bool save;
+    int ret;
+    bool ret_valid;
+} pa_card_set_profile_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);
 
@@ -115,7 +124,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/core.h b/src/pulsecore/core.h
index 8b4bf05..f8863ae 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -115,6 +115,37 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_CARD_NEW,
     PA_CORE_HOOK_CARD_PUT,
     PA_CORE_HOOK_CARD_UNLINK,
+
+    /* Fired when pa_card_set_profile() is called with bypass_router=false.
+     * Router modules can use this to intercept card profile switch requests.
+     * Call data: pa_card_set_profile_hook_data.
+     *
+     * What does "intercepting profile switch requests" mean? Router modules
+     * may want to control whether to accept the profile switch, or they may
+     * want to do something before and after the switch.
+     *
+     * The ret_valid field of pa_card_set_profile_hook_data controls an
+     * important aspect of pa_card_set_profile(): if ret_valid is true after
+     * the hook returns, it is assumed that a router module took care of the
+     * profile switch, and pa_card_set_profile() will just return the value of
+     * the ret field and not continue executing the profile switch.
+     *
+     * Denying a profile switch request can be done by setting the ret field
+     * to an appropriate negative error code and the ret_valid field to true.
+     *
+     * Doing something before and after a profile switch can be achieved by
+     * first doing the "before" thing in the hook callback, then calling
+     * pa_card_set_profile() with bypass_router=true (so that the hook won't
+     * be fired again), and then doing the "after" thing. ret_valid must be
+     * set to true, because the router module already executed the profile
+     * switch. In this case ret should probably be the return value of the
+     * "inner" pa_card_set_profile() call.
+     *
+     * The hook callback can access the profile and save parameters of the
+     * pa_card_set_profile() call via the provile and save fields of
+     * pa_card_set_profile_hook_data. */
+    PA_CORE_HOOK_CARD_SET_PROFILE,
+
     PA_CORE_HOOK_CARD_PROFILE_CHANGED,
     PA_CORE_HOOK_CARD_PROFILE_ADDED,
     PA_CORE_HOOK_CARD_PROFILE_AVAILABLE_CHANGED,
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;
     }
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list