From 68f1107bd2740e4437b121ae9e7d2e9ac5995ca6 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Sat, 6 Apr 2024 18:40:27 +0800 Subject: [PATCH] bluetooth: Add no volume control quirk for Thinkplus XT99 When this headset works in HFP/HSP profile, the input/output volume adjustment doesn't work if the headset is playing sth or capturing sth. Through the btmon log, we could see "+VGS" and "+VGM" were sent to headset and headset replied "command success", but the volume was not changed. It is something like once the SCO connecton is built, the volume couldn't be changed by "+VGS" and "+VGM" commands. Here add a quirk for this headset, skip to set set_sink_volume and set_source_volume, after this change, the pulseaudio will apply the software volume adjustment to this headset in the HFP/HSP mode. This change doesn't impact A2DP volume adjustment for this headset. Signed-off-by: Hui Wang --- src/modules/bluetooth/backend-native.c | 4 ++-- src/modules/bluetooth/bluez5-util.h | 5 ++++ src/modules/bluetooth/module-bluez5-device.c | 24 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 569cc6d36..50a58c6d3 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -917,7 +917,7 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i * RING: Sent by AG to HS to notify of an incoming call. It can safely be ignored because * it does not expect a reply. */ if (sscanf(buf, "AT+VGS=%d", &gain) == 1 || sscanf(buf, "\r\n+VGM%*[=:]%d\r\n", &gain) == 1) { - if (!t->set_sink_volume) { + if (!t->set_sink_volume && !(t->device->quirk & PA_BLUETOOTH_QUIRK_NO_VOLUME_CTL)) { pa_log_debug("HS/HF peer supports speaker gain control"); t->set_sink_volume = set_sink_volume; } @@ -927,7 +927,7 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i do_reply = true; } else if (sscanf(buf, "AT+VGM=%d", &gain) == 1 || sscanf(buf, "\r\n+VGS%*[=:]%d\r\n", &gain) == 1) { - if (!t->set_source_volume) { + if (!t->set_source_volume && !(t->device->quirk & PA_BLUETOOTH_QUIRK_NO_VOLUME_CTL)) { pa_log_debug("HS/HF peer supports microphone gain control"); t->set_source_volume = set_source_volume; } diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index fff3d573c..d8468629d 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -155,6 +155,7 @@ struct pa_bluetooth_device { char *alias; char *address; uint32_t class_of_device; + uint32_t quirk; pa_hashmap *uuids; /* char* -> char* (hashmap-as-a-set) */ /* pa_a2dp_codec_id* -> pa_hashmap ( char* (remote endpoint) -> struct a2dp_codec_capabilities* ) */ pa_hashmap *a2dp_sink_endpoints; @@ -180,6 +181,10 @@ struct pa_bluetooth_adapter { bool battery_provider_registered; }; +typedef enum pa_bluetooth_quirk_def { + PA_BLUETOOTH_QUIRK_NO_VOLUME_CTL = (1 << 0), +} pa_bluetooth_quirk_def_t; + #ifdef HAVE_BLUEZ_5_OFONO_HEADSET pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index dc6809ce5..2f3d1d811 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -183,6 +183,16 @@ typedef enum pa_bluetooth_form_factor { PA_BLUETOOTH_FORM_FACTOR_PHONE, } pa_bluetooth_form_factor_t; +struct pa_bluetooth_quirk_table { + char *alias; + pa_bluetooth_quirk_def_t q; +}; + +static struct pa_bluetooth_quirk_table quirk_tbl[] = { + {.alias = "联想 thinkplus XT99", .q = PA_BLUETOOTH_QUIRK_NO_VOLUME_CTL}, + {} +}; + /* Run from main thread */ static pa_bluetooth_form_factor_t form_factor_from_class(uint32_t class_of_device) { unsigned major, minor; @@ -2787,6 +2797,18 @@ static pa_hook_result_t a2dp_source_output_fixate_hook_callback(pa_core *c, pa_s return PA_HOOK_OK; } +static void apply_quirk (pa_bluetooth_device *d) { + int i = 0; + + d->quirk = 0; + + while (quirk_tbl[i].alias) { + if (pa_streq(d->alias, quirk_tbl[i].alias)) + d->quirk = quirk_tbl[i].q; + i++; + } +} + int pa__init(pa_module* m) { struct userdata *u; const char *path; @@ -2824,6 +2846,8 @@ int pa__init(pa_module* m) { goto fail_free_modargs; } + apply_quirk(u->device); + autodetect_mtu = false; if (pa_modargs_get_value_boolean(ma, "autodetect_mtu", &autodetect_mtu) < 0) { pa_log("Invalid boolean value for autodetect_mtu parameter");