On 21.09.2017 21:27, James Bottomley wrote: > When all headsets supported both HSP and HFP, life was good and we > only needed to implement HSP in the native backend. Unfortunately > some headsets have started supporting HFP only. Unfortuantely, we > can't simply switch to HFP only because that might break older HSP > only headsets meaning we need to support both HSP and HFP separately. > > This patch separates them from a joint profile to being two separate > ones. The older one retains the headset_head_unit name, meaning any > saved parameters will still select this (keeping us backward > compatible). It also introduces a new headset_handsfree. > > For headsets that support both HSP and HFP, the two profiles will > become separately visible and selectable. This will only matter once > we start adding features to HFP that HSP can't support (like wideband > audio). This paragraph is a bit misleading because you can't select the profiles separately. If HFP is available, it will be used. > > Signed-off-by: <James.Bottomley at HansenPartnership.com> > > --- > v5: > > - rename option to enable_native_hfp_hf > - don't call profile_done for HFP_HF unless it was initialised > > v3: > > - Update for PA 11.0 > > v2: > > - fold in review feedback > - add global disable option for not registering HFP > > v3: > > - change parameter to enable_profile_hfp > - update device_supports_profile to be aware of hfp/hsp exclusivity > - change parameter to enable_profile_hfp_hf > --- > src/modules/bluetooth/backend-native.c | 17 ++++++- > src/modules/bluetooth/bluez5-util.c | 31 +++++++++++-- > src/modules/bluetooth/bluez5-util.h | 4 +- > src/modules/bluetooth/module-bluetooth-policy.c | 3 +- > src/modules/bluetooth/module-bluez5-device.c | 60 +++++++++++++++++++++---- > src/modules/bluetooth/module-bluez5-discover.c | 6 ++- > 6 files changed, 106 insertions(+), 15 deletions(-) > > diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c > index f2009bfd..9ec9244b 100644 > --- a/src/modules/bluetooth/backend-native.c > +++ b/src/modules/bluetooth/backend-native.c > @@ -62,6 +62,7 @@ struct transport_data { > #define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" > > #define HSP_AG_PROFILE "/Profile/HSPAGProfile" > +#define HFP_AG_PROFILE "/Profile/HFPAGProfile" > #define HSP_HS_PROFILE "/Profile/HSPHSProfile" > > /* RFCOMM channel for HSP headset role > @@ -512,6 +513,8 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, > p = PA_BLUETOOTH_PROFILE_HSP_HS; > } else if (pa_streq(handler, HSP_HS_PROFILE)) { > p = PA_BLUETOOTH_PROFILE_HFP_AG; > + } else if (pa_streq(handler, HFP_AG_PROFILE)) { > + p = PA_BLUETOOTH_PROFILE_HFP_HF; > } else { > pa_log_error("Invalid handler"); > goto fail; > @@ -589,7 +592,8 @@ static DBusHandlerResult profile_handler(DBusConnection *c, DBusMessage *m, void > > pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); > > - if (!pa_streq(path, HSP_AG_PROFILE) && !pa_streq(path, HSP_HS_PROFILE)) > + if (!pa_streq(path, HSP_AG_PROFILE) && !pa_streq(path, HSP_HS_PROFILE) > + && !pa_streq(path, HFP_AG_PROFILE)) > return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; > > if (dbus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) { > @@ -634,6 +638,10 @@ static void profile_init(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile > object_name = HSP_HS_PROFILE; > uuid = PA_BLUETOOTH_UUID_HSP_HS; > break; > + case PA_BLUETOOTH_PROFILE_HFP_HF: > + object_name = HFP_AG_PROFILE; > + uuid = PA_BLUETOOTH_UUID_HFP_AG; > + break; > default: > pa_assert_not_reached(); > break; > @@ -653,6 +661,9 @@ static void profile_done(pa_bluetooth_backend *b, pa_bluetooth_profile_t profile > case PA_BLUETOOTH_PROFILE_HFP_AG: > dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HSP_HS_PROFILE); > break; > + case PA_BLUETOOTH_PROFILE_HFP_HF: > + dbus_connection_unregister_object_path(pa_dbus_connection_get(b->connection), HFP_AG_PROFILE); > + break; > default: > pa_assert_not_reached(); > break; > @@ -695,6 +706,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d > if (enable_hs_role) > profile_init(backend, PA_BLUETOOTH_PROFILE_HFP_AG); > profile_init(backend, PA_BLUETOOTH_PROFILE_HSP_HS); > + if (pa_bluetooth_discovery_get_enable_native_hfp_hf(y)) > + profile_init(backend, PA_BLUETOOTH_PROFILE_HFP_HF); > > return backend; > } > @@ -707,6 +720,8 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) { > if (backend->enable_hs_role) > profile_done(backend, PA_BLUETOOTH_PROFILE_HFP_AG); > profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS); > + if (pa_bluetooth_discovery_get_enable_native_hfp_hf(backend->discovery)) > + profile_done(backend, PA_BLUETOOTH_PROFILE_HFP_HF); > > pa_dbus_connection_unref(backend->connection); > > diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c > index 4470f2ef..80a025d5 100644 > --- a/src/modules/bluetooth/bluez5-util.c > +++ b/src/modules/bluetooth/bluez5-util.c > @@ -92,6 +92,7 @@ struct pa_bluetooth_discovery { > int headset_backend; > pa_bluetooth_backend *ofono_backend, *native_backend; > PA_LLIST_HEAD(pa_dbus_pending, pending); > + bool enable_native_hfp_hf; > }; > > static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m, > @@ -169,14 +170,27 @@ static const char *transport_state_to_string(pa_bluetooth_transport_state_t stat > } > > static bool device_supports_profile(pa_bluetooth_device *device, pa_bluetooth_profile_t profile) { > + bool show_hfp, show_hsp, enable_native_hfp_hf; > + > + enable_native_hfp_hf = pa_bluetooth_discovery_get_enable_native_hfp_hf(device->discovery); > + > + if (enable_native_hfp_hf) { > + show_hfp = pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF); > + show_hsp = !show_hfp; > + } else { > + show_hfp = false; > + show_hsp = true; > + } You have to consider the case that the ofono backend is used. In that case show_hfp=true; show_hsp=false; What about the AG device roles? If we start distinguishing between HFP and HSP, I think we should do it everywhere. If "headset=native", we only support HSP_AG devices, while with "auto" and "ofono" we support only HFP_AG devices. > + > switch (profile) { > case PA_BLUETOOTH_PROFILE_A2DP_SINK: > return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SINK); > case PA_BLUETOOTH_PROFILE_A2DP_SOURCE: > return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_A2DP_SOURCE); > case PA_BLUETOOTH_PROFILE_HSP_HS: > - return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS) > - || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF); > + return show_hsp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_HS); > + case PA_BLUETOOTH_PROFILE_HFP_HF: > + return show_hfp && !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_HF); > case PA_BLUETOOTH_PROFILE_HFP_AG: > return !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HSP_AG) > || !!pa_hashmap_get(device->uuids, PA_BLUETOOTH_UUID_HFP_AG); > @@ -536,6 +550,14 @@ pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_path(pa_bluetooth_disc > return NULL; > } > > +bool pa_bluetooth_discovery_get_enable_native_hfp_hf(pa_bluetooth_discovery *y) > +{ > + pa_assert(y); > + pa_assert(PA_REFCNT_VALUE(y) > 0); > + > + return y->enable_native_hfp_hf; > +} > + > pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local) { > pa_bluetooth_device *d; > void *state = NULL; > @@ -1306,6 +1328,8 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile) { > return "a2dp_source"; > case PA_BLUETOOTH_PROFILE_HSP_HS: > return "headset_head_unit"; > + case PA_BLUETOOTH_PROFILE_HFP_HF: > + return "headset_handsfree"; > case PA_BLUETOOTH_PROFILE_HFP_AG: > return "headset_audio_gateway"; > case PA_BLUETOOTH_PROFILE_OFF: > @@ -1727,7 +1751,7 @@ static void endpoint_done(pa_bluetooth_discovery *y, pa_bluetooth_profile_t prof > } > } > > -pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backend) { > +pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backend, bool enable_native_hfp_hf) { > pa_bluetooth_discovery *y; > DBusError err; > DBusConnection *conn; > @@ -1737,6 +1761,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c, int headset_backe > PA_REFCNT_INIT(y); > y->core = c; > y->headset_backend = headset_backend; > + y->enable_native_hfp_hf = enable_native_hfp_hf; > y->adapters = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, > (pa_free_cb_t) adapter_free); > y->devices = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, > diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h > index 84c0c3f1..b077ca2c 100644 > --- a/src/modules/bluetooth/bluez5-util.h > +++ b/src/modules/bluetooth/bluez5-util.h > @@ -47,6 +47,7 @@ typedef enum profile { > PA_BLUETOOTH_PROFILE_A2DP_SINK, > PA_BLUETOOTH_PROFILE_A2DP_SOURCE, > PA_BLUETOOTH_PROFILE_HSP_HS, > + PA_BLUETOOTH_PROFILE_HFP_HF, > PA_BLUETOOTH_PROFILE_HFP_AG, > PA_BLUETOOTH_PROFILE_OFF > } pa_bluetooth_profile_t; > @@ -161,8 +162,9 @@ const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile); > #define HEADSET_BACKEND_NATIVE 1 > #define HEADSET_BACKEND_AUTO 2 > > -pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core, int headset_backend); > +pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core, int headset_backend, bool default_profile_hfp); > pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y); > void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y); > void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is_running); > +bool pa_bluetooth_discovery_get_enable_native_hfp_hf(pa_bluetooth_discovery *y); > #endif > diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c > index 316b9a82..b17c5d39 100644 > --- a/src/modules/bluetooth/module-bluetooth-policy.c > +++ b/src/modules/bluetooth/module-bluetooth-policy.c > @@ -365,7 +365,8 @@ static pa_hook_result_t profile_available_hook_callback(pa_core *c, pa_card_prof > /* Do not automatically switch profiles for headsets, just in case */ > /* TODO: remove a2dp and hsp when we remove BlueZ 4 support */ > if (pa_streq(profile->name, "hsp") || pa_streq(profile->name, "a2dp") || pa_streq(profile->name, "a2dp_sink") || > - pa_streq(profile->name, "headset_head_unit")) > + pa_streq(profile->name, "headset_head_unit") || > + pa_streq(profile->name, "headset_handsfree")) > return PA_HOOK_OK; > > is_active_profile = card->active_profile == profile; > diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c > index d076fbad..d37ce9ce 100644 > --- a/src/modules/bluetooth/module-bluez5-device.c > +++ b/src/modules/bluetooth/module-bluez5-device.c > @@ -258,6 +258,7 @@ static int sco_process_render(struct userdata *u) { > > pa_assert(u); > pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || > + u->profile == PA_BLUETOOTH_PROFILE_HFP_HF || > u->profile == PA_BLUETOOTH_PROFILE_HFP_AG); > pa_assert(u->sink); > > @@ -318,6 +319,7 @@ static int sco_process_push(struct userdata *u) { > > pa_assert(u); > pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || > + u->profile == PA_BLUETOOTH_PROFILE_HFP_HF|| > u->profile == PA_BLUETOOTH_PROFILE_HFP_AG); > pa_assert(u->source); > pa_assert(u->read_smoother); > @@ -784,7 +786,9 @@ static void transport_release(struct userdata *u) { > > /* Run from I/O thread */ > static void transport_config_mtu(struct userdata *u) { > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > u->read_block_size = u->read_link_mtu; > u->write_block_size = u->write_link_mtu; > > @@ -1004,7 +1008,8 @@ static int add_source(struct userdata *u) { > data.namereg_fail = false; > pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile)); > pa_source_new_data_set_sample_spec(&data, &u->sample_spec); > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS) > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) > pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone"); > > connect_ports(u, &data, PA_DIRECTION_INPUT); > @@ -1016,6 +1021,7 @@ static int add_source(struct userdata *u) { > data.suspend_cause = PA_SUSPEND_USER; > break; > case PA_BLUETOOTH_PROFILE_HSP_HS: > + case PA_BLUETOOTH_PROFILE_HFP_HF: > /* u->stream_fd contains the error returned by the last transport_acquire() > * EAGAIN means we are waiting for a NewConnection signal */ > if (u->stream_fd == -EAGAIN) > @@ -1039,7 +1045,9 @@ static int add_source(struct userdata *u) { > u->source->userdata = u; > u->source->parent.process_msg = source_process_msg; > > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) { > pa_source_set_set_volume_callback(u->source, source_set_volume_cb); > u->source->n_volume_steps = 16; > } > @@ -1174,7 +1182,8 @@ static int add_sink(struct userdata *u) { > data.namereg_fail = false; > pa_proplist_sets(data.proplist, "bluetooth.protocol", pa_bluetooth_profile_to_string(u->profile)); > pa_sink_new_data_set_sample_spec(&data, &u->sample_spec); > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS) > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) > pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone"); > > connect_ports(u, &data, PA_DIRECTION_OUTPUT); > @@ -1185,6 +1194,7 @@ static int add_sink(struct userdata *u) { > data.suspend_cause = PA_SUSPEND_USER; > break; > case PA_BLUETOOTH_PROFILE_HSP_HS: > + case PA_BLUETOOTH_PROFILE_HFP_HF: > /* u->stream_fd contains the error returned by the last transport_acquire() > * EAGAIN means we are waiting for a NewConnection signal */ > if (u->stream_fd == -EAGAIN) > @@ -1210,7 +1220,9 @@ static int add_sink(struct userdata *u) { > u->sink->userdata = u; > u->sink->parent.process_msg = sink_process_msg; > > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF) { > pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb); > u->sink->n_volume_steps = 16; > } > @@ -1219,7 +1231,9 @@ static int add_sink(struct userdata *u) { > > /* Run from main thread */ > static void transport_config(struct userdata *u) { > - if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > + if (u->profile == PA_BLUETOOTH_PROFILE_HSP_HS > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_HF > + || u->profile == PA_BLUETOOTH_PROFILE_HFP_AG) { > u->sample_spec.format = PA_SAMPLE_S16LE; > u->sample_spec.channels = 1; > u->sample_spec.rate = 8000; > @@ -1370,6 +1384,7 @@ static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) { > [PA_BLUETOOTH_PROFILE_A2DP_SINK] = PA_DIRECTION_OUTPUT, > [PA_BLUETOOTH_PROFILE_A2DP_SOURCE] = PA_DIRECTION_INPUT, > [PA_BLUETOOTH_PROFILE_HSP_HS] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, > + [PA_BLUETOOTH_PROFILE_HFP_HF] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, > [PA_BLUETOOTH_PROFILE_HFP_AG] = PA_DIRECTION_INPUT | PA_DIRECTION_OUTPUT, > [PA_BLUETOOTH_PROFILE_OFF] = 0 > }; > @@ -1874,7 +1889,20 @@ static pa_card_profile *create_card_profile(struct userdata *u, pa_bluetooth_pro > break; > > case PA_BLUETOOTH_PROFILE_HSP_HS: > - cp = pa_card_profile_new(name, _("Headset Head Unit (HSP/HFP)"), sizeof(pa_bluetooth_profile_t)); > + cp = pa_card_profile_new(name, _("Headset Head Unit (HSP)"), sizeof(pa_bluetooth_profile_t)); > + cp->priority = 20; > + cp->n_sinks = 1; > + cp->n_sources = 1; > + cp->max_sink_channels = 1; > + cp->max_source_channels = 1; > + pa_hashmap_put(input_port->profiles, cp->name, cp); > + pa_hashmap_put(output_port->profiles, cp->name, cp); > + > + p = PA_CARD_PROFILE_DATA(cp); > + break; > + > + case PA_BLUETOOTH_PROFILE_HFP_HF: > + cp = pa_card_profile_new(name, _("Headset Handsfree (HFP)"), sizeof(pa_bluetooth_profile_t)); > cp->priority = 20; > cp->n_sinks = 1; > cp->n_sources = 1; > @@ -1960,8 +1988,10 @@ static int uuid_to_profile(const char *uuid, pa_bluetooth_profile_t *_r) { > *_r = PA_BLUETOOTH_PROFILE_A2DP_SINK; > else if (pa_streq(uuid, PA_BLUETOOTH_UUID_A2DP_SOURCE)) > *_r = PA_BLUETOOTH_PROFILE_A2DP_SOURCE; > - else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) > + else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS)) > *_r = PA_BLUETOOTH_PROFILE_HSP_HS; > + else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) > + *_r = PA_BLUETOOTH_PROFILE_HFP_HF; > else if (pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_AG) || pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_AG)) > *_r = PA_BLUETOOTH_PROFILE_HFP_AG; > else > @@ -1980,6 +2010,7 @@ static int add_card(struct userdata *u) { > pa_bluetooth_profile_t *p; > const char *uuid; > void *state; > + bool enable_native_hfp_hf, has_both; > > pa_assert(u); > pa_assert(u->device); > @@ -2010,9 +2041,22 @@ static int add_card(struct userdata *u) { > > create_card_ports(u, data.ports); > > + enable_native_hfp_hf = pa_bluetooth_discovery_get_enable_native_hfp_hf(u->discovery); > + > + has_both = enable_native_hfp_hf && pa_hashmap_get(d->uuids, PA_BLUETOOTH_UUID_HFP_HF) && pa_hashmap_get(d->uuids, PA_BLUETOOTH_UUID_HSP_HS); > PA_HASHMAP_FOREACH(uuid, d->uuids, state) { > pa_bluetooth_profile_t profile; > > + if (!enable_native_hfp_hf && pa_streq(uuid, PA_BLUETOOTH_UUID_HFP_HF)) { > + pa_log_info("device supports HFP but disabling profile as requested"); > + continue; > + } > + > + if (has_both && pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS)) { > + pa_log_info("device support HSP and HFP, selecting HFP only"); > + continue; > + } > + You need to skip this (or maybe log another message) if the ofono backend is used and enable_native_hfp_hf is not set. > if (uuid_to_profile(uuid, &profile) < 0) > continue; > > diff --git a/src/modules/bluetooth/module-bluez5-discover.c b/src/modules/bluetooth/module-bluez5-discover.c > index c535ead4..bfb361ae 100644 > --- a/src/modules/bluetooth/module-bluez5-discover.c > +++ b/src/modules/bluetooth/module-bluez5-discover.c > @@ -104,6 +104,7 @@ int pa__init(pa_module *m) { > const char *headset_str; > int headset_backend; > bool autodetect_mtu; > + bool enable_native_hfp_hf = true; > > pa_assert(m); > > @@ -127,6 +128,9 @@ int pa__init(pa_module *m) { > autodetect_mtu = false; > if (pa_modargs_get_value_boolean(ma, "autodetect_mtu", &autodetect_mtu) < 0) { > pa_log("Invalid boolean value for autodetect_mtu parameter"); > + } The two following lines from your patch 4 should go in here: + /* default value if no module parameter */ + enable_native_hfp_hf = (headset_backend == HEADSET_BACKEND_NATIVE); Otherwise the patch will break the "headset=auto" case. (Please keep changing the default backend to native as a separate patch, even if it is reduced to a one-line change) > + if (pa_modargs_get_value_boolean(ma, "enable_native_hfp_hf", &enable_native_hfp_hf) < 0) { > + pa_log("enable_native_hfp_hf must be true or false"); > goto fail; > } > > @@ -136,7 +140,7 @@ int pa__init(pa_module *m) { > u->autodetect_mtu = autodetect_mtu; > u->loaded_device_paths = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); > > - if (!(u->discovery = pa_bluetooth_discovery_get(u->core, headset_backend))) > + if (!(u->discovery = pa_bluetooth_discovery_get(u->core, headset_backend, enable_native_hfp_hf))) > goto fail; > > u->device_connection_changed_slot =