[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