From 79ee1eaff0f780625b11f0e21257cfd62a2405e9 Mon Sep 17 00:00:00 2001 From: Adam Marcus Date: Sun, 21 Jan 2024 17:09:27 +0000 Subject: [PATCH] bluez5: add AAC-ELD codec --- spa/include/spa/param/bluetooth/audio.h | 1 + spa/include/spa/param/bluetooth/type-info.h | 1 + spa/plugins/bluez5/a2dp-codec-aac.c | 105 ++++++++++++++++---- spa/plugins/bluez5/a2dp-codec-caps.h | 1 + spa/plugins/bluez5/bluez5-dbus.c | 1 + spa/plugins/bluez5/codec-loader.c | 1 + 6 files changed, 88 insertions(+), 22 deletions(-) diff --git a/spa/include/spa/param/bluetooth/audio.h b/spa/include/spa/param/bluetooth/audio.h index 68c6b9f22..bc6e98d87 100644 --- a/spa/include/spa/param/bluetooth/audio.h +++ b/spa/include/spa/param/bluetooth/audio.h @@ -21,6 +21,7 @@ enum spa_bluetooth_audio_codec { SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_BLUETOOTH_AUDIO_CODEC_MPEG, SPA_BLUETOOTH_AUDIO_CODEC_AAC, + SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD, SPA_BLUETOOTH_AUDIO_CODEC_APTX, SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD, SPA_BLUETOOTH_AUDIO_CODEC_LDAC, diff --git a/spa/include/spa/param/bluetooth/type-info.h b/spa/include/spa/param/bluetooth/type-info.h index 6b166fde6..e8bf3718f 100644 --- a/spa/include/spa/param/bluetooth/type-info.h +++ b/spa/include/spa/param/bluetooth/type-info.h @@ -25,6 +25,7 @@ static const struct spa_type_info spa_type_bluetooth_audio_codec[] = { { SPA_BLUETOOTH_AUDIO_CODEC_SBC_XQ, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "sbc_xq", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_MPEG, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "mpeg", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_AAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aac", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aac_eld", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_APTX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "aptx_hd", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_LDAC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "ldac", NULL }, diff --git a/spa/plugins/bluez5/a2dp-codec-aac.c b/spa/plugins/bluez5/a2dp-codec-aac.c index e6ddcf156..4384c2d5b 100644 --- a/spa/plugins/bluez5/a2dp-codec-aac.c +++ b/spa/plugins/bluez5/a2dp-codec-aac.c @@ -45,10 +45,13 @@ struct impl { static int codec_fill_caps(const struct media_codec *codec, uint32_t flags, uint8_t caps[A2DP_MAX_CAPS_SIZE]) { + eld = spa_streq(codec->name, "aac_eld"); + static const a2dp_aac_t a2dp_aac = { .object_type = /* NOTE: AAC Long Term Prediction and AAC Scalable are * not supported by the FDK-AAC library. */ + eld ? AAC_OBJECT_TYPE_MPEG4_AAC_ELD : AAC_OBJECT_TYPE_MPEG2_AAC_LC | AAC_OBJECT_TYPE_MPEG4_AAC_LC, AAC_INIT_FREQUENCY( @@ -118,18 +121,27 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, if (caps_size < sizeof(conf)) return -EINVAL; + eld = spa_streq(codec->name, "aac_eld"); + conf = *(a2dp_aac_t*)caps; - if (conf.object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) - conf.object_type = AAC_OBJECT_TYPE_MPEG2_AAC_LC; - else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) - conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LC; - else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) - return -ENOTSUP; /* Not supported by FDK-AAC */ - else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA) - return -ENOTSUP; /* Not supported by FDK-AAC */ - else - return -ENOTSUP; + if (eld) { + if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_ELD) + conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_ELD; + else + return -ENOTSUP; + } else { + if (conf.object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) + conf.object_type = AAC_OBJECT_TYPE_MPEG2_AAC_LC; + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) + conf.object_type = AAC_OBJECT_TYPE_MPEG4_AAC_LC; + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LTP) + return -ENOTSUP; /* Not supported by FDK-AAC */ + else if (conf.object_type & AAC_OBJECT_TYPE_MPEG4_AAC_SCA) + return -ENOTSUP; /* Not supported by FDK-AAC */ + else + return -ENOTSUP; + } if ((i = media_codec_select_config(aac_frequencies, SPA_N_ELEMENTS(aac_frequencies), @@ -233,6 +245,8 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags if (caps == NULL || caps_size < sizeof(conf)) return -EINVAL; + eld = spa_streq(codec->name, "aac_eld"); + memcpy(&conf, caps, sizeof(conf)); spa_zero(*info); @@ -246,9 +260,14 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags * bits for AAC object type. It's not clear if this was due to * a BlueZ bug, but we can be lax here and below in codec_init. */ - if (!(conf.object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC | - AAC_OBJECT_TYPE_MPEG4_AAC_LC))) - return -EINVAL; + if (eld) { + if (!(conf.object_type & AAC_OBJECT_TYPE_MPEG2_AAC_ELD)) + return -EINVAL; + } else { + if (!(conf.object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC | + AAC_OBJECT_TYPE_MPEG4_AAC_LC))) + return -EINVAL; + } j = 0; SPA_FOR_EACH_ELEMENT_VAR(aac_frequencies, f) { if (AAC_GET_FREQUENCY(conf) & f->config) { @@ -304,6 +323,8 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags, UINT bitratemode; int res; + eld = spa_streq(codec->name, "aac_eld"); + this = calloc(1, sizeof(struct impl)); if (this == NULL) { res = -errno; @@ -327,15 +348,30 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags, if (res != AACENC_OK) goto error; - if (!(conf->object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC | - AAC_OBJECT_TYPE_MPEG4_AAC_LC))) { - res = -EINVAL; - goto error; - } + if (eld) { + if (!(conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_ELD)) { + res = -EINVAL; + goto error; + } - res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC); - if (res != AACENC_OK) - goto error; + res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_ER_AAC_ELD); + if (res != AACENC_OK) + goto error; + + res = aacEncoder_SetParam(this->aacenc, AACENC_SBR_MODE, 1); + if (res != AACENC_OK) + goto error; + } else { + if (!(conf->object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC | + AAC_OBJECT_TYPE_MPEG4_AAC_LC))) { + res = -EINVAL; + goto error; + } + + res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC); + if (res != AACENC_OK) + goto error; + } res = aacEncoder_SetParam(this->aacenc, AACENC_SAMPLERATE, this->rate); if (res != AACENC_OK) @@ -632,7 +668,32 @@ const struct media_codec a2dp_codec_aac = { .set_log = codec_set_log, }; +const struct media_codec a2dp_codec_aac_eld = { + .id = SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD, + .codec_id = A2DP_CODEC_MPEG24, + .name = "aac_eld", + .description = "AAC-ELD", + .fill_caps = codec_fill_caps, + .select_config = codec_select_config, + .enum_config = codec_enum_config, + .validate_config = codec_validate_config, + .init_props = codec_init_props, + .clear_props = codec_clear_props, + .init = codec_init, + .deinit = codec_deinit, + .get_block_size = codec_get_block_size, + .start_encode = codec_start_encode, + .encode = codec_encode, + .start_decode = codec_start_decode, + .decode = codec_decode, + .abr_process = codec_abr_process, + .reduce_bitpool = codec_reduce_bitpool, + .increase_bitpool = codec_increase_bitpool, + .set_log = codec_set_log, +}; + MEDIA_CODEC_EXPORT_DEF( "aac", - &a2dp_codec_aac + &a2dp_codec_aac, + &a2dp_codec_aac_eld ); diff --git a/spa/plugins/bluez5/a2dp-codec-caps.h b/spa/plugins/bluez5/a2dp-codec-caps.h index 9f7259296..2a9b06734 100644 --- a/spa/plugins/bluez5/a2dp-codec-caps.h +++ b/spa/plugins/bluez5/a2dp-codec-caps.h @@ -101,6 +101,7 @@ #define AAC_OBJECT_TYPE_MPEG4_AAC_LC 0x40 #define AAC_OBJECT_TYPE_MPEG4_AAC_LTP 0x20 #define AAC_OBJECT_TYPE_MPEG4_AAC_SCA 0x10 +#define AAC_OBJECT_TYPE_MPEG4_AAC_ELD 0x02 #define AAC_SAMPLING_FREQ_8000 0x0800 #define AAC_SAMPLING_FREQ_11025 0x0400 diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index 928a4d665..7f0cbb937 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -3167,6 +3167,7 @@ int64_t spa_bt_transport_get_delay_nsec(struct spa_bt_transport *t) return 150 * SPA_NSEC_PER_MSEC; case SPA_BLUETOOTH_AUDIO_CODEC_LDAC: return 175 * SPA_NSEC_PER_MSEC; + case SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD: case SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL: case SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX: case SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM: diff --git a/spa/plugins/bluez5/codec-loader.c b/spa/plugins/bluez5/codec-loader.c index ac05d3c60..47970d295 100644 --- a/spa/plugins/bluez5/codec-loader.c +++ b/spa/plugins/bluez5/codec-loader.c @@ -35,6 +35,7 @@ static int codec_order(const struct media_codec *c) SPA_BLUETOOTH_AUDIO_CODEC_LDAC, SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD, SPA_BLUETOOTH_AUDIO_CODEC_APTX, + SPA_BLUETOOTH_AUDIO_CODEC_AAC_ELD, SPA_BLUETOOTH_AUDIO_CODEC_AAC, SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR, SPA_BLUETOOTH_AUDIO_CODEC_MPEG,