diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index e10a47447..ea4710d93 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -38,11 +38,14 @@ #include #include #include +#include #include "defs.h" #define NAME "native" +#define PROP_KEY_HEADSET_ROLES "bluez5.headset-roles" + struct spa_bt_backend { struct spa_bt_monitor *monitor; @@ -51,6 +54,8 @@ struct spa_bt_backend { struct spa_dbus *dbus; DBusConnection *conn; + enum spa_bt_profile enabled_profiles; + struct spa_list rfcomm_list; unsigned int msbc_support_enabled_in_config:1; }; @@ -921,6 +926,9 @@ static int register_profile(struct spa_bt_backend *backend, const char *profile, char *str; DBusPendingCall *call; + if (!(backend->enabled_profiles & spa_bt_profile_from_uuid(uuid))) + return -ECANCELED; + spa_log_debug(backend->log, NAME": Registering Profile %s %s", profile, uuid); m = dbus_message_new_method_call(BLUEZ_SERVICE, "/org/bluez", @@ -1014,6 +1022,46 @@ void backend_native_free(struct spa_bt_backend *backend) free(backend); } +static int parse_headset_roles(struct spa_bt_backend *backend, const struct spa_dict *info) +{ + const char *str; + struct spa_json it, it_array; + char role_name[256]; + enum spa_bt_profile profiles = SPA_BT_PROFILE_NULL; + + if ((str = spa_dict_lookup(info, PROP_KEY_HEADSET_ROLES)) == NULL) + goto fallback; + + spa_json_init(&it, str, strlen(str)); + + if (spa_json_enter_array(&it, &it_array) <= 0) { + spa_log_error(backend->log, + NAME": property "PROP_KEY_HEADSET_ROLES" '%s' is not an array", str); + goto fallback; + } + + while (spa_json_get_string(&it_array, role_name, sizeof(role_name)) > 0) { + if (strcmp(role_name, "hsp_hs") == 0) { + profiles |= SPA_BT_PROFILE_HSP_HS; + } else if (strcmp(role_name, "hsp_ag") == 0) { + profiles |= SPA_BT_PROFILE_HSP_AG; + } else if (strcmp(role_name, "hfp_hf") == 0) { + profiles |= SPA_BT_PROFILE_HFP_HF; + } else if (strcmp(role_name, "hfp_ag") == 0) { + profiles |= SPA_BT_PROFILE_HFP_AG; + } else { + spa_log_warn(backend->log, + NAME": unknown role name '%s' in "PROP_KEY_HEADSET_ROLES, role_name); + } + } + + backend->enabled_profiles = profiles; + return 0; +fallback: + backend->enabled_profiles = SPA_BT_PROFILE_HEADSET_AUDIO; + return 0; +} + struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor, void *dbus_connection, const struct spa_dict *info, @@ -1044,6 +1092,9 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor, else backend->msbc_support_enabled_in_config = false; + if (parse_headset_roles(backend, info) < 0) + goto fail; + #ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE if (!dbus_connection_register_object_path(backend->conn, PROFILE_HSP_AG, diff --git a/src/daemon/media-session.d/bluez-monitor.conf b/src/daemon/media-session.d/bluez-monitor.conf index 2789c0df8..8fdfb2823 100644 --- a/src/daemon/media-session.d/bluez-monitor.conf +++ b/src/daemon/media-session.d/bluez-monitor.conf @@ -4,7 +4,13 @@ properties = { #bluez5.msbc-support = true #bluez5.sbc-xq-support = true - # Enabled codecs (default: all) + # Enabled headset roles (default: all), this property only applies + # to native backend. Currently some headsets(Sony WH-1000XM3) are not + # working with both hsp_ag and hfp_ag enabled, disable either hsp_ag + # or hfp_ag to work around it. + #bluez5.headset-roles = [ hsp_hs hsp_ag hfp_ag ] + + # Enabled A2DP codecs (default: all) #bluez5.codecs = [ sbc aac ldac aptx aptx_hd ] }