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 <hui.wang@canonical.com>
This commit is contained in:
Hui Wang 2024-04-06 18:40:27 +08:00
parent 6c77b0191a
commit 68f1107bd2
3 changed files with 31 additions and 2 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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");