Playing MP3 from SD card Using FreeRTOS Task #544
Replies: 2 comments 4 replies
-
Here's an example: #define AUDIOTASK_PRIO 2
#define AUDIOTASK_CORE 1
#define I2S_DOUT 25
#define I2S_DIN -1 // pin not used
#define I2S_BCLK 27
#define I2S_LRC 26
#define I2S_MCLK 0 // mostly not used
enum : uint8_t { SET_VOLUME, GET_VOLUME, GET_BITRATE, CONNECTTOHOST, CONNECTTOFS, STOPSONG, SETTONE, INBUFF_FILLED,
INBUFF_FREE, ISRUNNING, HIGHWATERMARK, GET_CODEC, PAUSERESUME, CONNECTION_TIMEOUT, GET_FILESIZE,
GET_FILEPOSITION};
struct audioMessage{
uint8_t cmd;
const char* txt1;
const char* txt2;
const char* txt3;
uint32_t value1;
uint32_t value2;
uint32_t ret;
} audioTxMessage, audioRxMessage;
QueueHandle_t audioSetQueue = NULL;
QueueHandle_t audioGetQueue = NULL;
void CreateQueues(){
audioSetQueue = xQueueCreate(10, sizeof(struct audioMessage));
audioGetQueue = xQueueCreate(10, sizeof(struct audioMessage));
}
void audioTask(void *parameter) {
CreateQueues();
if(!audioSetQueue || !audioGetQueue){
SerialPrintfln(ANSI_ESC_RED "Error: queues are not initialized");
while(true){;} // endless loop
}
struct audioMessage audioRxTaskMessage;
struct audioMessage audioTxTaskMessage;
audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
if(I2S_MCLK != -1) audio.i2s_mclk_pin_select(I2S_MCLK);
audio.setVolume(5); // 0...21
while(true){
if(xQueueReceive(audioSetQueue, &audioRxTaskMessage, 1) == pdPASS) {
if(audioRxTaskMessage.cmd == SET_VOLUME){
audioTxTaskMessage.cmd = SET_VOLUME;
audio.setVolume(audioRxTaskMessage.value1);
audioTxTaskMessage.ret = 1;
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == CONNECTTOHOST){
audioTxTaskMessage.cmd = CONNECTTOHOST;
const char* host = audioRxTaskMessage.txt1;
const char* user = audioRxTaskMessage.txt2;
const char* pwd = audioRxTaskMessage.txt3;
audioTxTaskMessage.ret = audio.connecttohost(host, user, pwd);
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == CONNECTTOFS){
audioTxTaskMessage.cmd = CONNECTTOFS;
audioTxTaskMessage.ret = audio.connecttoFS(SD_MMC, audioRxTaskMessage.txt1, audioRxTaskMessage.value1);
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == GET_VOLUME){
audioTxTaskMessage.cmd = GET_VOLUME;
audioTxTaskMessage.ret = audio.getVolume();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == GET_BITRATE){
audioTxTaskMessage.cmd = GET_BITRATE;
audioTxTaskMessage.ret = audio.getBitRate(true);
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == GET_CODEC){
audioTxTaskMessage.cmd = GET_CODEC;
audioTxTaskMessage.ret = audio.getCodec();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == STOPSONG){
audioTxTaskMessage.cmd = STOPSONG;
audioTxTaskMessage.ret = audio.stopSong();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == SETTONE){
audioTxTaskMessage.cmd = SETTONE;
int8_t lowPass, bandPass, highPass;
lowPass = (audioRxTaskMessage.value1 & 0xFF);
bandPass = (audioRxTaskMessage.value1 >> 8) & 0xFF;
highPass = (audioRxTaskMessage.value1 >> 16) & 0xFF;
audio.setTone(lowPass, bandPass, highPass);
audioTxTaskMessage.ret = 0;
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == INBUFF_FILLED){
audioTxTaskMessage.cmd = INBUFF_FILLED;
audioTxTaskMessage.ret = audio.inBufferFilled();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == INBUFF_FREE){
audioTxTaskMessage.cmd = INBUFF_FREE;
audioTxTaskMessage.ret = audio.inBufferFree();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == ISRUNNING){
audioTxTaskMessage.cmd = ISRUNNING;
audioTxTaskMessage.ret = audio.isRunning();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == HIGHWATERMARK){
audioTxTaskMessage.cmd = HIGHWATERMARK;
audioTxTaskMessage.ret = uxTaskGetStackHighWaterMark(NULL);
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == PAUSERESUME){
audioTxTaskMessage.cmd = PAUSERESUME;
audioTxTaskMessage.ret = audio.pauseResume();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == CONNECTION_TIMEOUT){
audioTxTaskMessage.cmd = CONNECTION_TIMEOUT;
uint32_t to = audioRxTaskMessage.value1;
uint32_t to_ssl = audioRxTaskMessage.value2;
audio.setConnectionTimeout(to, to_ssl);
audioTxTaskMessage.ret = 0;
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == GET_FILESIZE){
audioTxTaskMessage.cmd = GET_FILESIZE;
audioTxTaskMessage.ret = audio.getFileSize();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else if(audioRxTaskMessage.cmd == GET_FILEPOSITION){
audioTxTaskMessage.cmd = GET_FILEPOSITION;
audioTxTaskMessage.ret = audio.getFilePos();
xQueueSend(audioGetQueue, &audioTxTaskMessage, portMAX_DELAY);
}
else{
SerialPrintfln(ANSI_ESC_RED "Error: unknown audioTaskMessage");
}
}
audio.loop();
}
}
void audioInit() {
xTaskCreatePinnedToCore(
audioTask, /* Function to implement the task */
"audioplay", /* Name of the task */
8000, /* Stack size in words */
NULL, /* Task input parameter */
AUDIOTASK_PRIO, /* Priority of the task */
NULL, /* Task handle. */
AUDIOTASK_CORE /* Core where the task should run */
);
}
audioMessage transmitReceive(audioMessage msg){
xQueueSend(audioSetQueue, &msg, portMAX_DELAY);
if(xQueueReceive(audioGetQueue, &audioRxMessage, portMAX_DELAY) == pdPASS){
if(msg.cmd != audioRxMessage.cmd){
SerialPrintfln(ANSI_ESC_RED "Error: wrong reply from message queue");
}
}
return audioRxMessage;
}
void audioSetVolume(uint8_t vol){
audioTxMessage.cmd = SET_VOLUME;
audioTxMessage.value1 = vol;
audioMessage RX = transmitReceive(audioTxMessage);
(void)RX;
}
uint8_t audioGetVolume(){
audioTxMessage.cmd = GET_VOLUME;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioGetBitRate(){
audioTxMessage.cmd = GET_BITRATE;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioGetCodec(){
audioTxMessage.cmd = GET_CODEC;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
boolean audioConnecttohost(const char* host, const char* user, const char* pwd){
audioTxMessage.cmd = CONNECTTOHOST;
audioTxMessage.txt1 = host;
audioTxMessage.txt2 = user;
audioTxMessage.txt3 = pwd;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
boolean audioConnecttoFS(const char* filename, uint32_t resumeFilePos){
audioTxMessage.cmd = CONNECTTOFS;
audioTxMessage.txt1 = filename;
audioTxMessage.value1 = resumeFilePos;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioStopSong(){
audioTxMessage.cmd = STOPSONG;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
void audioSetTone(int8_t lowPass, int8_t bandPass, int8_t highPass, int8_t unused){
audioTxMessage.cmd = SETTONE;
audioTxMessage.value1 = (uint8_t)highPass;
audioTxMessage.value1 <<= 8;
audioTxMessage.value1 += (uint8_t)bandPass;
audioTxMessage.value1 <<= 8;
audioTxMessage.value1 += (uint8_t)lowPass;
audioMessage RX = transmitReceive(audioTxMessage);
(void)unused;
(void)RX;
}
uint32_t audioInbuffFilled(){
audioTxMessage.cmd = INBUFF_FILLED;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioInbuffFree(){
audioTxMessage.cmd = INBUFF_FREE;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
boolean audioIsRunning(){
audioTxMessage.cmd = ISRUNNING;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioGetStackHighWatermark(){
audioTxMessage.cmd = HIGHWATERMARK;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
boolean audioPauseResume(){
audioTxMessage.cmd = PAUSERESUME;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
void audioConnectionTimeout(uint32_t timeout_ms, uint32_t timeout_ms_ssl){
audioTxMessage.value1 = timeout_ms;
audioTxMessage.value2 = timeout_ms_ssl;
audioMessage RX = transmitReceive(audioTxMessage);
(void)RX;
}
uint32_t audioGetFileSize(){
audioTxMessage.cmd = GET_FILESIZE;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
}
uint32_t audioGetFilePosition(){
audioTxMessage.cmd = GET_FILEPOSITION;
audioMessage RX = transmitReceive(audioTxMessage);
return RX.ret;
} The example is a bit long, it contains a lot of functions that you probably don't need and can delete. Im setup():
|
Beta Was this translation helpful? Give feedback.
-
Why does playing a short mp3 from setup() using audio.connecttoSD(filePath, 0) work fine, but playing the same file again from a task cause ESP32 to crash? The first mp3 has finished playing before the task to play the file again is created. Guru Meditation Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled. Code to reproduce: `
} void setup(){
} ` |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi. I'm looking to create an ESP32-S3 subsystem in a project to provide real time audio feedback to user running an app on a separate MCU. The ESP32 will receive commands over uart to play short MP3 (or WAV) files via I2S (MAX98357A) from an SD card. Received commands will include stop the current audio file and start playing another audio file. Can audio.loop be placed in a freertos task to play an MP3 from an SD card, while other asynchronous tasks are receving and transmitting over uart? What task priority and task interval should be used for audio.loop() to ensure uninterrupted audio playback ? Do you have any example code that would be helpful for this?
Beta Was this translation helpful? Give feedback.
All reactions