@@ -44,6 +44,23 @@ extern "C" void ccall_av_hdl_a2d_evt(uint16_t event, void *param) {
4444 }
4545}
4646
47+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
48+ extern " C" void ccall_audio_encoded_callback (esp_a2d_conn_hdl_t conn_hdl,
49+ esp_a2d_audio_buff_t *audio_buf) {
50+ ESP_LOGI (BT_AV_TAG, " ccall_audio_encoded_callback" );
51+ if (actual_bluetooth_a2dp_sink &&
52+ actual_bluetooth_a2dp_sink->encoded_stream_reader && audio_buf) {
53+ // pass raw encoded bytes
54+ ESP_LOGI (BT_AV_TAG, " encoded_stream_reader=%d" , (int )audio_buf->data_len );
55+ actual_bluetooth_a2dp_sink->encoded_stream_reader (audio_buf->data ,
56+ audio_buf->data_len );
57+ }
58+ if (audio_buf) {
59+ esp_a2d_audio_buff_free (audio_buf);
60+ }
61+ }
62+ #endif
63+
4764/* *
4865 * Constructor
4966 */
@@ -132,7 +149,6 @@ void BluetoothA2DPSink::start(const char *name) {
132149 // Initialize NVS
133150 init_nvs ();
134151 if (is_autoreconnect_allowed) {
135-
136152 // reconnect management
137153 // grab last connnectiom, even if we dont use it now for auto reconnect
138154 get_last_connection ();
@@ -192,6 +208,83 @@ void BluetoothA2DPSink::init_i2s() {
192208
193209esp_a2d_mct_t BluetoothA2DPSink::get_audio_type () { return audio_type; }
194210
211+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
212+
213+ bool BluetoothA2DPSink::set_codec (A2DPCodec codec,
214+ void (*encoded_cb)(const uint8_t *data,
215+ size_t len)) {
216+ encoded_stream_reader = encoded_cb;
217+ ESP_LOGI (BT_AV_TAG, " set_codec() called with codec=%d" , codec);
218+ is_output = false ;
219+ desired_codec = codec;
220+ ESP_LOGD (BT_AV_TAG, " set_codec: is_bluedroid_initialized=%d" ,
221+ is_bluedroid_initialized);
222+ if (!is_bluedroid_initialized) {
223+ ESP_LOGD (BT_AV_TAG,
224+ " set_codec: will register later (bluetooth not initialized)" );
225+ return true ; // will register later
226+ }
227+ ESP_LOGD (BT_AV_TAG, " set_codec: codec_sep_registered=%d" ,
228+ codec_sep_registered);
229+ if (codec_sep_registered) {
230+ ESP_LOGD (BT_AV_TAG, " set_codec: SEP already registered" );
231+ return true ;
232+ }
233+ esp_a2d_mcc_t mcc{};
234+ ESP_LOGD (BT_AV_TAG, " set_codec: preparing mcc struct" );
235+ switch (codec) {
236+ case A2DP_CODEC_SBC:
237+ mcc.type = ESP_A2D_MCT_SBC;
238+ mcc.cie .sbc_info .samp_freq =
239+ ESP_A2D_SBC_CIE_SF_44K | ESP_A2D_SBC_CIE_SF_48K;
240+ mcc.cie .sbc_info .ch_mode =
241+ ESP_A2D_SBC_CIE_CH_MODE_STEREO | ESP_A2D_SBC_CIE_CH_MODE_JOINT_STEREO;
242+ mcc.cie .sbc_info .block_len = ESP_A2D_SBC_CIE_BLOCK_LEN_16;
243+ mcc.cie .sbc_info .alloc_mthd = ESP_A2D_SBC_CIE_ALLOC_MTHD_LOUDNESS;
244+ mcc.cie .sbc_info .num_subbands = ESP_A2D_SBC_CIE_NUM_SUBBANDS_8;
245+ mcc.cie .sbc_info .min_bitpool = 2 ;
246+ mcc.cie .sbc_info .max_bitpool = 250 ;
247+ break ;
248+ case A2DP_CODEC_M12:
249+ mcc.type = ESP_A2D_MCT_M12; // may not be supported
250+ break ;
251+ case A2DP_CODEC_AAC:
252+ mcc.type = ESP_A2D_MCT_M24; // AAC (MPEG-2/4) - may not be supported
253+ break ;
254+ case A2DP_CODEC_ATRAC:
255+ mcc.type = ESP_A2D_MCT_ATRAC; // may not be supported
256+ break ;
257+ }
258+ ESP_LOGI (BT_AV_TAG,
259+ " set_codec: calling esp_a2d_sink_register_stream_endpoint" );
260+ esp_err_t err = esp_a2d_sink_register_stream_endpoint (0 , &mcc);
261+ ESP_LOGD (BT_AV_TAG,
262+ " set_codec: esp_a2d_sink_register_stream_endpoint returned %d" , err);
263+ if (err == ESP_OK) {
264+ codec_sep_registered = true ;
265+ ESP_LOGI (BT_AV_TAG, " Registered SEP for codec type %d" , mcc.type );
266+ if (encoded_cb) {
267+ ESP_LOGD (BT_AV_TAG, " set_codec: encoded_cb provided" );
268+ esp_err_t cb_err = esp_a2d_sink_register_audio_data_callback (
269+ ccall_audio_encoded_callback);
270+ ESP_LOGI (
271+ BT_AV_TAG,
272+ " set_codec: esp_a2d_sink_register_audio_data_callback returned %d" ,
273+ cb_err);
274+ if (cb_err != ESP_OK) {
275+ ESP_LOGW (BT_AV_TAG, " Failed to register encoded audio callback" );
276+ }
277+ }
278+
279+ return true ;
280+ } else {
281+ ESP_LOGW (BT_AV_TAG, " Failed to register SEP codec %d err=%d" , mcc.type ,
282+ err);
283+ return false ;
284+ }
285+ }
286+ #endif
287+
195288#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
196289const char *BluetoothA2DPSink::get_connected_source_name () {
197290 if (is_connected ()) {
@@ -409,9 +502,20 @@ void BluetoothA2DPSink::app_rc_ct_callback(esp_avrc_ct_cb_event_t event,
409502 sizeof (esp_avrc_ct_cb_param_t ));
410503 break ;
411504 }
505+ #endif
506+
507+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
412508
509+ case ESP_AVRC_CT_PROF_STATE_EVT: {
510+ ESP_LOGD (BT_AV_TAG, " %s ESP_AVRC_CT_PROF_STATE_EVT" ,
511+ __func__);
512+ app_work_dispatch (ccall_av_hdl_avrc_evt, event, param,
513+ sizeof (esp_avrc_ct_cb_param_t ));
514+ break ;
515+ }
413516#endif
414517
518+
415519 default :
416520 ESP_LOGE (BT_AV_TAG, " Invalid AVRC event: %d" , event);
417521 break ;
@@ -465,26 +569,77 @@ void BluetoothA2DPSink::handle_audio_cfg(uint16_t event, void *p_param) {
465569 a2d->audio_cfg .mcc .type );
466570
467571 // determine sample rate
468- m_sample_rate = 16000 ;
572+ int sample_rate = 0 ;
573+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
574+ // Use new sbc_info (avoid deprecated sbc[] array)
575+ uint8_t sf = a2d->audio_cfg .mcc .cie .sbc_info .samp_freq ;
576+ #ifdef ESP_A2D_SBC_CIE_SF_32K
577+ if (sf & ESP_A2D_SBC_CIE_SF_32K) {
578+ sample_rate = 32000 ;
579+ } else
580+ #endif
581+ if (sf & ESP_A2D_SBC_CIE_SF_44K) {
582+ sample_rate = 44100 ;
583+ } else if (sf & ESP_A2D_SBC_CIE_SF_48K) {
584+ sample_rate = 48000 ;
585+ }
586+ #else
587+ // Legacy field parsing (older IDF)
469588 char oct0 = a2d->audio_cfg .mcc .cie .sbc [0 ];
470589 if (oct0 & (0x01 << 6 )) {
471- m_sample_rate = 32000 ;
590+ sample_rate = 32000 ;
472591 } else if (oct0 & (0x01 << 5 )) {
473- m_sample_rate = 44100 ;
592+ sample_rate = 44100 ;
474593 } else if (oct0 & (0x01 << 4 )) {
475- m_sample_rate = 48000 ;
476- }
477- ESP_LOGI (BT_AV_TAG, " a2dp audio_cfg_cb , sample_rate %d" , m_sample_rate);
478- if (sample_rate_callback != nullptr ) {
479- sample_rate_callback (m_sample_rate);
594+ sample_rate = 48000 ;
480595 }
596+ #endif
481597
482598 // for now only SBC stream is supported
483599 if (a2d->audio_cfg .mcc .type == ESP_A2D_MCT_SBC) {
600+ // determine channel count from negotiated SBC channel mode
601+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
602+ uint8_t ch_mode = a2d->audio_cfg .mcc .cie .sbc_info .ch_mode ;
603+ if (ch_mode == ESP_A2D_SBC_CIE_CH_MODE_MONO) {
604+ m_channels = 1 ;
605+ } else {
606+ m_channels = 2 ; // dual/stereo/joint are all rendered as 2 channels
607+ }
608+ #else
609+ // legacy parsing: octet 1 bits 0..3 represent channel mode; only one is set
610+ uint8_t oct1 = a2d->audio_cfg .mcc .cie .sbc [1 ];
611+ // Bit masks per A2DP spec for channel mode (mono bit3, dual bit2, stereo
612+ // bit1, joint bit0)
613+ if (oct1 & 0x08 ) {
614+ m_channels = 1 ; // mono
615+ } else {
616+ m_channels = 2 ; // any other mode
617+ }
618+ #endif
619+ ESP_LOGI (BT_AV_TAG, " a2dp audio_cfg_cb , channels %d" , m_channels);
620+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
484621 ESP_LOGI (BT_AV_TAG, " configure audio player %x-%x-%x-%x\n " ,
485- a2d->audio_cfg .mcc .cie .sbc [0 ], a2d->audio_cfg .mcc .cie .sbc [1 ],
486- a2d->audio_cfg .mcc .cie .sbc [2 ], a2d->audio_cfg .mcc .cie .sbc [3 ]);
622+ (int )a2d->audio_cfg .mcc .cie .sbc_info .samp_freq ,
623+ (int )a2d->audio_cfg .mcc .cie .sbc_info .ch_mode ,
624+ (int )a2d->audio_cfg .mcc .cie .sbc_info .block_len ,
625+ (int )a2d->audio_cfg .mcc .cie .sbc_info .alloc_mthd );
626+ #else
627+ ESP_LOGI (
628+ BT_AV_TAG, " configure audio player %x-%x-%x-%x\n " ,
629+ (int )a2d->audio_cfg .mcc .cie .sbc [0 ], (int )a2d->audio_cfg .mcc .cie .sbc [1 ],
630+ (int )a2d->audio_cfg .mcc .cie .sbc [2 ], (int )a2d->audio_cfg .mcc .cie .sbc [3 ]);
631+ #endif
487632
633+ ESP_LOGI (BT_AV_TAG, " a2dp audio_cfg_cb , sample_rate %u" , m_sample_rate);
634+ }
635+
636+ // inform caller about new values
637+ if (sample_rate != 0 ) {
638+ m_sample_rate = sample_rate;
639+ // act on determined data
640+ if (sample_rate_callback != nullptr ) {
641+ sample_rate_callback (m_sample_rate);
642+ }
488643 out->set_sample_rate (m_sample_rate);
489644 }
490645}
@@ -831,6 +986,22 @@ void BluetoothA2DPSink::av_hdl_avrc_evt(uint16_t event, void *p_param) {
831986
832987#endif
833988
989+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
990+
991+ /* when avrcp controller init or deinit completed, this event comes */
992+ case ESP_AVRC_CT_PROF_STATE_EVT: {
993+ if (ESP_AVRC_INIT_SUCCESS == rc->avrc_ct_init_stat .state ) {
994+ ESP_LOGI (BT_RC_CT_TAG, " AVRCP CT STATE: Init Complete" );
995+ } else if (ESP_AVRC_DEINIT_SUCCESS == rc->avrc_ct_init_stat .state ) {
996+ ESP_LOGI (BT_RC_CT_TAG, " AVRCP CT STATE: Deinit Complete" );
997+ } else {
998+ ESP_LOGE (BT_RC_CT_TAG, " AVRCP CT STATE error: %d" , rc->avrc_ct_init_stat .state );
999+ }
1000+ break ;
1001+ }
1002+ #endif
1003+
1004+
8341005 default :
8351006 ESP_LOGE (BT_AV_TAG, " %s unhandled evt %d" , __func__, event);
8361007 break ;
@@ -893,6 +1064,13 @@ void BluetoothA2DPSink::av_hdl_stack_evt(uint16_t event, void *p_param) {
8931064 ESP_LOGE (BT_AV_TAG, " esp_a2d_sink_init" );
8941065 }
8951066
1067+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
1068+ // Register only later when user sets a callback
1069+ if (!codec_sep_registered && encoded_stream_reader != nullptr ) {
1070+ set_codec (desired_codec, encoded_stream_reader);
1071+ }
1072+ #endif
1073+
8961074 // start automatic reconnect if relevant and stack is up
8971075 if (reconnect_status == AutoReconnect && has_last_connection ()) {
8981076 ESP_LOGD (BT_AV_TAG, " reconnect" );
@@ -1105,8 +1283,7 @@ size_t BluetoothA2DPSink::i2s_write_data(const uint8_t *data,
11051283 int open = item_size;
11061284 int processed = 0 ;
11071285 while (open > 0 ) {
1108- int written =
1109- out->write (data + processed, std::min (open, max_write_size));
1286+ int written = out->write (data + processed, std::min (open, max_write_size));
11101287 open -= written;
11111288 processed += written;
11121289 // add some delay between the writes
@@ -1129,7 +1306,10 @@ void BluetoothA2DPSink::app_rc_tg_callback(esp_avrc_tg_cb_event_t event,
11291306 case ESP_AVRC_TG_PASSTHROUGH_CMD_EVT:
11301307 case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
11311308 case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT:
1132- case ESP_AVRC_TG_SET_PLAYER_APP_VALUE_EVT: {
1309+ case ESP_AVRC_TG_SET_PLAYER_APP_VALUE_EVT:
1310+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
1311+ case ESP_AVRC_TG_PROF_STATE_EVT: {
1312+ #endif
11331313 app_work_dispatch (ccall_av_hdl_avrc_tg_evt, event, param,
11341314 sizeof (esp_avrc_tg_cb_param_t ));
11351315 break ;
@@ -1219,6 +1399,21 @@ void BluetoothA2DPSink::av_hdl_avrc_tg_evt(uint16_t event, void *p_param) {
12191399 break ;
12201400 }
12211401
1402+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
1403+
1404+ /* when avrcp target init or deinit completed, this event comes */
1405+ case ESP_AVRC_TG_PROF_STATE_EVT: {
1406+ if (ESP_AVRC_INIT_SUCCESS == rc->avrc_tg_init_stat .state ) {
1407+ ESP_LOGI (BT_RC_CT_TAG, " AVRCP TG STATE: Init Complete" );
1408+ } else if (ESP_AVRC_DEINIT_SUCCESS == rc->avrc_tg_init_stat .state ) {
1409+ ESP_LOGI (BT_RC_CT_TAG, " AVRCP TG STATE: Deinit Complete" );
1410+ } else {
1411+ ESP_LOGE (BT_RC_CT_TAG, " AVRCP TG STATE error: %d" , rc->avrc_tg_init_stat .state );
1412+ }
1413+ break ;
1414+ }
1415+ #endif
1416+
12221417 default :
12231418 ESP_LOGE (BT_AV_TAG, " %s unhandled evt %d" , __func__, event);
12241419 break ;
0 commit comments