From 9d38d375d204b9055af569ac3a6c9d7d2a70a061 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 21 Jun 2021 21:10:42 +0300 Subject: [PATCH] bluez5: add and use quirk for broken mic HW volume Some headsets emit AT+VGM even though +VGM commands do not actually adjust the recording volume. --- spa/plugins/bluez5/backend-native.c | 18 +++++++++++++++--- spa/plugins/bluez5/defs.h | 3 ++- spa/plugins/bluez5/quirks.c | 1 + src/daemon/media-session.d/bluez-hardware.conf | 5 +++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c index 26e5ed882..cd8ae3473 100644 --- a/spa/plugins/bluez5/backend-native.c +++ b/spa/plugins/bluez5/backend-native.c @@ -129,6 +129,7 @@ struct rfcomm { char* path; bool has_volume; struct rfcomm_volume volumes[SPA_BT_VOLUME_ID_TERM]; + unsigned int broken_mic_hw_volume:1; #ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE unsigned int slc_configured:1; unsigned int codec_negotiation_supported:1; @@ -331,7 +332,8 @@ static bool rfcomm_hsp_ag(struct spa_source *source, char* buf) } } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1) { if (gain <= SPA_BT_VOLUME_HS_MAX) { - rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain); + if (!rfcomm->broken_mic_hw_volume) + rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain); rfcomm_send_reply(source, "OK"); } else { rfcomm_send_reply(source, "ERROR"); @@ -619,7 +621,7 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf) /* * Determine device volume control. Some headsets only support control of * TX volume, but not RX, even if they have a microphone. Determine this - * separately based on whether we also get AT+VGS/AT+VGM. + * separately based on whether we also get AT+VGS/AT+VGM, and quirks. */ rfcomm->has_volume = (features & SPA_BT_HFP_HF_FEATURE_REMOTE_VOLUME_CONTROL); @@ -753,7 +755,8 @@ static bool rfcomm_hfp_ag(struct spa_source *source, char* buf) spa_bt_device_emit_codec_switched(rfcomm->device, 0); } else if (sscanf(buf, "AT+VGM=%u", &gain) == 1) { if (gain <= SPA_BT_VOLUME_HS_MAX) { - rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain); + if (!rfcomm->broken_mic_hw_volume) + rfcomm_emit_volume_changed(rfcomm, SPA_BT_VOLUME_ID_RX, gain); rfcomm_send_reply(source, "OK"); } else { spa_log_debug(backend->log, NAME": RFCOMM receive unsupported VGM gain: %s", buf); @@ -1659,6 +1662,15 @@ static DBusHandlerResult profile_new_connection(DBusConnection *conn, DBusMessag rfcomm->hf_state = hfp_hf_brsf; } + if (rfcomm_volume_enabled(rfcomm) && (profile == SPA_BT_PROFILE_HFP_HF || profile == SPA_BT_PROFILE_HSP_HS)) { + uint32_t device_features; + if (spa_bt_quirks_get_features(backend->quirks, d->adapter, d, &device_features) == 0) { + rfcomm->broken_mic_hw_volume = !(device_features & SPA_BT_FEATURE_HW_VOLUME_MIC); + if (rfcomm->broken_mic_hw_volume) + spa_log_debug(backend->log, NAME": microphone HW volume disabled by quirk"); + } + } + if ((r = dbus_message_new_method_return(m)) == NULL) goto fail_need_memory; if (!dbus_connection_send(conn, r, NULL)) diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index 6a5a47cbd..30d8fd97a 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -671,7 +671,8 @@ enum spa_bt_feature { SPA_BT_FEATURE_MSBC_ALT1 = (1 << 1), SPA_BT_FEATURE_MSBC_ALT1_RTL = (1 << 2), SPA_BT_FEATURE_HW_VOLUME = (1 << 3), - SPA_BT_FEATURE_SBC_XQ = (1 << 4), + SPA_BT_FEATURE_HW_VOLUME_MIC = (1 << 4), + SPA_BT_FEATURE_SBC_XQ = (1 << 5), }; struct spa_bt_quirks; diff --git a/spa/plugins/bluez5/quirks.c b/spa/plugins/bluez5/quirks.c index bcae542c8..14e4c335c 100644 --- a/spa/plugins/bluez5/quirks.c +++ b/spa/plugins/bluez5/quirks.c @@ -75,6 +75,7 @@ static enum spa_bt_feature parse_feature(const char *str) { "msbc-alt1", SPA_BT_FEATURE_MSBC_ALT1 }, { "msbc-alt1-rtl", SPA_BT_FEATURE_MSBC_ALT1_RTL }, { "hw-volume", SPA_BT_FEATURE_HW_VOLUME }, + { "hw-volume-mic", SPA_BT_FEATURE_HW_VOLUME_MIC }, { "sbc-xq", SPA_BT_FEATURE_SBC_XQ }, }; size_t i; diff --git a/src/daemon/media-session.d/bluez-hardware.conf b/src/daemon/media-session.d/bluez-hardware.conf index d848da84f..08df5f5e8 100644 --- a/src/daemon/media-session.d/bluez-hardware.conf +++ b/src/daemon/media-session.d/bluez-hardware.conf @@ -10,7 +10,8 @@ # msbc "standard" mSBC (60 byte tx packet) # msbc-alt1 USB adapters with mSBC in ALT1 setting (24 byte tx packet) # msbc-alt1-rtl Realtek USB adapters with mSBC in ALT1 setting (24 byte tx packet) -# hw-volume AVRCP absolute volume support +# hw-volume AVRCP and HSP/HFP hardware volume support +# hw-volume-mic Functional HSP/HFP microphone volume support # sbc-xq "nonstandard" SBC codec setting with better sound quality # (XXX: the SBC-XQ per-device setting doesn't have effect yet) # @@ -25,7 +26,7 @@ bluez5.features.device = [ # - product-id # - version-id - { name = "Air 1 Plus" }, + { name = "Air 1 Plus", no-features = [ hw-volume-mic ] }, { name = "AirPods", no-features = [ msbc-alt1, msbc-alt1-rtl ] }, { name = "AirPods Pro", no-features = [ msbc-alt1, msbc-alt1-rtl ] }, { name = "AXLOIE Goin", no-features = [ msbc-alt1, msbc-alt1-rtl ] },