Arduino A2DP
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members
A2DPDecoderAAC Class Reference

AAC decode support for the managed A2DP decoder framework: wraps any audio_tools::AudioDecoder that decodes AAC - e.g. audio_tools::AACDecoderHelix (arduino-libhelix), AACDecoderFDK (arduino-fdk-aac) or AACDecoderFAAD (arduino-libfaad) - and advertises the AAC SEP capability. Construct your decoder of choice, include its codec header yourself (e.g. "AudioTools/AudioCodecs/CodecAACHelix.h"), and register an A2DPDecoderAAC wrapping it via BluetoothA2DPSink::add_decoder(). More...

#include <A2DPDecoderAAC.h>

Inheritance diagram for A2DPDecoderAAC:
A2DPDecoder

Public Member Functions

 A2DPDecoderAAC (audio_tools::AudioDecoder &decoder)
 
virtual bool begin (const esp_a2d_mcc_t &mcc)
 
void build_capability (esp_a2d_mcc_t &mcc) override
 Fills in the SEP capability advertised for this codec at registration.
 
esp_a2d_mct_t codec_type () override
 A2DP codec type this decoder handles (e.g. ESP_A2D_MCT_SBC)
 
virtual void end ()
 Closes the wrapped audio_tools decoder.
 
audio_tools::AudioInfo get_audio_info ()
 
const char * mime () override
 MIME type of the codec this decoder handles (e.g. "audio/sbc")
 
void set_he_aac (bool active)
 
size_t write (const uint8_t *data, size_t len) override
 

Protected Member Functions

void parse_audio_info (const esp_a2d_mcc_t &mcc) override
 
void write_adts_header (size_t adts_frame_len)
 

Static Protected Member Functions

static uint8_t adts_freq_idx (int rate)
 

Protected Attributes

int bits_per_sample = 16
 
int channels = 2
 
uint8_t freq_idx = 4
 
bool is_he_aac = false
 
audio_tools::AudioDecoder * p_decoder
 
audio_tools::CallbackStream pcm_stream
 
int sample_rate = 44100
 

Static Protected Attributes

static const int kAdtsHeaderSize = 7
 
static const int kAdtsMaxFrameLen = 8191
 

Detailed Description

AAC decode support for the managed A2DP decoder framework: wraps any audio_tools::AudioDecoder that decodes AAC - e.g. audio_tools::AACDecoderHelix (arduino-libhelix), AACDecoderFDK (arduino-fdk-aac) or AACDecoderFAAD (arduino-libfaad) - and advertises the AAC SEP capability. Construct your decoder of choice, include its codec header yourself (e.g. "AudioTools/AudioCodecs/CodecAACHelix.h"), and register an A2DPDecoderAAC wrapping it via BluetoothA2DPSink::add_decoder().

A2DP delivers raw AAC access units (ISO/IEC 13818-7 / 14496-3 raw_data_block()) with no ADTS header, but most general-purpose AAC decoders (including audio_tools::AACDecoderHelix) expect ADTS framing to find their sync word - so this class synthesizes a 7-byte ADTS header (from the sample rate/channel count negotiated via SEP configuration) and prepends it to every frame before handing it to the wrapped decoder.

By default only AAC-LC is advertised, because the synthesized ADTS header can only describe AAC-LC. Call set_he_aac(true) if the wrapped decoder detects HE-AAC (SBR/PS) implicitly from an AAC-LC labeled stream.

NOTE: registering a non-SBC stream endpoint is only supported by the underlying Bluedroid stack on ESP-IDF >= 6.1 - earlier versions document esp_a2d_sink_register_stream_endpoint() as SBC-only and are expected to reject this registration (see the ESP_A2D_SEP_REG_STATE_EVT log). This class still works on older IDF versions; it just won't get negotiated.

Author
Phil Schatzmann

Member Function Documentation

◆ adts_freq_idx()

static uint8_t A2DPDecoderAAC::adts_freq_idx ( int  rate)
inlinestaticprotected

maps a sample rate to its ADTS sampling_frequency_index; falls back to 44100's index if not one of the 13 well-known rates

◆ begin()

virtual bool A2DPDecoder::begin ( const esp_a2d_mcc_t &  mcc)
inlinevirtualinherited

Opens the wrapped audio_tools decoder for the negotiated SEP capability: calls parse_audio_info(mcc) (implemented per codec - most decoders self-detect sample rate/channels from the encoded stream and can leave sample_rate/channels at their defaults, but codecs whose wire format doesn't carry that info per-frame, e.g. AAC, need it to synthesize the framing their decoder expects - see A2DPDecoderAAC), then wires up the PCM output and audio-info-change notification and starts the decoder.

◆ build_capability()

void A2DPDecoderAAC::build_capability ( esp_a2d_mcc_t &  mcc)
inlineoverridevirtual

Fills in the SEP capability advertised for this codec at registration.

Implements A2DPDecoder.

◆ codec_type()

esp_a2d_mct_t A2DPDecoderAAC::codec_type ( )
inlineoverridevirtual

A2DP codec type this decoder handles (e.g. ESP_A2D_MCT_SBC)

Implements A2DPDecoder.

◆ get_audio_info()

audio_tools::AudioInfo A2DPDecoder::get_audio_info ( )
inlineinherited

Returns the most recently detected sample rate/channels (default AudioInfo values until the wrapped decoder has actually parsed them from the encoded stream)

◆ mime()

const char * A2DPDecoderAAC::mime ( )
inlineoverridevirtual

MIME type of the codec this decoder handles (e.g. "audio/sbc")

Implements A2DPDecoder.

◆ parse_audio_info()

void A2DPDecoderAAC::parse_audio_info ( const esp_a2d_mcc_t &  mcc)
inlineoverrideprotectedvirtual

determines sample_rate/channels/freq_idx from the negotiated AAC capability (a single bit is set per field once negotiation completes) - needed to synthesize the ADTS header, since AAC's raw frames don't carry this info themselves

Implements A2DPDecoder.

◆ set_he_aac()

void A2DPDecoderAAC::set_he_aac ( bool  active)
inline

Also advertise HE-AAC and HE-AAC v2 (default: false). Call before BluetoothA2DPSink::start().

◆ write()

size_t A2DPDecoderAAC::write ( const uint8_t *  data,
size_t  len 
)
inlineoverridevirtual

prepends a synthesized ADTS header to each frame, since A2DP AAC frames arrive as raw (headerless) access units but the wrapped decoder expects ADTS framing to find its sync word

Reimplemented from A2DPDecoder.

◆ write_adts_header()

void A2DPDecoderAAC::write_adts_header ( size_t  adts_frame_len)
inlineprotected

synthesizes a 7-byte ADTS header (no CRC) for an AAC-LC frame of the given total length (header + payload) at the negotiated sample rate/channel count. NOTE: the ADTS profile field is hardcoded to AAC-LC (profile=1) since it has no room to represent SBR/PS - if the source actually negotiates HE-AAC/HE-AAC v2 (advertised as negotiable in build_capability()), whether the wrapped decoder still recovers the SBR/PS extension from an LC-labeled ADTS stream depends on that decoder's implicit-signaling support and is untested here.


The documentation for this class was generated from the following file: