I2S: AAC support for web radio (#22787)

* I2S: AAC decoding support for web radio

* optimize AAC-lib for size
This commit is contained in:
Christian Baars 2025-01-08 21:35:42 +01:00 committed by GitHub
parent 1fc6f5c707
commit b73f50be6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 65 additions and 23 deletions

View File

@ -18,7 +18,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma GCC optimize ("O3")
#pragma GCC optimize ("Os")
#include "AudioGeneratorAAC.h"

View File

@ -54,7 +54,7 @@
#define AAC_ENABLE_SBR 1
#endif
#pragma GCC optimize ("O3")
#pragma GCC optimize ("Os")
#include "aacdec.h"
#include "statname.h"

View File

@ -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_

View File

@ -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

View File

@ -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 <layer3.h>
@ -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)

View File

@ -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<AudioGenerator *>(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<AudioGenerator *>(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);
if(I2SWebradio(XdrvMailbox.data, XdrvMailbox.index)){
ResponseCmndChar(XdrvMailbox.data);
} else {
ResponseCmndFailed();
}
} else {
ResponseCmndChar_P(PSTR("Stopped"));
}