From b73f50be6bc9be038ccee356f9b18f7f2df4a083 Mon Sep 17 00:00:00 2001 From: Christian Baars Date: Wed, 8 Jan 2025 21:35:42 +0100 Subject: [PATCH] I2S: AAC support for web radio (#22787) * I2S: AAC decoding support for web radio * optimize AAC-lib for size --- .../ESP8266Audio/src/AudioGeneratorAAC.cpp | 2 +- .../ESP8266Audio/src/libhelix-aac/aaccommon.h | 2 +- tasmota/my_user_config.h | 1 + .../xdrv_42_0_i2s_0_config_idf51.ino | 6 ++ .../xdrv_42_0_i2s_audio_idf51.ino | 10 +-- .../xdrv_42_7_i2s_webradio_idf51.ino | 67 ++++++++++++++----- 6 files changed, 65 insertions(+), 23 deletions(-) diff --git a/lib/lib_audio/ESP8266Audio/src/AudioGeneratorAAC.cpp b/lib/lib_audio/ESP8266Audio/src/AudioGeneratorAAC.cpp index c7568676a..9b30aefd9 100644 --- a/lib/lib_audio/ESP8266Audio/src/AudioGeneratorAAC.cpp +++ b/lib/lib_audio/ESP8266Audio/src/AudioGeneratorAAC.cpp @@ -18,7 +18,7 @@ along with this program. If not, see . */ -#pragma GCC optimize ("O3") +#pragma GCC optimize ("Os") #include "AudioGeneratorAAC.h" diff --git a/lib/lib_audio/ESP8266Audio/src/libhelix-aac/aaccommon.h b/lib/lib_audio/ESP8266Audio/src/libhelix-aac/aaccommon.h index 804337cd0..ca32837b2 100644 --- a/lib/lib_audio/ESP8266Audio/src/libhelix-aac/aaccommon.h +++ b/lib/lib_audio/ESP8266Audio/src/libhelix-aac/aaccommon.h @@ -54,7 +54,7 @@ #define AAC_ENABLE_SBR 1 #endif -#pragma GCC optimize ("O3") +#pragma GCC optimize ("Os") #include "aacdec.h" #include "statname.h" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index b7ae9dea9..acfcbe62c 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -1409,6 +1409,7 @@ #define USE_SHINE #define MP3_MIC_STREAM #define USE_I2S_AUDIO_BERRY + #define USE_I2S_AAC #endif // USE_I2S_ALL #endif // _MY_USER_CONFIG_H_ diff --git a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_0_config_idf51.ino b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_0_config_idf51.ino index ec39ba43a..24223ee0d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_0_config_idf51.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_0_config_idf51.ino @@ -52,6 +52,12 @@ enum : int8_t { I2S_SLOT_PHILIPS = 2, // Philips }; +// I2S decoder type +enum : uint32_t { + AAC_DECODER = 0, + MP3_DECODER = 1, +}; + #define I2S_SLOTS 2 #define AUDIO_SETTINGS_VERSION 2 diff --git a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio_idf51.ino b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio_idf51.ino index cd8dccd85..fc4269ea5 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio_idf51.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_42_0_i2s_audio_idf51.ino @@ -30,7 +30,9 @@ #include "AudioGeneratorTalkie.h" #include "AudioFileSourceICYStream.h" #include "AudioFileSourceBuffer.h" +#ifdef USE_I2S_AAC #include "AudioGeneratorAAC.h" +#endif // USE_I2S_AAC #include @@ -54,9 +56,9 @@ extern FS *ufsp; extern FS *ffsp; -const int preallocateBufferSize = 16*1024; -const int preallocateCodecSize = 29192; // MP3 codec max mem needed -//const int preallocateCodecSize = 85332; // AAC+SBR codec max mem needed +constexpr int preallocateBufferSize = 16*1024; +constexpr int preallocateCodecSize = 29192; // MP3 codec max mem needed +constexpr int preallocateCodecSizeAAC = 85332; // AAC+SBR codec max mem needed void sayTime(int hour, int minutes); void Cmndwav2mp3(void); @@ -81,7 +83,7 @@ struct AUDIO_I2S_MP3_t { #endif // USE_I2S_MP3 #if defined(USE_I2S_MP3) || defined(USE_I2S_WEBRADIO) || defined(USE_SHINE) || defined(MP3_MIC_STREAM) - AudioGeneratorMP3 *decoder = NULL; + AudioGenerator *decoder = nullptr; TaskHandle_t mp3_task_handle; TaskHandle_t mic_task_handle; #endif // defined(USE_I2S_MP3) || defined(USE_I2S_WEBRADIO) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_42_7_i2s_webradio_idf51.ino b/tasmota/tasmota_xdrv_driver/xdrv_42_7_i2s_webradio_idf51.ino index c88c14514..5f482a7de 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_42_7_i2s_webradio_idf51.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_42_7_i2s_webradio_idf51.ino @@ -46,7 +46,29 @@ void I2SWrStatusCB(void *cbData, int code, const char *str){ AddLog(LOG_LEVEL_INFO, "I2S: status: %s",str); } -void Webradio(const char *url) { +bool I2SinitDecoder(uint32_t decoder_type){ + switch(decoder_type){ + case MP3_DECODER: + audio_i2s_mp3.decoder = dynamic_cast(new AudioGeneratorMP3(Audio_webradio.preallocateCodec, preallocateCodecSize)); + break; +#ifdef USE_I2S_AAC + case AAC_DECODER: + Audio_webradio.preallocateCodec = special_realloc(Audio_webradio.preallocateCodec, preallocateCodecSizeAAC); + if(Audio_webradio.preallocateCodec == nullptr){ + AddLog(LOG_LEVEL_ERROR, "I2S: could not alloc heap for AAC"); + return false; + } + audio_i2s_mp3.decoder = dynamic_cast(new AudioGeneratorAAC(Audio_webradio.preallocateCodec, preallocateCodecSizeAAC)); + break; +#endif //USE_I2S_AAC + } + if(audio_i2s_mp3.decoder == nullptr){ + return false; + } + return true; +} + +bool I2SWebradio(const char *url, uint32_t decoder_type) { // allocate buffers if not already done if (Audio_webradio.preallocateBuffer == NULL) { Audio_webradio.preallocateBuffer = special_malloc(preallocateBufferSize); @@ -65,41 +87,49 @@ void Webradio(const char *url) { free(Audio_webradio.preallocateCodec); Audio_webradio.preallocateCodec = NULL; } - return; + return false; } Audio_webradio.ifile = new AudioFileSourceICYStream(); Audio_webradio.ifile->RegisterMetadataCB(I2sMDCallback, NULL); Audio_webradio.ifile->RegisterStatusCB(I2SWrStatusCB, NULL); if(!Audio_webradio.ifile->open(url)){ - I2sWebRadioStopPlaying(); - return; + goto i2swr_fail; } AddLog(LOG_LEVEL_INFO, "I2S: did connect to %s",url); I2SAudioPower(true); Audio_webradio.buff = new AudioFileSourceBuffer(Audio_webradio.ifile, Audio_webradio.preallocateBuffer, preallocateBufferSize); if(Audio_webradio.buff == nullptr){ - return; + goto i2swr_fail; } Audio_webradio.buff->RegisterStatusCB(I2sStatusCallback, NULL); - audio_i2s_mp3.decoder = new AudioGeneratorMP3(Audio_webradio.preallocateCodec, preallocateCodecSize); - if(audio_i2s_mp3.decoder == nullptr){ - return; - } - audio_i2s_mp3.decoder->RegisterStatusCB(I2sStatusCallback, NULL); - audio_i2s_mp3.decoder->begin(Audio_webradio.buff, audio_i2s.out); - if (!audio_i2s_mp3.decoder->isRunning()) { - I2sStopPlaying(); + + if(I2SinitDecoder(decoder_type) == false){ + AddLog(LOG_LEVEL_DEBUG, "I2S: decoder init failed"); + goto i2swr_fail; } - AddLog(LOG_LEVEL_DEBUG,PSTR("I2S: will launch webradio task")); + audio_i2s_mp3.decoder->RegisterStatusCB(I2sStatusCallback, NULL); + if(audio_i2s_mp3.decoder->begin(Audio_webradio.buff, audio_i2s.out)){ + AddLog(LOG_LEVEL_DEBUG, "I2S: decoder started"); + } else { + goto i2swr_fail; + } + + AddLog(LOG_LEVEL_DEBUG,PSTR("I2S: will launch webradio task with decoder type %u"), decoder_type); xTaskCreatePinnedToCore(I2sMp3WrTask, "MP3-WR", 8192, NULL, 3, &audio_i2s_mp3.mp3_task_handle, 1); + return true; + +i2swr_fail: + I2sStopPlaying(); + I2sWebRadioStopPlaying(); + return false; } #ifdef USE_WEBSERVER const char HTTP_WEBRADIO[] PROGMEM = - "{s}" "I2S_WR-Title" "{m}%s{e}"; + "{s}" "Webradio:" "{m}%s{e}"; void I2sWrShow(bool json) { if (audio_i2s_mp3.decoder) { @@ -116,8 +146,11 @@ void CmndI2SWebRadio(void) { if (I2SPrepareTx() != I2S_OK) return; if (XdrvMailbox.data_len > 0) { - Webradio(XdrvMailbox.data); - ResponseCmndChar(XdrvMailbox.data); + if(I2SWebradio(XdrvMailbox.data, XdrvMailbox.index)){ + ResponseCmndChar(XdrvMailbox.data); + } else { + ResponseCmndFailed(); + } } else { ResponseCmndChar_P(PSTR("Stopped")); }