[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