From: Mikel Astiz <mikel.astiz@xxxxxxxxxxxx> Add support for hfgw card profile in module-bluetooth-policy, just like a2dp_source is handled. In this case also the sink needs to be connected using module-loopback. --- src/modules/bluetooth/module-bluetooth-policy.c | 56 ++++++++++++++++++++++- 1 files changed, 55 insertions(+), 1 deletions(-) diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c index 0d66eb0..03beeb2 100644 --- a/src/modules/bluetooth/module-bluetooth-policy.c +++ b/src/modules/bluetooth/module-bluetooth-policy.c @@ -40,16 +40,20 @@ PA_MODULE_DESCRIPTION("When a bluetooth sink or source is added, load module-loo PA_MODULE_VERSION(PACKAGE_VERSION); PA_MODULE_LOAD_ONCE(TRUE); PA_MODULE_USAGE( - "a2dp_source=<Handle a2dp_source card profile (sink role)?>"); + "a2dp_source=<Handle a2dp_source card profile (sink role)?> " + "hfgw=<Handle hfgw card profile (headset role)?>"); static const char* const valid_modargs[] = { "a2dp_source", + "hfgw", NULL }; struct userdata { bool enable_a2dp_source; + bool enable_hfgw; pa_hook_slot *source_put_slot; + pa_hook_slot *sink_put_slot; }; /* When a source is created, loopback it to default sink */ @@ -76,6 +80,8 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, if (u->enable_a2dp_source && pa_streq(s, "a2dp_source")) /* A2DP profile (we're doing sink role) */ role = "music"; + else if (u->enable_hfgw && pa_streq(s, "hfgw")) /* HFP profile (we're doing headset role) */ + role = "phone"; else { pa_log_debug("Profile %s cannot be selected for loopback", s); return PA_HOOK_OK; @@ -89,6 +95,43 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, return PA_HOOK_OK; } +/* When a sink is created, loopback it to default source */ +static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void *userdata) { + struct userdata *u = userdata; + const char *s; + const char *role; + char *args; + + pa_assert(c); + pa_assert(sink); + + /* Only consider bluetooth sinks and sources */ + s = pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_BUS); + if (!s) + return PA_HOOK_OK; + + if (!pa_streq(s, "bluetooth")) + return PA_HOOK_OK; + + s = pa_proplist_gets(sink->proplist, "bluetooth.protocol"); + if (!s) + return PA_HOOK_OK; + + if (u->enable_hfgw && pa_streq(s, "hfgw")) /* HFP profile (we're doing headset role) */ + role = "phone"; + else { + pa_log_debug("Profile %s cannot be selected for loopback", s); + return PA_HOOK_OK; + } + + /* Load module-loopback */ + args = pa_sprintf_malloc("sink=\"%s\" sink_dont_move=\"true\" source_output_properties=\"media.role=%s\"", sink->name, role); + (void) pa_module_load(c, "module-loopback", args); + pa_xfree(args); + + return PA_HOOK_OK; +} + int pa__init(pa_module *m) { pa_modargs *ma; struct userdata *u; @@ -108,8 +151,16 @@ int pa__init(pa_module *m) { goto fail; } + u->enable_hfgw = TRUE; + if (pa_modargs_get_value_boolean(ma, "hfgw", &u->enable_hfgw) < 0) { + pa_log("Failed to parse hfgw argument."); + goto fail; + } + u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) source_put_hook_callback, u); + u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_put_hook_callback, u); + pa_modargs_free(ma); return 0; @@ -129,5 +180,8 @@ void pa__done(pa_module *m) { if (u->source_put_slot) pa_hook_slot_free(u->source_put_slot); + if (u->sink_put_slot) + pa_hook_slot_free(u->sink_put_slot); + pa_xfree(u); } -- 1.7.7.6