Skip to content

Commit

Permalink
Select only A2DP features supported by BlueALSA
Browse files Browse the repository at this point in the history
Fixes #609
  • Loading branch information
arkq committed Jan 2, 2023
1 parent dfaaf20 commit fc91d28
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 71 deletions.
21 changes: 18 additions & 3 deletions src/a2dp-aac.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* BlueALSA - a2dp-aac.c
* Copyright (c) 2016-2022 Arkadiusz Bokowy
* Copyright (c) 2016-2023 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
Expand Down Expand Up @@ -63,7 +63,7 @@ struct a2dp_codec a2dp_aac_sink = {
.dir = A2DP_SINK,
.codec_id = A2DP_CODEC_MPEG24,
.capabilities.aac = {
/* NOTE: AAC Long Term Prediction and AAC Scalable are
/* NOTE: AAC Long Term Prediction and AAC Scalable might be
* not supported by the FDK-AAC library. */
.object_type =
AAC_OBJECT_TYPE_MPEG2_AAC_LC |
Expand Down Expand Up @@ -99,7 +99,7 @@ struct a2dp_codec a2dp_aac_source = {
.dir = A2DP_SOURCE,
.codec_id = A2DP_CODEC_MPEG24,
.capabilities.aac = {
/* NOTE: AAC Long Term Prediction and AAC Scalable are
/* NOTE: AAC Long Term Prediction and AAC Scalable might be
* not supported by the FDK-AAC library. */
.object_type =
AAC_OBJECT_TYPE_MPEG2_AAC_LC |
Expand Down Expand Up @@ -133,6 +133,21 @@ struct a2dp_codec a2dp_aac_source = {

void a2dp_aac_init(void) {

LIB_INFO info[16] = { 0 };
info[ARRAYSIZE(info) - 1].module_id = ~FDK_NONE;

aacDecoder_GetLibInfo(info);
aacEncGetLibInfo(info);

unsigned int caps_dec = FDKlibInfo_getCapabilities(info, FDK_AACDEC);
unsigned int caps_enc = FDKlibInfo_getCapabilities(info, FDK_AACENC);
debug("FDK-AAC lib capabilities: dec:%#x enc:%#x", caps_dec, caps_enc);

if (caps_dec & CAPF_ER_AAC_SCAL)
a2dp_aac_sink.capabilities.aac.object_type |= AAC_OBJECT_TYPE_MPEG4_AAC_SCA;
if (caps_enc & CAPF_ER_AAC_SCAL)
a2dp_aac_source.capabilities.aac.object_type |= AAC_OBJECT_TYPE_MPEG4_AAC_SCA;

if (config.a2dp.force_mono)
a2dp_aac_source.capabilities.aac.channels = AAC_CHANNELS_1;
if (config.a2dp.force_44100)
Expand Down
146 changes: 78 additions & 68 deletions src/a2dp.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* BlueALSA - a2dp.c
* Copyright (c) 2016-2022 Arkadiusz Bokowy
* Copyright (c) 2016-2023 Arkadiusz Bokowy
*
* This file is a part of bluez-alsa.
*
Expand Down Expand Up @@ -628,15 +628,21 @@ int a2dp_select_configuration(
return errno = EINVAL, -1;
}

a2dp_t tmp;
/* save original capabilities blob for later */
memcpy(&tmp, capabilities, size);

/* Narrow capabilities to values supported by BlueALSA. */
if (a2dp_filter_capabilities(codec, capabilities, size) != 0)
return -1;

switch (codec->codec_id) {
case A2DP_CODEC_SBC: {

a2dp_sbc_t *cap = capabilities;
unsigned int cap_chm = cap->channel_mode;
unsigned int cap_freq = cap->frequency;

const unsigned int cap_chm = cap->channel_mode;
if ((cap->channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("SBC: No supported channel modes: %#x", cap_chm);
error("SBC: No supported channel modes: %#x", tmp.sbc.channel_mode);
goto fail;
}

Expand All @@ -645,72 +651,77 @@ int a2dp_select_configuration(
if (cap_chm & SBC_CHANNEL_MODE_DUAL_CHANNEL)
cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
else
warn("SBC XQ: Dual channel mode not supported: %#x", cap_chm);
warn("SBC XQ: Dual channel mode not supported: %#x", tmp.sbc.channel_mode);
}

const unsigned int cap_freq = cap->frequency;
if ((cap->frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("SBC: No supported sampling frequencies: %#x", cap_freq);
error("SBC: No supported sampling frequencies: %#x", tmp.sbc.frequency);
goto fail;
}

if (cap->block_length & SBC_BLOCK_LENGTH_16)
const uint8_t cap_block_length = cap->block_length;
if (cap_block_length & SBC_BLOCK_LENGTH_16)
cap->block_length = SBC_BLOCK_LENGTH_16;
else if (cap->block_length & SBC_BLOCK_LENGTH_12)
else if (cap_block_length & SBC_BLOCK_LENGTH_12)
cap->block_length = SBC_BLOCK_LENGTH_12;
else if (cap->block_length & SBC_BLOCK_LENGTH_8)
else if (cap_block_length & SBC_BLOCK_LENGTH_8)
cap->block_length = SBC_BLOCK_LENGTH_8;
else if (cap->block_length & SBC_BLOCK_LENGTH_4)
else if (cap_block_length & SBC_BLOCK_LENGTH_4)
cap->block_length = SBC_BLOCK_LENGTH_4;
else {
error("SBC: No supported block lengths: %#x", cap->block_length);
error("SBC: No supported block lengths: %#x", tmp.sbc.block_length);
goto fail;
}

if (cap->subbands & SBC_SUBBANDS_8)
const uint8_t cap_subbands = cap->subbands;
if (cap_subbands & SBC_SUBBANDS_8)
cap->subbands = SBC_SUBBANDS_8;
else if (cap->subbands & SBC_SUBBANDS_4)
else if (cap_subbands & SBC_SUBBANDS_4)
cap->subbands = SBC_SUBBANDS_4;
else {
error("SBC: No supported sub-bands: %#x", cap->subbands);
error("SBC: No supported sub-bands: %#x", tmp.sbc.subbands);
goto fail;
}

if (cap->allocation_method & SBC_ALLOCATION_LOUDNESS)
const uint8_t cap_allocation_method = cap->allocation_method;
if (cap_allocation_method & SBC_ALLOCATION_LOUDNESS)
cap->allocation_method = SBC_ALLOCATION_LOUDNESS;
else if (cap->allocation_method & SBC_ALLOCATION_SNR)
else if (cap_allocation_method & SBC_ALLOCATION_SNR)
cap->allocation_method = SBC_ALLOCATION_SNR;
else {
error("SBC: No supported allocation method: %#x", cap->allocation_method);
error("SBC: No supported allocation method: %#x", tmp.sbc.allocation_method);
goto fail;
}

cap->min_bitpool = MAX(codec->capabilities.sbc.min_bitpool, cap->min_bitpool);
cap->max_bitpool = MIN(codec->capabilities.sbc.max_bitpool, cap->max_bitpool);

break;
}

#if ENABLE_MPEG
case A2DP_CODEC_MPEG12: {

a2dp_mpeg_t *cap = capabilities;
unsigned int cap_chm = cap->channel_mode;
unsigned int cap_freq = cap->frequency;

if (cap->layer & MPEG_LAYER_MP3)
const uint8_t cap_layer = cap->layer;
if (cap_layer & MPEG_LAYER_MP3)
cap->layer = MPEG_LAYER_MP3;
else if (cap_layer & MPEG_LAYER_MP2)
cap->layer = MPEG_LAYER_MP2;
else if (cap_layer & MPEG_LAYER_MP1)
cap->layer = MPEG_LAYER_MP1;
else {
error("MPEG: No supported layer: %#x", cap->layer);
error("MPEG: No supported layer: %#x", tmp.mpeg.layer);
goto fail;
}

const unsigned int cap_chm = cap->channel_mode;
if ((cap->channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("MPEG: No supported channel modes: %#x", cap_chm);
error("MPEG: No supported channel modes: %#x", tmp.mpeg.channel_mode);
goto fail;
}

const unsigned int cap_freq = cap->frequency;
if ((cap->frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("MPEG: No supported sampling frequencies: %#x", cap_freq);
error("MPEG: No supported sampling frequencies: %#x", tmp.mpeg.frequency);
goto fail;
}

Expand All @@ -725,34 +736,34 @@ int a2dp_select_configuration(

#if ENABLE_AAC
case A2DP_CODEC_MPEG24: {

a2dp_aac_t *cap = capabilities;
unsigned int cap_chm = cap->channels;
unsigned int cap_freq = AAC_GET_FREQUENCY(*cap);

if (cap->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA)
const uint8_t cap_object_type = cap->object_type;
if (cap_object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA)
cap->object_type = AAC_OBJECT_TYPE_MPEG4_AAC_SCA;
else if (cap->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP)
else if (cap_object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP)
cap->object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LTP;
else if (cap->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC)
else if (cap_object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC)
cap->object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LC;
else if (cap->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC)
else if (cap_object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC)
cap->object_type = AAC_OBJECT_TYPE_MPEG2_AAC_LC;
else {
error("AAC: No supported object type: %#x", cap->object_type);
error("AAC: No supported object type: %#x", tmp.aac.object_type);
goto fail;
}

const unsigned int cap_chm = cap->channels;
if ((cap->channels = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("AAC: No supported channels: %#x", cap_chm);
error("AAC: No supported channels: %#x", tmp.aac.channels);
goto fail;
}

unsigned int freq;
const unsigned int cap_freq = AAC_GET_FREQUENCY(*cap);
if ((freq = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) != 0)
AAC_SET_FREQUENCY(*cap, freq);
else {
error("AAC: No supported sampling frequencies: %#x", cap_freq);
error("AAC: No supported sampling frequencies: %#x", AAC_GET_FREQUENCY(tmp.aac));
goto fail;
}

Expand All @@ -772,18 +783,17 @@ int a2dp_select_configuration(

#if ENABLE_APTX
case A2DP_CODEC_VENDOR_APTX: {

a2dp_aptx_t *cap = capabilities;
unsigned int cap_chm = cap->channel_mode;
unsigned int cap_freq = cap->frequency;

const unsigned int cap_chm = cap->channel_mode;
if ((cap->channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("apt-X: No supported channel modes: %#x", cap_chm);
error("apt-X: No supported channel modes: %#x", tmp.aptx.channel_mode);
goto fail;
}

const unsigned int cap_freq = cap->frequency;
if ((cap->frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("apt-X: No supported sampling frequencies: %#x", cap_freq);
error("apt-X: No supported sampling frequencies: %#x", tmp.aptx.frequency);
goto fail;
}

Expand All @@ -793,18 +803,17 @@ int a2dp_select_configuration(

#if ENABLE_APTX_HD
case A2DP_CODEC_VENDOR_APTX_HD: {

a2dp_aptx_hd_t *cap = capabilities;
unsigned int cap_chm = cap->aptx.channel_mode;
unsigned int cap_freq = cap->aptx.frequency;

const unsigned int cap_chm = cap->aptx.channel_mode;
if ((cap->aptx.channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("apt-X HD: No supported channel modes: %#x", cap_chm);
error("apt-X HD: No supported channel modes: %#x", tmp.aptx_hd.aptx.channel_mode);
goto fail;
}

const unsigned int cap_freq = cap->aptx.frequency;
if ((cap->aptx.frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("apt-X HD: No supported sampling frequencies: %#x", cap_freq);
error("apt-X HD: No supported sampling frequencies: %#x", tmp.aptx_hd.aptx.frequency);
goto fail;
}

Expand All @@ -814,23 +823,24 @@ int a2dp_select_configuration(

#if ENABLE_FASTSTREAM
case A2DP_CODEC_VENDOR_FASTSTREAM: {

a2dp_faststream_t *cap = capabilities;
unsigned int cap_freq = cap->frequency_music;
unsigned int cap_freq_bc = cap->frequency_voice;

const unsigned int cap_freq = cap->frequency_music;
if ((cap->frequency_music = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("FastStream: No supported sampling frequencies: %#x", cap_freq);
error("FastStream: No supported sampling frequencies: %#x",
tmp.faststream.frequency_music);
goto fail;
}

const unsigned int cap_freq_bc = cap->frequency_voice;
if ((cap->frequency_voice = a2dp_codec_select_sampling_freq(codec, cap_freq_bc, true)) == 0) {
error("FastStream: No supported back-channel sampling frequencies: %#x", cap_freq_bc);
error("FastStream: No supported back-channel sampling frequencies: %#x",
tmp.faststream.frequency_voice);
goto fail;
}

if ((cap->direction & (FASTSTREAM_DIRECTION_MUSIC | FASTSTREAM_DIRECTION_VOICE)) == 0) {
error("FastStream: No supported directions: %#x", cap->direction);
error("FastStream: No supported directions: %#x", tmp.faststream.direction);
}

break;
Expand All @@ -839,32 +849,33 @@ int a2dp_select_configuration(

#if ENABLE_LC3PLUS
case A2DP_CODEC_VENDOR_LC3PLUS: {

a2dp_lc3plus_t *cap = capabilities;
unsigned int cap_chm = cap->channels;
unsigned int cap_freq = LC3PLUS_GET_FREQUENCY(*cap);

if (cap->frame_duration & LC3PLUS_FRAME_DURATION_100)
const uint8_t cap_frame_duration = cap->object_type;
if (cap_frame_duration & LC3PLUS_FRAME_DURATION_100)
cap->frame_duration = LC3PLUS_FRAME_DURATION_100;
else if (cap->frame_duration & LC3PLUS_FRAME_DURATION_050)
else if (cap_frame_duration & LC3PLUS_FRAME_DURATION_050)
cap->frame_duration = LC3PLUS_FRAME_DURATION_050;
else if (cap->frame_duration & LC3PLUS_FRAME_DURATION_025)
else if (cap_frame_duration & LC3PLUS_FRAME_DURATION_025)
cap->frame_duration = LC3PLUS_FRAME_DURATION_025;
else {
error("LC3plus: No supported frame duration: %#x", cap->frame_duration);
error("LC3plus: No supported frame duration: %#x", tmp.lc3plus.frame_duration);
goto fail;
}

const unsigned int cap_chm = cap->channels;
if ((cap->channels = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("LC3plus: No supported channels: %#x", cap_chm);
error("LC3plus: No supported channels: %#x", tmp.lc3plus.channels);
goto fail;
}

unsigned int freq;
const unsigned int cap_freq = LC3PLUS_GET_FREQUENCY(*cap);
if ((freq = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) != 0)
LC3PLUS_SET_FREQUENCY(*cap, freq);
else {
error("LC3plus: No supported sampling frequencies: %#x", cap_freq);
error("LC3plus: No supported sampling frequencies: %#x",
LC3PLUS_GET_FREQUENCY(tmp.lc3plus));
goto fail;
}

Expand All @@ -874,18 +885,17 @@ int a2dp_select_configuration(

#if ENABLE_LDAC
case A2DP_CODEC_VENDOR_LDAC: {

a2dp_ldac_t *cap = capabilities;
unsigned int cap_chm = cap->channel_mode;
unsigned int cap_freq = cap->frequency;

const unsigned int cap_chm = cap->channel_mode;
if ((cap->channel_mode = a2dp_codec_select_channel_mode(codec, cap_chm, false)) == 0) {
error("LDAC: No supported channel modes: %#x", cap_chm);
error("LDAC: No supported channel modes: %#x", tmp.ldac.channel_mode);
goto fail;
}

const unsigned int cap_freq = cap->frequency;
if ((cap->frequency = a2dp_codec_select_sampling_freq(codec, cap_freq, false)) == 0) {
error("LDAC: No supported sampling frequencies: %#x", cap_freq);
error("LDAC: No supported sampling frequencies: %#x", tmp.ldac.frequency);
goto fail;
}

Expand Down
Loading

0 comments on commit fc91d28

Please sign in to comment.