mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: use separate routes for HFP and A2DP
The A2DP and HFP profiles may have different volume curves, so trying to convert volumes between the two can produce undesirable volume spikes. For example, when one of them is using hardware volume and the other software. Fix by separating HFP and A2DP routes.
This commit is contained in:
parent
bb2f054d43
commit
276c4bc554
1 changed files with 58 additions and 10 deletions
|
|
@ -1301,16 +1301,17 @@ static bool validate_profile(struct impl *this, uint32_t profile,
|
|||
}
|
||||
|
||||
static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
|
||||
uint32_t id, uint32_t port, uint32_t dev, uint32_t profile)
|
||||
uint32_t id, uint32_t port, uint32_t profile)
|
||||
{
|
||||
struct spa_bt_device *device = this->bt_dev;
|
||||
struct spa_pod_frame f[2];
|
||||
enum spa_direction direction;
|
||||
const char *name_prefix, *description, *port_type;
|
||||
const char *name_prefix, *description, *hfp_description, *port_type;
|
||||
enum spa_bt_form_factor ff;
|
||||
enum spa_bluetooth_audio_codec codec;
|
||||
char name[128];
|
||||
uint32_t i, j, mask, next;
|
||||
uint32_t dev = SPA_ID_INVALID, enum_dev;
|
||||
|
||||
ff = spa_bt_form_factor_from_class(device->bluetooth_class);
|
||||
|
||||
|
|
@ -1318,52 +1319,62 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
|
|||
case SPA_BT_FORM_FACTOR_HEADSET:
|
||||
name_prefix = "headset";
|
||||
description = _("Headset");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "headset";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_HANDSFREE:
|
||||
name_prefix = "handsfree";
|
||||
description = _("Handsfree");
|
||||
hfp_description = _("Handsfree (HFP)");
|
||||
port_type = "handsfree";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_MICROPHONE:
|
||||
name_prefix = "microphone";
|
||||
description = _("Microphone");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "mic";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_SPEAKER:
|
||||
name_prefix = "speaker";
|
||||
description = _("Speaker");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "speaker";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_HEADPHONE:
|
||||
name_prefix = "headphone";
|
||||
description = _("Headphone");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "headphones";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_PORTABLE:
|
||||
name_prefix = "portable";
|
||||
description = _("Portable");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "portable";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_CAR:
|
||||
name_prefix = "car";
|
||||
description = _("Car");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "car";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_HIFI:
|
||||
name_prefix = "hifi";
|
||||
description = _("HiFi");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "hifi";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_PHONE:
|
||||
name_prefix = "phone";
|
||||
description = _("Phone");
|
||||
hfp_description = _("Handsfree");
|
||||
port_type = "phone";
|
||||
break;
|
||||
case SPA_BT_FORM_FACTOR_UNKNOWN:
|
||||
default:
|
||||
name_prefix = "bluetooth";
|
||||
description = _("Bluetooth");
|
||||
hfp_description = _("Bluetooth (HFP)");
|
||||
port_type = "bluetooth";
|
||||
break;
|
||||
}
|
||||
|
|
@ -1372,16 +1383,51 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
|
|||
case 0:
|
||||
direction = SPA_DIRECTION_INPUT;
|
||||
snprintf(name, sizeof(name), "%s-input", name_prefix);
|
||||
enum_dev = DEVICE_ID_SOURCE;
|
||||
if (profile == DEVICE_PROFILE_A2DP)
|
||||
dev = enum_dev;
|
||||
else if (profile != SPA_ID_INVALID)
|
||||
enum_dev = SPA_ID_INVALID;
|
||||
break;
|
||||
case 1:
|
||||
direction = SPA_DIRECTION_OUTPUT;
|
||||
snprintf(name, sizeof(name), "%s-output", name_prefix);
|
||||
enum_dev = DEVICE_ID_SINK;
|
||||
if (profile == DEVICE_PROFILE_A2DP)
|
||||
dev = enum_dev;
|
||||
else if (profile != SPA_ID_INVALID)
|
||||
enum_dev = SPA_ID_INVALID;
|
||||
break;
|
||||
case 2:
|
||||
direction = SPA_DIRECTION_INPUT;
|
||||
snprintf(name, sizeof(name), "%s-hf-input", name_prefix);
|
||||
description = hfp_description;
|
||||
enum_dev = DEVICE_ID_SOURCE;
|
||||
if (profile == DEVICE_PROFILE_HSP_HFP)
|
||||
dev = enum_dev;
|
||||
else if (profile != SPA_ID_INVALID)
|
||||
enum_dev = SPA_ID_INVALID;
|
||||
break;
|
||||
case 3:
|
||||
direction = SPA_DIRECTION_OUTPUT;
|
||||
snprintf(name, sizeof(name), "%s-hf-output", name_prefix);
|
||||
description = hfp_description;
|
||||
enum_dev = DEVICE_ID_SINK;
|
||||
if (profile == DEVICE_PROFILE_HSP_HFP)
|
||||
dev = enum_dev;
|
||||
else if (profile != SPA_ID_INVALID)
|
||||
enum_dev = SPA_ID_INVALID;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (enum_dev == SPA_ID_INVALID) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_ParamRoute, id);
|
||||
spa_pod_builder_add(b,
|
||||
SPA_PARAM_ROUTE_index, SPA_POD_Int(port),
|
||||
|
|
@ -1406,6 +1452,11 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
|
|||
for (i = 1; (j = get_profile_from_index(this, i, &next, &codec)) != SPA_ID_INVALID; i = next) {
|
||||
uint32_t profile_mask;
|
||||
|
||||
if (j == DEVICE_PROFILE_A2DP && !(port == 0 || port == 1))
|
||||
continue;
|
||||
if (j == DEVICE_PROFILE_HSP_HFP && !(port == 2 || port == 3))
|
||||
continue;
|
||||
|
||||
profile_mask = profile_direction_mask(this, j, codec);
|
||||
if (!(profile_mask & (1 << direction)))
|
||||
continue;
|
||||
|
|
@ -1472,8 +1523,7 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
|
|||
|
||||
spa_pod_builder_prop(b, SPA_PARAM_ROUTE_devices, 0);
|
||||
spa_pod_builder_push_array(b, &f[1]);
|
||||
/* port and device indexes are the same, 0=source, 1=sink */
|
||||
spa_pod_builder_int(b, port);
|
||||
spa_pod_builder_int(b, enum_dev);
|
||||
spa_pod_builder_pop(b, &f[1]);
|
||||
|
||||
if (profile != SPA_ID_INVALID) {
|
||||
|
|
@ -1640,9 +1690,8 @@ static int impl_enum_params(void *object, int seq,
|
|||
case SPA_PARAM_EnumRoute:
|
||||
{
|
||||
switch (result.index) {
|
||||
case 0: case 1:
|
||||
param = build_route(this, &b, id, result.index,
|
||||
SPA_ID_INVALID, SPA_ID_INVALID);
|
||||
case 0: case 1: case 2: case 3:
|
||||
param = build_route(this, &b, id, result.index, SPA_ID_INVALID);
|
||||
if (param == NULL)
|
||||
goto next;
|
||||
break;
|
||||
|
|
@ -1654,9 +1703,8 @@ static int impl_enum_params(void *object, int seq,
|
|||
case SPA_PARAM_Route:
|
||||
{
|
||||
switch (result.index) {
|
||||
case 0: case 1:
|
||||
param = build_route(this, &b, id, result.index,
|
||||
result.index, this->profile);
|
||||
case 0: case 1: case 2: case 3:
|
||||
param = build_route(this, &b, id, result.index, this->profile);
|
||||
if (param == NULL)
|
||||
goto next;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue