pipewire/spa/plugins/bluez5/a2dp-codecs.c
Pauli Virtanen 5071589aea bluez5: enable SBC-XQ codec by default, if allowed by quirks
Enable SBC-XQ by default, and move it at the end of the codecs list, so
that bluez does not connect to it automatically except when it is the
codec used previously.

When the codec is disabled by quirks, it won't appear in the codecs
list, and so can't be selected by user (and so won't be connected
automatically).

However, since SelectConfiguration does not carry information which
device is in question, we cannot prevent BlueZ connecting to the codec
even if it's disabled for a specific device. If the "impossible" occurs
regardless, we won't reject the connection and the profile will be shown
as the generic "A2DP" one.  If the sound is garbled, the user can select
some other profile that works.
2021-08-13 18:45:16 +00:00

156 lines
3.2 KiB
C

/*
* BlueALSA - bluez-a2dp.c
* Copyright (c) 2016-2017 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
* This project is licensed under the terms of the MIT license.
*
*/
#include "a2dp-codecs.h"
int a2dp_codec_select_config(const struct a2dp_codec_config configs[], size_t n,
uint32_t cap, int preferred_value)
{
size_t i;
int *scores, res;
unsigned int max_priority;
if (n == 0)
return -EINVAL;
scores = calloc(n, sizeof(int));
if (scores == NULL)
return -errno;
max_priority = configs[0].priority;
for (i = 1; i < n; ++i) {
if (configs[i].priority > max_priority)
max_priority = configs[i].priority;
}
for (i = 0; i < n; ++i) {
if (!(configs[i].config & cap)) {
scores[i] = -1;
continue;
}
if (configs[i].value == preferred_value)
scores[i] = 100 * (max_priority + 1);
else if (configs[i].value > preferred_value)
scores[i] = 10 * (max_priority + 1);
else
scores[i] = 1;
scores[i] *= configs[i].priority + 1;
}
res = 0;
for (i = 1; i < n; ++i) {
if (scores[i] > scores[res])
res = i;
}
if (scores[res] < 0)
res = -EINVAL;
free(scores);
return res;
}
bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id,
const void *caps, size_t caps_size,
const struct a2dp_codec_audio_info *info)
{
uint8_t config[A2DP_MAX_CAPS_SIZE];
int res;
if (codec_id != codec->codec_id)
return false;
if (caps == NULL)
return false;
res = codec->select_config(codec, 0, caps, caps_size, info, NULL, config);
if (res < 0)
return false;
return ((size_t)res == caps_size);
}
#if ENABLE_MP3
const a2dp_mpeg_t bluez_a2dp_mpeg = {
.layer =
MPEG_LAYER_MP1 |
MPEG_LAYER_MP2 |
MPEG_LAYER_MP3,
.crc = 1,
.channel_mode =
MPEG_CHANNEL_MODE_MONO |
MPEG_CHANNEL_MODE_DUAL_CHANNEL |
MPEG_CHANNEL_MODE_STEREO |
MPEG_CHANNEL_MODE_JOINT_STEREO,
.mpf = 1,
.frequency =
MPEG_SAMPLING_FREQ_16000 |
MPEG_SAMPLING_FREQ_22050 |
MPEG_SAMPLING_FREQ_24000 |
MPEG_SAMPLING_FREQ_32000 |
MPEG_SAMPLING_FREQ_44100 |
MPEG_SAMPLING_FREQ_48000,
.bitrate =
MPEG_BIT_RATE_VBR |
MPEG_BIT_RATE_320000 |
MPEG_BIT_RATE_256000 |
MPEG_BIT_RATE_224000 |
MPEG_BIT_RATE_192000 |
MPEG_BIT_RATE_160000 |
MPEG_BIT_RATE_128000 |
MPEG_BIT_RATE_112000 |
MPEG_BIT_RATE_96000 |
MPEG_BIT_RATE_80000 |
MPEG_BIT_RATE_64000 |
MPEG_BIT_RATE_56000 |
MPEG_BIT_RATE_48000 |
MPEG_BIT_RATE_40000 |
MPEG_BIT_RATE_32000 |
MPEG_BIT_RATE_FREE,
};
#endif
extern struct a2dp_codec a2dp_codec_sbc;
extern struct a2dp_codec a2dp_codec_sbc_xq;
#if ENABLE_LDAC
extern struct a2dp_codec a2dp_codec_ldac;
#endif
#if ENABLE_AAC
extern struct a2dp_codec a2dp_codec_aac;
#endif
#if ENABLE_MP3
extern struct a2dp_codec a2dp_codec_mpeg;
#endif
#if ENABLE_APTX
extern struct a2dp_codec a2dp_codec_aptx;
extern struct a2dp_codec a2dp_codec_aptx_hd;
#endif
static const struct a2dp_codec * const a2dp_codec_list[] = {
#if ENABLE_LDAC
&a2dp_codec_ldac,
#endif
#if ENABLE_APTX
&a2dp_codec_aptx_hd,
&a2dp_codec_aptx,
#endif
#if ENABLE_AAC
&a2dp_codec_aac,
#endif
#if ENABLE_MP3
&a2dp_codec_mpeg,
#endif
&a2dp_codec_sbc,
&a2dp_codec_sbc_xq,
NULL
};
const struct a2dp_codec * const * const a2dp_codecs = a2dp_codec_list;