diff --git a/spa/plugins/bluez5/a2dp-codec-aac.c b/spa/plugins/bluez5/a2dp-codec-aac.c index 1ebd6717f..05b5d91ca 100644 --- a/spa/plugins/bluez5/a2dp-codec-aac.c +++ b/spa/plugins/bluez5/a2dp-codec-aac.c @@ -90,22 +90,26 @@ static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, return sizeof(a2dp_aac); } -static struct { - int config; - int freq; -} aac_frequencies[] = { - { AAC_SAMPLING_FREQ_48000, 48000 }, - { AAC_SAMPLING_FREQ_44100, 44100 }, - { AAC_SAMPLING_FREQ_96000, 96000 }, - { AAC_SAMPLING_FREQ_88200, 88200 }, - { AAC_SAMPLING_FREQ_64000, 64000 }, - { AAC_SAMPLING_FREQ_32000, 32000 }, - { AAC_SAMPLING_FREQ_24000, 24000 }, - { AAC_SAMPLING_FREQ_22050, 22050 }, - { AAC_SAMPLING_FREQ_16000, 16000 }, - { AAC_SAMPLING_FREQ_12000, 12000 }, - { AAC_SAMPLING_FREQ_11025, 11025 }, - { AAC_SAMPLING_FREQ_8000, 8000 }, +static struct a2dp_codec_config +aac_frequencies[] = { + { AAC_SAMPLING_FREQ_48000, 48000, 11 }, + { AAC_SAMPLING_FREQ_44100, 44100, 10 }, + { AAC_SAMPLING_FREQ_96000, 96000, 9 }, + { AAC_SAMPLING_FREQ_88200, 88200, 8 }, + { AAC_SAMPLING_FREQ_64000, 64000, 7 }, + { AAC_SAMPLING_FREQ_32000, 32000, 6 }, + { AAC_SAMPLING_FREQ_24000, 24000, 5 }, + { AAC_SAMPLING_FREQ_22050, 22050, 4 }, + { AAC_SAMPLING_FREQ_16000, 16000, 3 }, + { AAC_SAMPLING_FREQ_12000, 12000, 2 }, + { AAC_SAMPLING_FREQ_11025, 11025, 1 }, + { AAC_SAMPLING_FREQ_8000, 8000, 0 }, +}; + +static struct a2dp_codec_config +aac_channel_modes[] = { + { AAC_CHANNELS_2, 2, 1 }, + { AAC_CHANNELS_1, 1, 0 }, }; static int get_valid_aac_bitrate(a2dp_aac_t *conf) @@ -120,11 +124,11 @@ static int get_valid_aac_bitrate(a2dp_aac_t *conf) static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]) { a2dp_aac_t conf; - int freq; - bool freq_found; + int i; if (caps_size < sizeof(conf)) return -EINVAL; @@ -142,24 +146,21 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, else return -ENOTSUP; - freq = AAC_GET_FREQUENCY(conf); - freq_found = false; - for (size_t i = 0; i < SPA_N_ELEMENTS(aac_frequencies); i++) { - if (freq & aac_frequencies[i].config) { - AAC_SET_FREQUENCY(conf, aac_frequencies[i].config); - freq_found = true; - break; - } - } - if (!freq_found) + if ((i = a2dp_codec_select_config(aac_frequencies, + SPA_N_ELEMENTS(aac_frequencies), + AAC_GET_FREQUENCY(conf), + info ? info->rate : A2DP_CODEC_DEFAULT_RATE + )) < 0) return -ENOTSUP; + AAC_SET_FREQUENCY(conf, aac_frequencies[i].config); - if (conf.channels & AAC_CHANNELS_2) - conf.channels = AAC_CHANNELS_2; - else if (conf.channels & AAC_CHANNELS_1) - conf.channels = AAC_CHANNELS_1; - else + if ((i = a2dp_codec_select_config(aac_channel_modes, + SPA_N_ELEMENTS(aac_channel_modes), + conf.channels, + info ? info->channels : A2DP_CODEC_DEFAULT_CHANNELS + )) < 0) return -ENOTSUP; + conf.channels = aac_channel_modes[i].config; AAC_SET_BITRATE(conf, get_valid_aac_bitrate(&conf)); @@ -200,8 +201,8 @@ static int codec_enum_config(const struct a2dp_codec *codec, for (size_t j = 0; j < SPA_N_ELEMENTS(aac_frequencies); j++) { if (AAC_GET_FREQUENCY(conf) & aac_frequencies[j].config) { if (i++ == 0) - spa_pod_builder_int(b, aac_frequencies[j].freq); - spa_pod_builder_int(b, aac_frequencies[j].freq); + spa_pod_builder_int(b, aac_frequencies[j].value); + spa_pod_builder_int(b, aac_frequencies[j].value); } } if (i == 0) diff --git a/spa/plugins/bluez5/a2dp-codec-aptx.c b/spa/plugins/bluez5/a2dp-codec-aptx.c index af51aadbb..53b92c734 100644 --- a/spa/plugins/bluez5/a2dp-codec-aptx.c +++ b/spa/plugins/bluez5/a2dp-codec-aptx.c @@ -76,11 +76,21 @@ static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, return actual_conf_size; } +static struct a2dp_codec_config +aptx_frequencies[] = { + { APTX_SAMPLING_FREQ_48000, 48000, 3 }, + { APTX_SAMPLING_FREQ_44100, 44100, 2 }, + { APTX_SAMPLING_FREQ_32000, 32000, 1 }, + { APTX_SAMPLING_FREQ_16000, 16000, 0 }, +}; + static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]) { a2dp_aptx_t conf; + int i; size_t actual_conf_size = codec_get_caps_size(codec); if (caps_size < sizeof(conf) || actual_conf_size < sizeof(conf)) @@ -92,16 +102,13 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, codec->vendor.codec_id != conf.info.codec_id) return -ENOTSUP; - if (conf.frequency & APTX_SAMPLING_FREQ_48000) - conf.frequency = APTX_SAMPLING_FREQ_48000; - else if (conf.frequency & APTX_SAMPLING_FREQ_44100) - conf.frequency = APTX_SAMPLING_FREQ_44100; - else if (conf.frequency & APTX_SAMPLING_FREQ_32000) - conf.frequency = APTX_SAMPLING_FREQ_32000; - else if (conf.frequency & APTX_SAMPLING_FREQ_16000) - conf.frequency = APTX_SAMPLING_FREQ_16000; - else + if ((i = a2dp_codec_select_config(aptx_frequencies, + SPA_N_ELEMENTS(aptx_frequencies), + conf.frequency, + info ? info->rate : A2DP_CODEC_DEFAULT_RATE + )) < 0) return -ENOTSUP; + conf.frequency = aptx_frequencies[i].config; if (conf.channel_mode & APTX_CHANNEL_MODE_STEREO) conf.channel_mode = APTX_CHANNEL_MODE_STEREO; diff --git a/spa/plugins/bluez5/a2dp-codec-ldac.c b/spa/plugins/bluez5/a2dp-codec-ldac.c index f1da6876c..ea9b8af84 100644 --- a/spa/plugins/bluez5/a2dp-codec-ldac.c +++ b/spa/plugins/bluez5/a2dp-codec-ldac.c @@ -95,11 +95,28 @@ static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, uint8 return sizeof(a2dp_ldac); } +static struct a2dp_codec_config +ldac_frequencies[] = { + { LDACBT_SAMPLING_FREQ_044100, 44100, 3 }, + { LDACBT_SAMPLING_FREQ_048000, 48000, 2 }, + { LDACBT_SAMPLING_FREQ_088200, 88200, 1 }, + { LDACBT_SAMPLING_FREQ_096000, 96000, 0 }, +}; + +static struct a2dp_codec_config +ldac_channel_modes[] = { + { LDACBT_CHANNEL_MODE_STEREO, 2, 2 }, + { LDACBT_CHANNEL_MODE_DUAL_CHANNEL, 2, 1 }, + { LDACBT_CHANNEL_MODE_MONO, 1, 0 }, +}; + static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]) { a2dp_ldac_t conf; + int i; if (caps_size < sizeof(conf)) return -EINVAL; @@ -110,25 +127,21 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, codec->vendor.codec_id != conf.info.codec_id) return -ENOTSUP; - if (conf.frequency & LDACBT_SAMPLING_FREQ_044100) - conf.frequency = LDACBT_SAMPLING_FREQ_044100; - else if (conf.frequency & LDACBT_SAMPLING_FREQ_048000) - conf.frequency = LDACBT_SAMPLING_FREQ_048000; - else if (conf.frequency & LDACBT_SAMPLING_FREQ_088200) - conf.frequency = LDACBT_SAMPLING_FREQ_088200; - else if (conf.frequency & LDACBT_SAMPLING_FREQ_096000) - conf.frequency = LDACBT_SAMPLING_FREQ_096000; - else + if ((i = a2dp_codec_select_config(ldac_frequencies, + SPA_N_ELEMENTS(ldac_frequencies), + conf.frequency, + info ? info->rate : A2DP_CODEC_DEFAULT_RATE + )) < 0) return -ENOTSUP; + conf.frequency = ldac_frequencies[i].config; - if (conf.channel_mode & LDACBT_CHANNEL_MODE_STEREO) - conf.channel_mode = LDACBT_CHANNEL_MODE_STEREO; - else if (conf.channel_mode & LDACBT_CHANNEL_MODE_DUAL_CHANNEL) - conf.channel_mode = LDACBT_CHANNEL_MODE_DUAL_CHANNEL; - else if (conf.channel_mode & LDACBT_CHANNEL_MODE_MONO) - conf.channel_mode = LDACBT_CHANNEL_MODE_MONO; - else + if ((i = a2dp_codec_select_config(ldac_channel_modes, + SPA_N_ELEMENTS(ldac_channel_modes), + conf.channel_mode, + info ? info->channels : A2DP_CODEC_DEFAULT_CHANNELS + )) < 0) return -ENOTSUP; + conf.channel_mode = ldac_channel_modes[i].config; memcpy(config, &conf, sizeof(conf)); diff --git a/spa/plugins/bluez5/a2dp-codec-sbc.c b/spa/plugins/bluez5/a2dp-codec-sbc.c index b7f5e4567..e0c3f430c 100644 --- a/spa/plugins/bluez5/a2dp-codec-sbc.c +++ b/spa/plugins/bluez5/a2dp-codec-sbc.c @@ -119,14 +119,48 @@ static uint8_t default_bitpool(uint8_t freq, uint8_t mode, bool xq) return xq ? 86 : 64; } + +static struct a2dp_codec_config +sbc_frequencies[] = { + { SBC_SAMPLING_FREQ_48000, 48000, 3 }, + { SBC_SAMPLING_FREQ_44100, 44100, 2 }, + { SBC_SAMPLING_FREQ_32000, 32000, 1 }, + { SBC_SAMPLING_FREQ_16000, 16000, 0 }, +}; + +static struct a2dp_codec_config +sbc_xq_frequencies[] = { + { SBC_SAMPLING_FREQ_44100, 44100, 1 }, + { SBC_SAMPLING_FREQ_48000, 48000, 0 }, +}; + +static struct a2dp_codec_config +sbc_channel_modes[] = { + { SBC_CHANNEL_MODE_JOINT_STEREO, 2, 3 }, + { SBC_CHANNEL_MODE_STEREO, 2, 2 }, + { SBC_CHANNEL_MODE_DUAL_CHANNEL, 2, 1 }, + { SBC_CHANNEL_MODE_MONO, 1, 0 }, +}; + +static struct a2dp_codec_config +sbc_xq_channel_modes[] = { + { SBC_CHANNEL_MODE_DUAL_CHANNEL, 2, 2 }, + { SBC_CHANNEL_MODE_JOINT_STEREO, 2, 1 }, + { SBC_CHANNEL_MODE_STEREO, 2, 0 }, +}; + static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]) { a2dp_sbc_t conf; - int bitpool; + int bitpool, i; + size_t n; + struct a2dp_codec_config * configs; bool xq = false; + if (caps_size < sizeof(conf)) return -EINVAL; @@ -135,44 +169,30 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, memcpy(&conf, caps, sizeof(conf)); if (xq) { - if (conf.frequency & SBC_SAMPLING_FREQ_44100) - conf.frequency = SBC_SAMPLING_FREQ_44100; - else if (conf.frequency & SBC_SAMPLING_FREQ_48000) - conf.frequency = SBC_SAMPLING_FREQ_48000; - else - return -ENOTSUP; + configs = sbc_xq_frequencies; + n = SPA_N_ELEMENTS(sbc_xq_frequencies); + } else { + configs = sbc_frequencies; + n = SPA_N_ELEMENTS(sbc_frequencies); } - else if (conf.frequency & SBC_SAMPLING_FREQ_48000) - conf.frequency = SBC_SAMPLING_FREQ_48000; - else if (conf.frequency & SBC_SAMPLING_FREQ_44100) - conf.frequency = SBC_SAMPLING_FREQ_44100; - else if (conf.frequency & SBC_SAMPLING_FREQ_32000) - conf.frequency = SBC_SAMPLING_FREQ_32000; - else if (conf.frequency & SBC_SAMPLING_FREQ_16000) - conf.frequency = SBC_SAMPLING_FREQ_16000; - else + if ((i = a2dp_codec_select_config(configs, n, conf.frequency, + info ? info->rate : A2DP_CODEC_DEFAULT_RATE + )) < 0) return -ENOTSUP; + conf.frequency = configs[i].config; if (xq) { - if (conf.channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) - conf.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; - else if (conf.channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) - conf.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; - else if (conf.channel_mode & SBC_CHANNEL_MODE_STEREO) - conf.channel_mode = SBC_CHANNEL_MODE_STEREO; - else - return -ENOTSUP; + configs = sbc_xq_channel_modes; + n = SPA_N_ELEMENTS(sbc_xq_channel_modes); + } else { + configs = sbc_channel_modes; + n = SPA_N_ELEMENTS(sbc_channel_modes); } - else if (conf.channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) - conf.channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; - else if (conf.channel_mode & SBC_CHANNEL_MODE_STEREO) - conf.channel_mode = SBC_CHANNEL_MODE_STEREO; - else if (conf.channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) - conf.channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; - else if (conf.channel_mode & SBC_CHANNEL_MODE_MONO) - conf.channel_mode = SBC_CHANNEL_MODE_MONO; - else + if ((i = a2dp_codec_select_config(configs, n, conf.channel_mode, + info ? info->channels : A2DP_CODEC_DEFAULT_CHANNELS + )) < 0) return -ENOTSUP; + conf.channel_mode = configs[i].config; if (conf.block_length & SBC_BLOCK_LENGTH_16) conf.block_length = SBC_BLOCK_LENGTH_16; @@ -209,7 +229,7 @@ static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, } static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size) + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info) { a2dp_sbc_t conf1, conf2; a2dp_sbc_t *conf; @@ -218,8 +238,8 @@ static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void bool xq = (strcmp(codec->name, "sbc_xq") == 0); /* Order selected configurations by preference */ - res1 = codec->select_config(codec, 0, caps1, caps1_size, NULL, (uint8_t *)&conf1); - res2 = codec->select_config(codec, 0, caps2, caps2_size, NULL, (uint8_t *)&conf2); + res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1); + res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2); #define PREFER_EXPR(expr) \ do { \ diff --git a/spa/plugins/bluez5/a2dp-codecs.c b/spa/plugins/bluez5/a2dp-codecs.c index 0f4587dc9..38dd809d3 100644 --- a/spa/plugins/bluez5/a2dp-codecs.c +++ b/spa/plugins/bluez5/a2dp-codecs.c @@ -10,7 +10,57 @@ #include "a2dp-codecs.h" -bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, const void *caps, size_t caps_size) +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; @@ -21,7 +71,7 @@ bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id if (caps == NULL) return false; - res = codec->select_config(codec, 0, caps, caps_size, NULL, config); + res = codec->select_config(codec, 0, caps, caps_size, info, NULL, config); if (res < 0) return false; diff --git a/spa/plugins/bluez5/a2dp-codecs.h b/spa/plugins/bluez5/a2dp-codecs.h index 0a79835e5..b2b2a16e9 100644 --- a/spa/plugins/bluez5/a2dp-codecs.h +++ b/spa/plugins/bluez5/a2dp-codecs.h @@ -293,35 +293,13 @@ typedef struct { #error "Unknown byte order" #endif -static inline int a2dp_sbc_get_channels(a2dp_sbc_t *config) -{ - switch (config->channel_mode) { - case SBC_CHANNEL_MODE_MONO: - return 1; - case SBC_CHANNEL_MODE_DUAL_CHANNEL: - case SBC_CHANNEL_MODE_STEREO: - case SBC_CHANNEL_MODE_JOINT_STEREO: - return 2; - default: - return -1; - } -} +#define A2DP_CODEC_DEFAULT_RATE 48000 +#define A2DP_CODEC_DEFAULT_CHANNELS 2 -static inline int a2dp_sbc_get_frequency(a2dp_sbc_t *config) -{ - switch (config->frequency) { - case SBC_SAMPLING_FREQ_16000: - return 16000; - case SBC_SAMPLING_FREQ_32000: - return 32000; - case SBC_SAMPLING_FREQ_44100: - return 44100; - case SBC_SAMPLING_FREQ_48000: - return 48000; - default: - return -1; - } -} +struct a2dp_codec_audio_info { + uint32_t rate; + uint32_t channels; +}; struct a2dp_codec_handle; @@ -342,6 +320,7 @@ struct a2dp_codec { uint8_t caps[A2DP_MAX_CAPS_SIZE]); int (*select_config) (const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, const struct spa_dict *settings, uint8_t config[A2DP_MAX_CAPS_SIZE]); int (*enum_config) (const struct a2dp_codec *codec, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, @@ -356,7 +335,7 @@ struct a2dp_codec { * otherwise not checked beforehand. */ int (*caps_preference_cmp) (const struct a2dp_codec *codec, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size); + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info); void *(*init_props) (const struct a2dp_codec *codec, const struct spa_dict *settings); void (*clear_props) (void *); @@ -394,6 +373,16 @@ struct a2dp_codec { extern const struct a2dp_codec **a2dp_codecs; -bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, const void *caps, size_t caps_size); +struct a2dp_codec_config { + uint32_t config; + int value; + unsigned int priority; +}; + +int a2dp_codec_select_config(const struct a2dp_codec_config configs[], size_t n, + uint32_t cap, int preferred_value); + +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); #endif diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 3b633d0e9..25288facb 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -91,6 +91,9 @@ struct spa_bt_monitor { unsigned int backend_native_registered:1; unsigned int backend_ofono_registered:1; unsigned int backend_hsphfpd_registered:1; + + /* A reference audio info for A2DP codec configuration. */ + struct a2dp_codec_audio_info default_audio_info; }; /* Stream endpoints owned by BlueZ for each device */ @@ -468,7 +471,7 @@ static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBu * This causes inconsistency with SelectConfiguration() triggered * by codec switching. */ - res = codec->select_config(codec, 0, cap, size, NULL, config); + res = codec->select_config(codec, 0, cap, size, &monitor->default_audio_info, NULL, config); else res = -ENOTSUP; @@ -1233,7 +1236,8 @@ bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struc } spa_list_for_each(ep, &device->remote_endpoint_list, device_link) { - if (a2dp_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len)) + if (a2dp_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, + &ep->monitor->default_audio_info)) return true; } @@ -2200,7 +2204,9 @@ static bool a2dp_codec_switch_process_current(struct spa_bt_a2dp_codec_switch *s goto next; } - res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, sw->device->settings, config); + res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, + &sw->device->monitor->default_audio_info, + sw->device->settings, config); if (res < 0) { spa_log_debug(sw->device->monitor->log, NAME": a2dp codec switch %p: incompatible capabilities (%d), try next", sw, res); @@ -2364,7 +2370,7 @@ static int a2dp_codec_switch_cmp(const void *a, const void *b) return -1; return codec->caps_preference_cmp(codec, ep1->capabilities, ep1->capabilities_len, - ep2->capabilities, ep2->capabilities_len); + ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info); } /* Ensure there's a transport for at least one of the listed codecs */ @@ -3860,13 +3866,25 @@ impl_init(const struct spa_handle_factory *factory, if ((res = parse_codec_array(this, info)) < 0) return res; + this->default_audio_info.rate = A2DP_CODEC_DEFAULT_RATE; + this->default_audio_info.channels = A2DP_CODEC_DEFAULT_CHANNELS; + if (info) { const char *str; + uint32_t tmp; if ((str = spa_dict_lookup(info, "api.bluez5.connection-info")) != NULL && (strcmp(str, "true") == 0 || atoi(str))) this->connection_info_supported = true; + if ((str = spa_dict_lookup(info, "bluez5.default.rate")) != NULL && + (tmp = atoi(str)) > 0) + this->default_audio_info.rate = tmp; + + if ((str = spa_dict_lookup(info, "bluez5.default.channels")) != NULL && + ((tmp = atoi(str)) > 0)) + this->default_audio_info.channels = tmp; + if ((str = spa_dict_lookup(info, "bluez5.sbc-xq-support")) != NULL && (strcmp(str, "true") == 0 || atoi(str))) this->enable_sbc_xq = true; diff --git a/src/daemon/media-session.d/bluez-monitor.conf b/src/daemon/media-session.d/bluez-monitor.conf index 901c8bd56..cbc6551ae 100644 --- a/src/daemon/media-session.d/bluez-monitor.conf +++ b/src/daemon/media-session.d/bluez-monitor.conf @@ -22,6 +22,10 @@ properties = { # Enabled A2DP codecs (default: all). #bluez5.codecs = [ sbc aac ldac aptx aptx_hd ] + + # Properties for the A2DP codec configuration + #bluez5.default.rate = 48000 + #bluez5.default.channels = 2 } rules = [