v0.7.355
This commit is contained in:
@@ -317,6 +317,12 @@ Work is in progress...
|
|||||||
|
|
||||||
---
|
---
|
||||||
## Version history
|
## Version history
|
||||||
|
#### v0.7.355
|
||||||
|
- updating libraries ESP32-audioI2S and ESP32-vs1053_ext to the latest version
|
||||||
|
- optimization of the web interface during playback
|
||||||
|
- fixed one js bug. a [full update](#update-over-web-interface) with Sketch data upload is desirable
|
||||||
|
- plugin example for esp deep sleep when playback is stopped (exsamples/plugins/deepsleep.ino)
|
||||||
|
|
||||||
#### v0.7.330
|
#### v0.7.330
|
||||||
**!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** \
|
**!!! a [full update](#update-over-web-interface) with Sketch data upload is required. After updating please press CTRL+F5 in browser !!!** \
|
||||||
**Please backup playlist.csv and wifi.csv before updating.**
|
**Please backup playlist.csv and wifi.csv before updating.**
|
||||||
|
|||||||
29
exsamples/plugins/deepsleep.ino
Normal file
29
exsamples/plugins/deepsleep.ino
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**************************************************************
|
||||||
|
|
||||||
|
Example of esp32 deep sleep when playback is stopped.
|
||||||
|
This file must be in the root directory of the sketch.
|
||||||
|
|
||||||
|
**************************************************************/
|
||||||
|
#define SLEEP_DELAY 60 // 1 min
|
||||||
|
#define WAKEUP_PIN_1 GPIO_NUM_12
|
||||||
|
#define WAKEUP_LEVEL LOW
|
||||||
|
|
||||||
|
Ticker deepSleepTicker;
|
||||||
|
|
||||||
|
void goToSleep(){
|
||||||
|
if(BRIGHTNESS_PIN!=255) analogWrite(BRIGHTNESS_PIN, 0); /* BRIGHTNESS_PIN added in v0.7.330 */
|
||||||
|
esp_deep_sleep_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void yoradio_on_setup(){
|
||||||
|
esp_sleep_enable_ext0_wakeup(WAKEUP_PIN_1, WAKEUP_LEVEL);
|
||||||
|
deepSleepTicker.attach(SLEEP_DELAY, goToSleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void player_on_start_play(){
|
||||||
|
deepSleepTicker.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
void player_on_stop_play(){
|
||||||
|
deepSleepTicker.attach(SLEEP_DELAY, goToSleep);
|
||||||
|
}
|
||||||
@@ -15,6 +15,15 @@ void audio_info(const char *info) {
|
|||||||
player.mode = STOPPED;
|
player.mode = STOPPED;
|
||||||
player.stopInfo();
|
player.stopInfo();
|
||||||
}
|
}
|
||||||
|
if (strstr(info, "not supported") != NULL){
|
||||||
|
config.setTitle(info);
|
||||||
|
netserver.requestOnChange(TITLE, 0);
|
||||||
|
player.setOutputPins(false);
|
||||||
|
player.setDefaults();
|
||||||
|
if (player_on_stop_play) player_on_stop_play();
|
||||||
|
player.mode = STOPPED;
|
||||||
|
player.stopInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_bitrate(const char *info)
|
void audio_bitrate(const char *info)
|
||||||
|
|||||||
@@ -5,6 +5,18 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
Config config;
|
Config config;
|
||||||
|
|
||||||
|
void DBGVB(const char *format, ...) {
|
||||||
|
#ifdef DEBUG_V
|
||||||
|
char buf[200];
|
||||||
|
va_list args;
|
||||||
|
va_start (args, format );
|
||||||
|
vsnprintf(buf, 200, format, args);
|
||||||
|
Serial.print("[DEBUG] ");
|
||||||
|
Serial.print(buf);
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Config::init() {
|
void Config::init() {
|
||||||
EEPROM.begin(EEPROM_SIZE);
|
EEPROM.begin(EEPROM_SIZE);
|
||||||
#if IR_PIN!=255
|
#if IR_PIN!=255
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#define TMP_PATH "/data/tmpfile.txt"
|
#define TMP_PATH "/data/tmpfile.txt"
|
||||||
#define INDEX_PATH "/data/index.dat"
|
#define INDEX_PATH "/data/index.dat"
|
||||||
|
|
||||||
|
void DBGVB(const char *format, ...);
|
||||||
|
|
||||||
struct config_t
|
struct config_t
|
||||||
{
|
{
|
||||||
unsigned int config_set; //must be 4262
|
unsigned int config_set; //must be 4262
|
||||||
|
|||||||
Binary file not shown.
@@ -38,7 +38,7 @@ enum : uint16_t { VU_X = 4, VU_Y = 116, VU_BW = 24, VU_BH = 80, VU_BS = 4,
|
|||||||
enum : uint16_t { VU_X = 4, VU_Y = 90, VU_BW = 120, VU_BH = 20, VU_BS = 0, VU_NB = 12, VU_FS = 3, VU_HOR = 1, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
enum : uint16_t { VU_X = 4, VU_Y = 90, VU_BW = 120, VU_BH = 20, VU_BS = 0, VU_NB = 12, VU_FS = 3, VU_HOR = 1, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
||||||
|
|
||||||
#elif DSP_MODEL==DSP_ILI9225 /* ILI9225 220x176 */
|
#elif DSP_MODEL==DSP_ILI9225 /* ILI9225 220x176 */
|
||||||
enum : uint16_t { VU_X = 4, VU_Y = 80, VU_BW = 13, VU_BH = 56, VU_BS = 2, VU_NB = 8, VU_FS = 3, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
enum : uint16_t { VU_X = 4, VU_Y = 80, VU_BW = 13, VU_BH = 56, VU_BS = 2, VU_NB = 8, VU_FS = 4, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
||||||
|
|
||||||
#elif (DSP_MODEL==DSP_ST7735 && DTYPE==INITR_MINI160x80) || (DSP_MODEL==DSP_GC9106) /* ST7735 160x80, GC9106 160x80 */
|
#elif (DSP_MODEL==DSP_ST7735 && DTYPE==INITR_MINI160x80) || (DSP_MODEL==DSP_GC9106) /* ST7735 160x80, GC9106 160x80 */
|
||||||
enum : uint16_t { VU_X = 1, VU_Y = 30, VU_BW = 12, VU_BH = 36, VU_BS = 4, VU_NB = 8, VU_FS = 2, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
enum : uint16_t { VU_X = 1, VU_Y = 30, VU_BW = 12, VU_BH = 36, VU_BS = 4, VU_NB = 8, VU_FS = 2, VU_HOR = 0, VU_COLOR_MAX = TFT_LOGO, VU_COLOR_MIN = GRAY };
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#define MIN_MALLOC 24112
|
#define MIN_MALLOC 24112
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CORS_DEBUG
|
//#define CORS_DEBUG
|
||||||
|
|
||||||
NetServer netserver;
|
NetServer netserver;
|
||||||
|
|
||||||
@@ -40,21 +40,20 @@ void NetServer::takeMallocDog(){
|
|||||||
int mcb = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
int mcb = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||||
int mci = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
int mci = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
|
||||||
(void)mci;
|
(void)mci;
|
||||||
log_i("[yoradio] webserver.on / - MALLOC_CAP_INTERNAL=%d, MALLOC_CAP_8BIT=%d", mci, mcb);
|
DBGVB("MALLOC_CAP_8BIT=%d, MALLOC_CAP_INTERNAL=%d", mcb, mci);
|
||||||
resumePlay = mcb < MIN_MALLOC;
|
resumePlay = mcb < MIN_MALLOC;
|
||||||
if (resumePlay) {
|
if (resumePlay) {
|
||||||
player.toggle();
|
player.toggle();
|
||||||
while (player.isRunning()) {
|
vTaskDelay(150);
|
||||||
vTaskDelay(10);
|
xSemaphoreTake(player.playmutex, portMAX_DELAY);
|
||||||
}
|
|
||||||
vTaskDelay(50);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetServer::giveMallocDog(){
|
void NetServer::giveMallocDog(){
|
||||||
if (resumePlay) {
|
if (resumePlay) {
|
||||||
resumePlay = false;
|
resumePlay = false;
|
||||||
vTaskDelay(100);
|
vTaskDelay(150);
|
||||||
|
xSemaphoreGive(player.playmutex);
|
||||||
player.toggle();
|
player.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,13 +62,13 @@ bool NetServer::begin() {
|
|||||||
importRequest = false;
|
importRequest = false;
|
||||||
irRecordEnable = false;
|
irRecordEnable = false;
|
||||||
webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
|
webserver.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||||
netserver.takeMallocDog();
|
|
||||||
if (network.status == CONNECTED) {
|
if (network.status == CONNECTED) {
|
||||||
request->send(SPIFFS, "/www/index.html", String(), false, processor);
|
netserver.htmlPath = PINDEX;
|
||||||
|
netserver.chunkedHtmlPage(String(), request);
|
||||||
}else{
|
}else{
|
||||||
request->send(SPIFFS, "/www/settings.html", String(), false, processor);
|
netserver.htmlPath = PSETTINGS;
|
||||||
|
netserver.chunkedHtmlPage(String(), request);
|
||||||
}
|
}
|
||||||
netserver.giveMallocDog();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000");
|
webserver.serveStatic("/", SPIFFS, "/www/").setCacheControl("max-age=31536000");
|
||||||
@@ -81,34 +80,35 @@ bool NetServer::begin() {
|
|||||||
netserver.takeMallocDog();
|
netserver.takeMallocDog();
|
||||||
request->send(SPIFFS, PLAYLIST_PATH, "application/octet-stream");
|
request->send(SPIFFS, PLAYLIST_PATH, "application/octet-stream");
|
||||||
netserver.giveMallocDog();
|
netserver.giveMallocDog();
|
||||||
|
DBGVB("PLAYLIST_PATH client ip=%s", request->client()->remoteIP().toString().c_str());
|
||||||
|
/*netserver.htmlPath = PPLAYLIST; // TODO
|
||||||
|
netserver.chunkedHtmlPage("application/octet-stream", request);
|
||||||
|
netserver.giveMallocDog();*/
|
||||||
});
|
});
|
||||||
webserver.on(INDEX_PATH, HTTP_GET, [](AsyncWebServerRequest * request) {
|
webserver.on(INDEX_PATH, HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||||
request->send(SPIFFS, INDEX_PATH, "application/octet-stream");
|
request->send(SPIFFS, INDEX_PATH, "application/octet-stream");
|
||||||
});
|
});
|
||||||
webserver.on(SSIDS_PATH, HTTP_GET, [](AsyncWebServerRequest * request) {
|
webserver.on(SSIDS_PATH, HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||||
netserver.takeMallocDog();
|
netserver.htmlPath = PSSIDS;
|
||||||
request->send(SPIFFS, SSIDS_PATH, "application/octet-stream");
|
netserver.chunkedHtmlPage("application/octet-stream", request);
|
||||||
netserver.giveMallocDog();
|
|
||||||
});
|
});
|
||||||
webserver.on("/upload", HTTP_POST, [](AsyncWebServerRequest * request) {
|
webserver.on("/upload", HTTP_POST, [](AsyncWebServerRequest * request) {
|
||||||
//request->send(200);
|
//request->send(200);
|
||||||
|
|
||||||
}, handleUpload);
|
}, handleUpload);
|
||||||
webserver.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
webserver.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
netserver.takeMallocDog();
|
netserver.htmlPath = PUPDATE;
|
||||||
request->send(SPIFFS, "/www/update.html", String(), false, processor);
|
netserver.chunkedHtmlPage(String(), request);
|
||||||
netserver.giveMallocDog();
|
|
||||||
});
|
});
|
||||||
webserver.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
webserver.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
netserver.takeMallocDog();
|
netserver.htmlPath = PSETTINGS;
|
||||||
request->send(SPIFFS, "/www/settings.html", String(), false, processor);
|
netserver.chunkedHtmlPage(String(), request);
|
||||||
netserver.giveMallocDog();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
#if IR_PIN!=255
|
#if IR_PIN!=255
|
||||||
webserver.on("/ir", HTTP_GET, [](AsyncWebServerRequest *request){
|
webserver.on("/ir", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
netserver.takeMallocDog();
|
netserver.htmlPath = PIR;
|
||||||
request->send(SPIFFS, "/www/ir.html", String(), false, processor);
|
netserver.chunkedHtmlPage(String(), request);
|
||||||
netserver.giveMallocDog();
|
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
webserver.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
webserver.on("/update", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
@@ -160,6 +160,66 @@ bool NetServer::begin() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetServer::chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request){
|
||||||
|
max = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 32;
|
||||||
|
htmlpos = 0;
|
||||||
|
theend = false;
|
||||||
|
DBGVB("chunkedHtmlPage client ip=%s", request->client()->remoteIP().toString().c_str());
|
||||||
|
AsyncWebServerResponse *response = request->beginChunkedResponse(contentType, [](uint8_t *buffer, size_t maxLen, size_t index) -> size_t {
|
||||||
|
if(netserver.theend) return 0;
|
||||||
|
File htmlpage;
|
||||||
|
switch(netserver.htmlPath){
|
||||||
|
case PINDEX: {
|
||||||
|
htmlpage = SPIFFS.open("/www/index.html", "r");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PSETTINGS: {
|
||||||
|
htmlpage = SPIFFS.open("/www/settings.html", "r");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PUPDATE: {
|
||||||
|
htmlpage = SPIFFS.open("/www/update.html", "r");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PIR: {
|
||||||
|
htmlpage = SPIFFS.open("/www/ir.html", "r");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PPLAYLIST: {
|
||||||
|
htmlpage = SPIFFS.open(PLAYLIST_PATH, "r");
|
||||||
|
DBGVB("SPIFFS.open(PLAYLIST_PATH)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PSSIDS: {
|
||||||
|
htmlpage = SPIFFS.open(SSIDS_PATH, "r");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!htmlpage) return 0;
|
||||||
|
uint32_t htmlpagesize = htmlpage.size();
|
||||||
|
uint32_t len = htmlpagesize - netserver.htmlpos;
|
||||||
|
if (len > maxLen) len = maxLen;
|
||||||
|
if (len > netserver.max) len = netserver.max;
|
||||||
|
if (len + netserver.htmlpos > htmlpagesize) {
|
||||||
|
netserver.theend = true;
|
||||||
|
len = htmlpagesize - netserver.htmlpos;
|
||||||
|
}
|
||||||
|
if (len > 0) {
|
||||||
|
DBGVB("seek to %d in %s and read %d bytes", netserver.htmlpos, htmlpage.name(), len);
|
||||||
|
htmlpage.seek(netserver.htmlpos, SeekSet);
|
||||||
|
htmlpage.read(buffer, len);
|
||||||
|
netserver.htmlpos = netserver.htmlpos + len;
|
||||||
|
}
|
||||||
|
if(htmlpage) htmlpage.close();
|
||||||
|
return len;
|
||||||
|
}, processor); // AsyncWebServerResponse
|
||||||
|
request->send(response);
|
||||||
|
}
|
||||||
|
|
||||||
void NetServer::loop() {
|
void NetServer::loop() {
|
||||||
if(shouldReboot){
|
if(shouldReboot){
|
||||||
Serial.println("Rebooting...");
|
Serial.println("Rebooting...");
|
||||||
@@ -173,7 +233,7 @@ void NetServer::loop() {
|
|||||||
}
|
}
|
||||||
if (importRequest) {
|
if (importRequest) {
|
||||||
if (importPlaylist()) {
|
if (importPlaylist()) {
|
||||||
//requestOnChange(PLAYLIST, 0);
|
requestOnChange(PLAYLIST, 0);
|
||||||
}
|
}
|
||||||
importRequest = false;
|
importRequest = false;
|
||||||
}
|
}
|
||||||
@@ -400,7 +460,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
|
|||||||
display.putRequest({NEWMODE, PLAYER});
|
display.putRequest({NEWMODE, PLAYER});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
/* RESETS */
|
||||||
if (strcmp(cmd, "reset") == 0) {
|
if (strcmp(cmd, "reset") == 0) {
|
||||||
if (strcmp(val, "system") == 0) {
|
if (strcmp(val, "system") == 0) {
|
||||||
config.store.smartstart=2;
|
config.store.smartstart=2;
|
||||||
@@ -465,7 +525,7 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
|
|||||||
requestOnChange(GETCONTROLS,clientId);
|
requestOnChange(GETCONTROLS,clientId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} /* RESETS */
|
||||||
if (strcmp(cmd, "volume") == 0) {
|
if (strcmp(cmd, "volume") == 0) {
|
||||||
byte v = atoi(val);
|
byte v = atoi(val);
|
||||||
player.setVol(v, false);
|
player.setVol(v, false);
|
||||||
@@ -541,6 +601,9 @@ void NetServer::onWsMessage(void *arg, uint8_t *data, size_t len, uint8_t client
|
|||||||
player.toggle();
|
player.toggle();
|
||||||
resumePlay=false;
|
resumePlay=false;
|
||||||
}
|
}
|
||||||
|
#ifdef MQTT_HOST
|
||||||
|
mqttPublishPlaylist();
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if IR_PIN!=255
|
#if IR_PIN!=255
|
||||||
@@ -589,6 +652,7 @@ bool NetServer::savePlaylist(const char* post) {
|
|||||||
} else {
|
} else {
|
||||||
file.print(post);
|
file.print(post);
|
||||||
file.close();
|
file.close();
|
||||||
|
vTaskDelay(150);
|
||||||
netserver.requestOnChange(PLAYLISTSAVED, 0);
|
netserver.requestOnChange(PLAYLISTSAVED, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -650,9 +714,9 @@ void NetServer::requestOnChange(requestType_e request, uint8_t clientId) {
|
|||||||
config.indexPlaylist();
|
config.indexPlaylist();
|
||||||
config.initPlaylist();
|
config.initPlaylist();
|
||||||
getPlaylist(clientId);
|
getPlaylist(clientId);
|
||||||
#ifdef MQTT_HOST
|
/*#ifdef MQTT_HOST
|
||||||
mqttPublishPlaylist();
|
mqttPublishPlaylist();
|
||||||
#endif
|
#endif*/
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GETACTIVE: {
|
case GETACTIVE: {
|
||||||
@@ -808,6 +872,7 @@ String processor(const String& var) { // %Templates%
|
|||||||
|
|
||||||
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||||
if (!index) {
|
if (!index) {
|
||||||
|
netserver.takeMallocDog();
|
||||||
request->_tempFile = SPIFFS.open(TMP_PATH , "w");
|
request->_tempFile = SPIFFS.open(TMP_PATH , "w");
|
||||||
}
|
}
|
||||||
if (len) {
|
if (len) {
|
||||||
@@ -824,7 +889,7 @@ void handleUpload(AsyncWebServerRequest *request, String filename, size_t index,
|
|||||||
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
|
void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WS_EVT_CONNECT:
|
case WS_EVT_CONNECT:
|
||||||
if(config.store.audioinfo) Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
|
if(config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
|
||||||
/*netserver.requestOnChange(STATION, client->id());
|
/*netserver.requestOnChange(STATION, client->id());
|
||||||
netserver.requestOnChange(TITLE, client->id());
|
netserver.requestOnChange(TITLE, client->id());
|
||||||
netserver.requestOnChange(VOLUME, client->id());
|
netserver.requestOnChange(VOLUME, client->id());
|
||||||
@@ -836,7 +901,7 @@ void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventTyp
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case WS_EVT_DISCONNECT:
|
case WS_EVT_DISCONNECT:
|
||||||
if(config.store.audioinfo) Serial.printf("WebSocket client #%u disconnected\n", client->id());
|
if(config.store.audioinfo) Serial.printf("[WEBSOCKET] client #%u disconnected\n", client->id());
|
||||||
break;
|
break;
|
||||||
case WS_EVT_DATA:
|
case WS_EVT_DATA:
|
||||||
netserver.onWsMessage(arg, data, len, client->id());
|
netserver.onWsMessage(arg, data, len, client->id());
|
||||||
|
|||||||
@@ -5,13 +5,15 @@
|
|||||||
#include "ESPAsyncWebServer.h"
|
#include "ESPAsyncWebServer.h"
|
||||||
#include "AsyncUDP.h"
|
#include "AsyncUDP.h"
|
||||||
|
|
||||||
enum requestType_e { PLAYLIST, STATION, ITEM, TITLE, VOLUME, NRSSI, BITRATE, MODE, EQUALIZER, BALANCE, PLAYLISTSAVED, GETMODE, GETINDEX, GETACTIVE, GETSYSTEM, GETSCREEN, GETTIMEZONE, GETWEATHER, GETCONTROLS };
|
enum requestType_e : uint8_t { PLAYLIST=1, STATION=2, ITEM=3, TITLE=4, VOLUME=5, NRSSI=6, BITRATE=7, MODE=8, EQUALIZER=9, BALANCE=10, PLAYLISTSAVED=11, GETMODE=12, GETINDEX=13, GETACTIVE=14, GETSYSTEM=15, GETSCREEN=16, GETTIMEZONE=17, GETWEATHER=18, GETCONTROLS=19 };
|
||||||
|
enum htmlPath_e : uint8_t { PINDEX=1, PSETTINGS=2, PUPDATE=3, PIR=4, PPLAYLIST=5, PSSIDS=6 };
|
||||||
|
|
||||||
class NetServer {
|
class NetServer {
|
||||||
public:
|
public:
|
||||||
uint8_t playlistrequest; // ClientId want the playlist
|
uint8_t playlistrequest; // ClientId want the playlist
|
||||||
bool importRequest;
|
bool importRequest;
|
||||||
bool resumePlay;
|
bool resumePlay;
|
||||||
|
htmlPath_e htmlPath;
|
||||||
public:
|
public:
|
||||||
NetServer() {};
|
NetServer() {};
|
||||||
bool begin();
|
bool begin();
|
||||||
@@ -22,10 +24,13 @@ class NetServer {
|
|||||||
bool savePlaylist(const char* post);
|
bool savePlaylist(const char* post);
|
||||||
void takeMallocDog();
|
void takeMallocDog();
|
||||||
void giveMallocDog();
|
void giveMallocDog();
|
||||||
|
uint32_t max, htmlpos;
|
||||||
|
bool theend;
|
||||||
#if IR_PIN!=255
|
#if IR_PIN!=255
|
||||||
bool irRecordEnable;
|
bool irRecordEnable;
|
||||||
void irToWs(const char* protocol, uint64_t irvalue);
|
void irToWs(const char* protocol, uint64_t irvalue);
|
||||||
void irValsToWs();
|
void irValsToWs();
|
||||||
|
void chunkedHtmlPage(const String& contentType, AsyncWebServerRequest *request);
|
||||||
#endif
|
#endif
|
||||||
private:
|
private:
|
||||||
requestType_e request;
|
requestType_e request;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef options_h
|
#ifndef options_h
|
||||||
#define options_h
|
#define options_h
|
||||||
|
|
||||||
#define VERSION "0.7.330"
|
#define VERSION "0.7.355"
|
||||||
|
|
||||||
/*******************************************************
|
/*******************************************************
|
||||||
DO NOT EDIT THIS FILE.
|
DO NOT EDIT THIS FILE.
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ void Player::init() {
|
|||||||
requestToStart = true;
|
requestToStart = true;
|
||||||
volTimer=false;
|
volTimer=false;
|
||||||
zeroRequest();
|
zeroRequest();
|
||||||
|
playmutex = xSemaphoreCreateMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::stopInfo() {
|
void Player::stopInfo() {
|
||||||
@@ -70,6 +71,7 @@ void Player::loop() {
|
|||||||
//stopSong();
|
//stopSong();
|
||||||
setDefaults();
|
setDefaults();
|
||||||
stopInfo();
|
stopInfo();
|
||||||
|
xSemaphoreGive(playmutex);
|
||||||
if (player_on_stop_play) player_on_stop_play();
|
if (player_on_stop_play) player_on_stop_play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,6 +112,8 @@ void Player::setOutputPins(bool isPlaying) {
|
|||||||
|
|
||||||
void Player::play(uint16_t stationId) {
|
void Player::play(uint16_t stationId) {
|
||||||
//stopSong();
|
//stopSong();
|
||||||
|
xSemaphoreGive(playmutex);
|
||||||
|
xSemaphoreTake(playmutex, portMAX_DELAY);
|
||||||
setDefaults();
|
setDefaults();
|
||||||
setOutputPins(false);
|
setOutputPins(false);
|
||||||
config.setTitle("[connecting]");
|
config.setTitle("[connecting]");
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Player: public Audio {
|
|||||||
audiorequest_t request;
|
audiorequest_t request;
|
||||||
bool requestToStart;
|
bool requestToStart;
|
||||||
void zeroRequest();
|
void zeroRequest();
|
||||||
|
SemaphoreHandle_t playmutex=NULL;
|
||||||
public:
|
public:
|
||||||
Player();
|
Player();
|
||||||
void init();
|
void init();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Audio.h
|
* Audio.h
|
||||||
*
|
*
|
||||||
* Created on: Oct 26,2018
|
* Created on: Oct 28,2018
|
||||||
* Updated on: Jan 05,2022
|
* Updated on: Aug 12,2022
|
||||||
* Author: Wolle (schreibfaul1)
|
* Author: Wolle (schreibfaul1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -11,13 +11,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#pragma GCC optimize ("Ofast")
|
#pragma GCC optimize ("Ofast")
|
||||||
|
#include <vector>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <libb64/cencode.h>
|
#include <libb64/cencode.h>
|
||||||
|
#include <esp32-hal-log.h>
|
||||||
|
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <vector>
|
||||||
#include <driver/i2s.h>
|
#include <driver/i2s.h>
|
||||||
|
|
||||||
#ifdef SDFATFS_USED
|
#ifdef SDFATFS_USED
|
||||||
@@ -31,11 +33,12 @@
|
|||||||
#endif // SDFATFS_USED
|
#endif // SDFATFS_USED
|
||||||
|
|
||||||
#ifndef AUDIOBUFFER_MULTIPLIER
|
#ifndef AUDIOBUFFER_MULTIPLIER
|
||||||
#define AUDIOBUFFER_MULTIPLIER 13
|
#define AUDIOBUFFER_MULTIPLIER 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SDFATFS_USED
|
#ifdef SDFATFS_USED
|
||||||
typedef File32 File;
|
//typedef File32 File;
|
||||||
|
typedef FsFile File;
|
||||||
|
|
||||||
namespace fs {
|
namespace fs {
|
||||||
class FS : public SdFat {
|
class FS : public SdFat {
|
||||||
@@ -65,7 +68,7 @@ using namespace fs;
|
|||||||
#define SD SD_SDFAT
|
#define SD SD_SDFAT
|
||||||
#endif //SDFATFS_USED
|
#endif //SDFATFS_USED
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
extern __attribute__((weak)) void audio_info(const char*);
|
extern __attribute__((weak)) void audio_info(const char*);
|
||||||
@@ -83,6 +86,8 @@ extern __attribute__((weak)) void audio_eof_speech(const char*);
|
|||||||
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
||||||
extern __attribute__((weak)) void audio_process_extern(int16_t* buff, uint16_t len, bool *continueI2S); // record audiodata or send via BT
|
extern __attribute__((weak)) void audio_process_extern(int16_t* buff, uint16_t len, bool *continueI2S); // record audiodata or send via BT
|
||||||
|
|
||||||
|
#define AUDIO_INFO(...) {char buff[512 + 64]; sprintf(buff,__VA_ARGS__); if(audio_info) audio_info(buff);}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class AudioBuffer {
|
class AudioBuffer {
|
||||||
@@ -116,6 +121,8 @@ public:
|
|||||||
AudioBuffer(size_t maxBlockSize = 0); // constructor
|
AudioBuffer(size_t maxBlockSize = 0); // constructor
|
||||||
~AudioBuffer(); // frees the buffer
|
~AudioBuffer(); // frees the buffer
|
||||||
size_t init(); // set default values
|
size_t init(); // set default values
|
||||||
|
bool isInitialized() { return m_f_init; };
|
||||||
|
void setBufsize(int ram, int psram);
|
||||||
void changeMaxBlockSize(uint16_t mbs); // is default 1600 for mp3 and aac, set 16384 for FLAC
|
void changeMaxBlockSize(uint16_t mbs); // is default 1600 for mp3 and aac, set 16384 for FLAC
|
||||||
uint16_t getMaxBlockSize(); // returns maxBlockSize
|
uint16_t getMaxBlockSize(); // returns maxBlockSize
|
||||||
size_t freeSpace(); // number of free bytes to overwrite
|
size_t freeSpace(); // number of free bytes to overwrite
|
||||||
@@ -128,24 +135,26 @@ public:
|
|||||||
uint32_t getWritePos(); // write position relative to the beginning
|
uint32_t getWritePos(); // write position relative to the beginning
|
||||||
uint32_t getReadPos(); // read position relative to the beginning
|
uint32_t getReadPos(); // read position relative to the beginning
|
||||||
void resetBuffer(); // restore defaults
|
void resetBuffer(); // restore defaults
|
||||||
|
bool havePSRAM() { return m_f_psram; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
||||||
//const size_t m_buffSizeRAM = 1600 * 5 * AUDIOBUFFER_MULTIPLIER;
|
//size_t m_buffSizeRAM = 1600 * 5;
|
||||||
const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
||||||
size_t m_buffSize = 0;
|
size_t m_buffSize = 0;
|
||||||
size_t m_freeSpace = 0;
|
size_t m_freeSpace = 0;
|
||||||
size_t m_writeSpace = 0;
|
size_t m_writeSpace = 0;
|
||||||
size_t m_dataLength = 0;
|
size_t m_dataLength = 0;
|
||||||
//size_t m_resBuffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER; // reserved buffspace, >= one mp3 frame
|
size_t m_resBuffSizeRAM = 1600; // reserved buffspace, >= one mp3 frame
|
||||||
size_t m_resBuffSizeRAM = 1600; // reserved buffspace, >= one mp3 frame
|
size_t m_resBuffSizePSRAM = 4096 * 4; // reserved buffspace, >= one flac frame
|
||||||
size_t m_resBuffSizePSRAM = 4096 * 4; // reserved buffspace, >= one flac frame
|
size_t m_maxBlockSize = 1600;
|
||||||
size_t m_maxBlockSize = 1600;
|
uint8_t* m_buffer = NULL;
|
||||||
uint8_t* m_buffer = NULL;
|
uint8_t* m_writePtr = NULL;
|
||||||
uint8_t* m_writePtr = NULL;
|
uint8_t* m_readPtr = NULL;
|
||||||
uint8_t* m_readPtr = NULL;
|
uint8_t* m_endPtr = NULL;
|
||||||
uint8_t* m_endPtr = NULL;
|
bool m_f_start = true;
|
||||||
bool m_f_start = true;
|
bool m_f_init = false;
|
||||||
|
bool m_f_psram = false; // PSRAM is available (and used...)
|
||||||
};
|
};
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -154,26 +163,30 @@ class Audio : private AudioBuffer{
|
|||||||
AudioBuffer InBuff; // instance of input buffer
|
AudioBuffer InBuff; // instance of input buffer
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Audio(bool internalDAC = false, i2s_dac_mode_t channelEnabled = I2S_DAC_CHANNEL_LEFT_EN); // #99
|
Audio(bool internalDAC = false, uint8_t channelEnabled = 3, uint8_t i2sPort = I2S_NUM_0); // #99
|
||||||
~Audio();
|
~Audio();
|
||||||
|
void setBufsize(int rambuf_sz, int psrambuf_sz);
|
||||||
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
||||||
bool connecttospeech(const char* speech, const char* lang);
|
bool connecttospeech(const char* speech, const char* lang);
|
||||||
bool connecttoFS(fs::FS &fs, const char* path);
|
bool connecttomarytts(const char* speech, const char* lang, const char* voice);
|
||||||
bool connecttoSD(const char* path);
|
bool connecttoFS(fs::FS &fs, const char* path, uint32_t resumeFilePos = 0);
|
||||||
|
bool connecttoSD(const char* path, uint32_t resumeFilePos = 0);
|
||||||
bool setFileLoop(bool input);//TEST loop
|
bool setFileLoop(bool input);//TEST loop
|
||||||
|
void setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl);
|
||||||
bool setAudioPlayPosition(uint16_t sec);
|
bool setAudioPlayPosition(uint16_t sec);
|
||||||
bool setFilePos(uint32_t pos);
|
bool setFilePos(uint32_t pos);
|
||||||
bool audioFileSeek(const float speed);
|
bool audioFileSeek(const float speed);
|
||||||
bool setTimeOffset(int sec);
|
bool setTimeOffset(int sec);
|
||||||
bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN=I2S_PIN_NO_CHANGE);
|
bool setPinout(uint8_t BCLK, uint8_t LRC, uint8_t DOUT, int8_t DIN = I2S_PIN_NO_CHANGE, int8_t MCK = I2S_PIN_NO_CHANGE);
|
||||||
bool pauseResume();
|
bool pauseResume();
|
||||||
bool isRunning() {return m_f_running;}
|
bool isRunning() {return m_f_running;}
|
||||||
void loop();
|
void loop();
|
||||||
void stopSong();
|
uint32_t stopSong();
|
||||||
void forceMono(bool m);
|
void forceMono(bool m);
|
||||||
void setBalance(int8_t bal = 0);
|
void setBalance(int8_t bal = 0);
|
||||||
void setVolume(uint8_t vol);
|
void setVolume(uint8_t vol);
|
||||||
uint8_t getVolume();
|
uint8_t getVolume();
|
||||||
|
uint8_t getI2sPort();
|
||||||
|
|
||||||
uint32_t getAudioDataStartPos();
|
uint32_t getAudioDataStartPos();
|
||||||
uint32_t getFileSize();
|
uint32_t getFileSize();
|
||||||
@@ -181,10 +194,11 @@ public:
|
|||||||
uint32_t getSampleRate();
|
uint32_t getSampleRate();
|
||||||
uint8_t getBitsPerSample();
|
uint8_t getBitsPerSample();
|
||||||
uint8_t getChannels();
|
uint8_t getChannels();
|
||||||
uint32_t getBitRate();
|
uint32_t getBitRate(bool avg = false);
|
||||||
uint32_t getAudioFileDuration();
|
uint32_t getAudioFileDuration();
|
||||||
uint32_t getAudioCurrentTime();
|
uint32_t getAudioCurrentTime();
|
||||||
uint32_t getTotalPlayingTime();
|
uint32_t getTotalPlayingTime();
|
||||||
|
|
||||||
void setDefaults();
|
void setDefaults();
|
||||||
/* VU METER */
|
/* VU METER */
|
||||||
void setVUmeter() {};
|
void setVUmeter() {};
|
||||||
@@ -196,19 +210,34 @@ public:
|
|||||||
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
|
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
|
||||||
uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer
|
uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer
|
||||||
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
||||||
[[deprecated]]void setInternalDAC(bool internalDAC = true, i2s_dac_mode_t channelEnabled = I2S_DAC_CHANNEL_LEFT_EN);
|
|
||||||
void setI2SCommFMT_LSB(bool commFMT);
|
void setI2SCommFMT_LSB(bool commFMT);
|
||||||
|
int getCodec() {return m_codec;}
|
||||||
|
const char *getCodecname() {return codecname[m_codec];}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
#ifndef ESP_ARDUINO_VERSION_VAL
|
||||||
|
#define ESP_ARDUINO_VERSION_MAJOR 0
|
||||||
|
#define ESP_ARDUINO_VERSION_MINOR 0
|
||||||
|
#define ESP_ARDUINO_VERSION_PATCH 0
|
||||||
|
#endif
|
||||||
|
|
||||||
void UTF8toASCII(char* str);
|
void UTF8toASCII(char* str);
|
||||||
bool latinToUTF8(char* buff, size_t bufflen);
|
bool latinToUTF8(char* buff, size_t bufflen);
|
||||||
void httpPrint(const char* url);
|
|
||||||
//void setDefaults(); // free buffers and set defaults
|
//void setDefaults(); // free buffers and set defaults
|
||||||
void initInBuff();
|
void initInBuff();
|
||||||
|
bool httpPrint(const char* host);
|
||||||
void processLocalFile();
|
void processLocalFile();
|
||||||
void processWebStream();
|
void processWebStream();
|
||||||
void processPlayListData();
|
void processWebStreamTS();
|
||||||
void processM3U8entries(uint8_t nrOfEntries = 0, uint32_t seqNr = 0, uint8_t pos = 0, uint16_t targetDuration = 0);
|
void processWebStreamHLS();
|
||||||
|
void playAudioData();
|
||||||
|
size_t chunkedDataTransfer();
|
||||||
|
bool readPlayListData();
|
||||||
|
const char* parsePlaylist_M3U();
|
||||||
|
const char* parsePlaylist_PLS();
|
||||||
|
const char* parsePlaylist_ASX();
|
||||||
|
const char* parsePlaylist_M3U8();
|
||||||
bool STfromEXTINF(char* str);
|
bool STfromEXTINF(char* str);
|
||||||
void showCodecParams();
|
void showCodecParams();
|
||||||
int findNextSync(uint8_t* data, size_t len);
|
int findNextSync(uint8_t* data, size_t len);
|
||||||
@@ -217,24 +246,27 @@ private:
|
|||||||
void printDecodeError(int r);
|
void printDecodeError(int r);
|
||||||
void showID3Tag(const char* tag, const char* val);
|
void showID3Tag(const char* tag, const char* val);
|
||||||
void unicode2utf8(char* buff, uint32_t len);
|
void unicode2utf8(char* buff, uint32_t len);
|
||||||
|
size_t readAudioHeader(uint32_t bytes);
|
||||||
int read_WAV_Header(uint8_t* data, size_t len);
|
int read_WAV_Header(uint8_t* data, size_t len);
|
||||||
int read_FLAC_Header(uint8_t *data, size_t len);
|
int read_FLAC_Header(uint8_t *data, size_t len);
|
||||||
int read_MP3_Header(uint8_t* data, size_t len);
|
int read_ID3_Header(uint8_t* data, size_t len);
|
||||||
int read_M4A_Header(uint8_t* data, size_t len);
|
int read_M4A_Header(uint8_t* data, size_t len);
|
||||||
int read_OGG_Header(uint8_t *data, size_t len);
|
int read_OGG_Header(uint8_t *data, size_t len);
|
||||||
|
size_t process_m3u8_ID3_Header(uint8_t* packet);
|
||||||
bool setSampleRate(uint32_t hz);
|
bool setSampleRate(uint32_t hz);
|
||||||
bool setBitsPerSample(int bits);
|
bool setBitsPerSample(int bits);
|
||||||
bool setChannels(int channels);
|
bool setChannels(int channels);
|
||||||
bool setBitrate(int br);
|
bool setBitrate(int br);
|
||||||
bool playChunk();
|
bool playChunk();
|
||||||
bool playSample(int16_t sample[2]) ;
|
bool playSample(int16_t sample[2]) ;
|
||||||
bool playI2Sremains();
|
void playI2Sremains();
|
||||||
int32_t Gain(int16_t s[2]);
|
int32_t Gain(int16_t s[2]);
|
||||||
bool fill_InputBuf();
|
bool fill_InputBuf();
|
||||||
void showstreamtitle(const char* ml);
|
void showstreamtitle(const char* ml);
|
||||||
bool parseContentType(const char* ct);
|
bool parseContentType(char* ct);
|
||||||
void processAudioHeaderData();
|
bool parseHttpResponseHeader();
|
||||||
bool readMetadata(uint8_t b, bool first = false);
|
bool initializeDecoder();
|
||||||
|
uint16_t readMetadata(uint16_t b, bool first = false);
|
||||||
esp_err_t I2Sstart(uint8_t i2s_num);
|
esp_err_t I2Sstart(uint8_t i2s_num);
|
||||||
esp_err_t I2Sstop(uint8_t i2s_num);
|
esp_err_t I2Sstop(uint8_t i2s_num);
|
||||||
void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false);
|
void urlencode(char* buff, uint16_t buffLen, bool spacesOnly = false);
|
||||||
@@ -243,8 +275,9 @@ private:
|
|||||||
int16_t* IIR_filterChain2(int16_t* iir_in, bool clear = false);
|
int16_t* IIR_filterChain2(int16_t* iir_in, bool clear = false);
|
||||||
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
||||||
inline uint8_t getDatamode(){return m_datamode;}
|
inline uint8_t getDatamode(){return m_datamode;}
|
||||||
inline uint32_t streamavail() {if(m_f_ssl==false) return client.available(); else return clientsecure.available();}
|
inline uint32_t streamavail(){ return _client ? _client->available() : 0;}
|
||||||
void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3);
|
void IIR_calculateCoefficients(int8_t G1, int8_t G2, int8_t G3);
|
||||||
|
bool ts_parsePacket(uint8_t* packet, uint8_t* packetStart, uint8_t* packetLength);
|
||||||
|
|
||||||
// implement several function with respect to the index of string
|
// implement several function with respect to the index of string
|
||||||
void trim(char *s) {
|
void trim(char *s) {
|
||||||
@@ -283,7 +316,7 @@ private:
|
|||||||
return (strncmp(p, str, slen) == 0);
|
return (strncmp(p, str, slen) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int indexOf (const char* base, const char* str, int startIndex) {
|
int indexOf (const char* base, const char* str, int startIndex = 0) {
|
||||||
//fb
|
//fb
|
||||||
const char *p = base;
|
const char *p = base;
|
||||||
for (; startIndex > 0; startIndex--)
|
for (; startIndex > 0; startIndex--)
|
||||||
@@ -293,7 +326,7 @@ private:
|
|||||||
return pos - base;
|
return pos - base;
|
||||||
}
|
}
|
||||||
|
|
||||||
int indexOf (const char* base, char ch, int startIndex) {
|
int indexOf (const char* base, char ch, int startIndex = 0) {
|
||||||
//fb
|
//fb
|
||||||
const char *p = base;
|
const char *p = base;
|
||||||
for (; startIndex > 0; startIndex--)
|
for (; startIndex > 0; startIndex--)
|
||||||
@@ -369,21 +402,42 @@ private:
|
|||||||
}
|
}
|
||||||
return expectedLen;
|
return expectedLen;
|
||||||
}
|
}
|
||||||
|
void vector_clear_and_shrink(vector<char*>&vec){
|
||||||
|
uint size = vec.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if(vec[i]){
|
||||||
|
free(vec[i]);
|
||||||
|
vec[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec.clear();
|
||||||
|
vec.shrink_to_fit();
|
||||||
|
}
|
||||||
|
uint32_t simpleHash(const char* str){
|
||||||
|
if(str == NULL) return 0;
|
||||||
|
uint32_t hash = 0;
|
||||||
|
for(int i=0; i<strlen(str); i++){
|
||||||
|
if(str[i] < 32) continue; // ignore control sign
|
||||||
|
hash += (str[i] - 31) * i * 32;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
const char *codecname[9] = {"unknown", "WAV", "MP3", "AAC", "M4A", "FLAC", "OGG", "OGG FLAC", "OPUS"};
|
||||||
enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
|
enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 };
|
||||||
enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
|
enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 };
|
||||||
enum : int { CODEC_NONE, CODEC_WAV, CODEC_MP3, CODEC_AAC, CODEC_M4A, CODEC_FLAC, CODEC_OGG,
|
|
||||||
CODEC_OGG_FLAC, CODEC_OGG_OPUS};
|
|
||||||
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
|
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
|
||||||
enum : int { AUDIO_NONE, AUDIO_HEADER, AUDIO_DATA,
|
enum : int { AUDIO_NONE, HTTP_RESPONSE_HEADER, AUDIO_DATA, AUDIO_LOCALFILE,
|
||||||
AUDIO_PLAYLISTINIT, AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA};
|
AUDIO_PLAYLISTINIT, AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA};
|
||||||
enum : int { FLAC_BEGIN = 0, FLAC_MAGIC = 1, FLAC_MBH =2, FLAC_SINFO = 3, FLAC_PADDING = 4, FLAC_APP = 5,
|
enum : int { FLAC_BEGIN = 0, FLAC_MAGIC = 1, FLAC_MBH =2, FLAC_SINFO = 3, FLAC_PADDING = 4, FLAC_APP = 5,
|
||||||
FLAC_SEEK = 6, FLAC_VORBIS = 7, FLAC_CUESHEET = 8, FLAC_PICTURE = 9, FLAC_OKAY = 100};
|
FLAC_SEEK = 6, FLAC_VORBIS = 7, FLAC_CUESHEET = 8, FLAC_PICTURE = 9, FLAC_OKAY = 100};
|
||||||
enum : int { M4A_BEGIN = 0, M4A_FTYP = 1, M4A_CHK = 2, M4A_MOOV = 3, M4A_FREE = 4, M4A_TRAK = 5, M4A_MDAT = 6,
|
enum : int { M4A_BEGIN = 0, M4A_FTYP = 1, M4A_CHK = 2, M4A_MOOV = 3, M4A_FREE = 4, M4A_TRAK = 5, M4A_MDAT = 6,
|
||||||
M4A_ILST = 7, M4A_MP4A = 8, M4A_AMRDY = 99, M4A_OKAY = 100};
|
M4A_ILST = 7, M4A_MP4A = 8, M4A_AMRDY = 99, M4A_OKAY = 100};
|
||||||
enum : int { OGG_BEGIN = 0, OGG_MAGIC = 1, OGG_HEADER = 2, OGG_FIRST = 3, OGG_AMRDY = 99, OGG_OKAY = 100};
|
enum : int { OGG_BEGIN = 0, OGG_MAGIC = 1, OGG_HEADER = 2, OGG_FIRST = 3, OGG_AMRDY = 99, OGG_OKAY = 100};
|
||||||
|
enum : int { CODEC_NONE = 0, CODEC_WAV = 1, CODEC_MP3 = 2, CODEC_AAC = 3, CODEC_M4A = 4, CODEC_FLAC = 5,
|
||||||
|
CODEC_OGG = 6, CODEC_OGG_FLAC = 7, CODEC_OGG_OPUS = 8, CODEC_AACP = 9};
|
||||||
|
enum : int { ST_NONE = 0, ST_WEBFILE = 1, ST_WEBSTREAM = 2};
|
||||||
typedef enum { LEFTCHANNEL=0, RIGHTCHANNEL=1 } SampleIndex;
|
typedef enum { LEFTCHANNEL=0, RIGHTCHANNEL=1 } SampleIndex;
|
||||||
typedef enum { LOWSHELF = 0, PEAKEQ = 1, HIFGSHELF =2 } FilterType;
|
typedef enum { LOWSHELF = 0, PEAKEQ = 1, HIFGSHELF =2 } FilterType;
|
||||||
|
|
||||||
@@ -398,18 +452,29 @@ private:
|
|||||||
float b2;
|
float b2;
|
||||||
} filter_t;
|
} filter_t;
|
||||||
|
|
||||||
File audiofile; // @suppress("Abstract class cannot be instantiated")
|
typedef struct _pis_array{
|
||||||
WiFiClient client; // @suppress("Abstract class cannot be instantiated")
|
int number;
|
||||||
WiFiClientSecure clientsecure; // @suppress("Abstract class cannot be instantiated")
|
int pids[4];
|
||||||
WiFiUDP udpclient; // @suppress("Abstract class cannot be instantiated")
|
} pid_array;
|
||||||
i2s_config_t m_i2s_config; // stores values for I2S driver
|
|
||||||
i2s_pin_config_t m_pin_config;
|
File audiofile; // @suppress("Abstract class cannot be instantiated")
|
||||||
|
WiFiClient client; // @suppress("Abstract class cannot be instantiated")
|
||||||
|
WiFiClientSecure clientsecure; // @suppress("Abstract class cannot be instantiated")
|
||||||
|
WiFiClient* _client = nullptr;
|
||||||
|
i2s_config_t m_i2s_config = {}; // stores values for I2S driver
|
||||||
|
i2s_pin_config_t m_pin_config = {};
|
||||||
|
std::vector<char*> m_playlistContent; // m3u8 playlist buffer
|
||||||
|
std::vector<char*> m_playlistURL; // m3u8 streamURLs buffer
|
||||||
|
std::vector<uint32_t> m_hashQueue;
|
||||||
|
|
||||||
const size_t m_frameSizeWav = 1600;
|
const size_t m_frameSizeWav = 1600;
|
||||||
const size_t m_frameSizeMP3 = 1600;
|
const size_t m_frameSizeMP3 = 1600;
|
||||||
const size_t m_frameSizeAAC = 1600;
|
const size_t m_frameSizeAAC = 1600;
|
||||||
const size_t m_frameSizeFLAC = 4096 * 4;
|
const size_t m_frameSizeFLAC = 4096 * 4;
|
||||||
|
|
||||||
|
static const uint8_t m_tsPacketSize = 188;
|
||||||
|
static const uint8_t m_tsHeaderSize = 4;
|
||||||
|
|
||||||
char chbuf[512 + 128]; // must be greater than m_lastHost #254
|
char chbuf[512 + 128]; // must be greater than m_lastHost #254
|
||||||
char m_lastHost[512]; // Store the last URL to a webstream
|
char m_lastHost[512]; // Store the last URL to a webstream
|
||||||
char* m_playlistBuff = NULL; // stores playlistdata
|
char* m_playlistBuff = NULL; // stores playlistdata
|
||||||
@@ -419,23 +484,28 @@ private:
|
|||||||
uint32_t m_sampleRate=16000;
|
uint32_t m_sampleRate=16000;
|
||||||
uint32_t m_bitRate=0; // current bitrate given fom decoder
|
uint32_t m_bitRate=0; // current bitrate given fom decoder
|
||||||
uint32_t m_avr_bitrate = 0; // average bitrate, median computed by VBR
|
uint32_t m_avr_bitrate = 0; // average bitrate, median computed by VBR
|
||||||
int m_readbytes=0; // bytes read
|
int m_readbytes = 0; // bytes read
|
||||||
int m_metalen=0; // Number of bytes in metadata
|
uint32_t m_metacount = 0; // counts down bytes between metadata
|
||||||
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
||||||
int8_t m_balance = 0; // -16 (mute left) ... +16 (mute right)
|
int8_t m_balance = 0; // -16 (mute left) ... +16 (mute right)
|
||||||
uint8_t m_vol=64; // volume
|
uint8_t m_vol=64; // volume
|
||||||
uint8_t m_bitsPerSample = 16; // bitsPerSample
|
uint8_t m_bitsPerSample = 16; // bitsPerSample
|
||||||
uint8_t m_channels=2;
|
uint8_t m_channels = 2;
|
||||||
uint8_t m_i2s_num = I2S_NUM_0; // I2S_NUM_0 or I2S_NUM_1
|
uint8_t m_i2s_num = I2S_NUM_0; // I2S_NUM_0 or I2S_NUM_1
|
||||||
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
||||||
uint8_t m_m3u8codec = CODEC_NONE; // M4A
|
|
||||||
uint8_t m_codec = CODEC_NONE; //
|
uint8_t m_codec = CODEC_NONE; //
|
||||||
|
uint8_t m_expectedCodec = CODEC_NONE; // set in connecttohost (e.g. http://url.mp3 -> CODEC_MP3)
|
||||||
|
uint8_t m_expectedPlsFmt = FORMAT_NONE; // set in connecttohost (e.g. streaming01.m3u) -> FORMAT_M3U)
|
||||||
uint8_t m_filterType[2]; // lowpass, highpass
|
uint8_t m_filterType[2]; // lowpass, highpass
|
||||||
|
uint8_t m_streamType = ST_NONE;
|
||||||
|
uint8_t m_ID3Size = 0; // lengt of ID3frame - ID3header
|
||||||
int16_t m_outBuff[2048*2]; // Interleaved L/R
|
int16_t m_outBuff[2048*2]; // Interleaved L/R
|
||||||
int16_t m_validSamples = 0;
|
int16_t m_validSamples = 0;
|
||||||
int16_t m_curSample = 0;
|
int16_t m_curSample = 0;
|
||||||
uint16_t m_st_remember = 0; // Save hash from the last streamtitle
|
|
||||||
uint16_t m_datamode = 0; // Statemaschine
|
uint16_t m_datamode = 0; // Statemaschine
|
||||||
|
uint16_t m_streamTitleHash = 0; // remember streamtitle, ignore multiple occurence in metadata
|
||||||
|
uint16_t m_timeout_ms = 250;
|
||||||
|
uint16_t m_timeout_ms_ssl = 2700;
|
||||||
uint8_t m_flacBitsPerSample = 0; // bps should be 16
|
uint8_t m_flacBitsPerSample = 0; // bps should be 16
|
||||||
uint8_t m_flacNumChannels = 0; // can be read out in the FLAC file header
|
uint8_t m_flacNumChannels = 0; // can be read out in the FLAC file header
|
||||||
uint32_t m_flacSampleRate = 0; // can be read out in the FLAC file header
|
uint32_t m_flacSampleRate = 0; // can be read out in the FLAC file header
|
||||||
@@ -448,30 +518,27 @@ private:
|
|||||||
uint32_t m_contentlength = 0; // Stores the length if the stream comes from fileserver
|
uint32_t m_contentlength = 0; // Stores the length if the stream comes from fileserver
|
||||||
uint32_t m_bytesNotDecoded = 0; // pictures or something else that comes with the stream
|
uint32_t m_bytesNotDecoded = 0; // pictures or something else that comes with the stream
|
||||||
uint32_t m_PlayingStartTime = 0; // Stores the milliseconds after the start of the audio
|
uint32_t m_PlayingStartTime = 0; // Stores the milliseconds after the start of the audio
|
||||||
|
uint32_t m_resumeFilePos = 0; // the return value from stopSong() can be entered here
|
||||||
|
uint16_t m_m3u8_targetDuration = 10; //
|
||||||
bool m_f_swm = true; // Stream without metadata
|
bool m_f_swm = true; // Stream without metadata
|
||||||
bool m_f_unsync = false; // set within ID3 tag but not used
|
bool m_f_unsync = false; // set within ID3 tag but not used
|
||||||
bool m_f_exthdr = false; // ID3 extended header
|
bool m_f_exthdr = false; // ID3 extended header
|
||||||
bool m_f_localfile = false ; // Play from local mp3-file
|
|
||||||
bool m_f_webstream = false ; // Play from URL
|
|
||||||
bool m_f_ssl = false;
|
bool m_f_ssl = false;
|
||||||
bool m_f_running = false;
|
bool m_f_running = false;
|
||||||
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
||||||
bool m_f_ctseen = false; // First line of header seen or not
|
|
||||||
bool m_f_chunked = false ; // Station provides chunked transfer
|
bool m_f_chunked = false ; // Station provides chunked transfer
|
||||||
bool m_f_firstmetabyte = false; // True if first metabyte (counter)
|
bool m_f_firstmetabyte = false; // True if first metabyte (counter)
|
||||||
bool m_f_playing = false; // valid mp3 stream recognized
|
bool m_f_playing = false; // valid mp3 stream recognized
|
||||||
bool m_f_webfile = false; // assume it's a radiostream, not a podcast
|
|
||||||
bool m_f_tts = false; // text to speech
|
bool m_f_tts = false; // text to speech
|
||||||
bool m_f_psram = false; // set if PSRAM is availabe
|
|
||||||
bool m_f_loop = false; // Set if audio file should loop
|
bool m_f_loop = false; // Set if audio file should loop
|
||||||
bool m_f_forceMono = false; // if true stereo -> mono
|
bool m_f_forceMono = false; // if true stereo -> mono
|
||||||
bool m_f_internalDAC = false; // false: output vis I2S, true output via internal DAC
|
bool m_f_internalDAC = false; // false: output vis I2S, true output via internal DAC
|
||||||
bool m_f_rtsp = false; // set if RTSP is used (m3u8 stream)
|
bool m_f_rtsp = false; // set if RTSP is used (m3u8 stream)
|
||||||
bool m_f_m3u8data = false; // used in processM3U8entries
|
bool m_f_m3u8data = false; // used in processM3U8entries
|
||||||
bool m_f_Log = true; // if m3u8: log is cancelled
|
bool m_f_Log = false; // set in platformio.ini -DAUDIO_LOG and -DCORE_DEBUG_LEVEL=3 or 4
|
||||||
bool m_f_continue = false; // next m3u8 chunk is available
|
bool m_f_continue = false; // next m3u8 chunk is available
|
||||||
bool m_f_initInbuffOnce = false; // init InBuff only once
|
bool m_f_ts = true; // transport stream
|
||||||
i2s_dac_mode_t m_f_channelEnabled = I2S_DAC_CHANNEL_LEFT_EN; // internal DAC on GPIO26 for M5StickC/Plus
|
uint8_t m_f_channelEnabled = 3; // internal DAC, both channels
|
||||||
uint32_t m_audioFileDuration = 0;
|
uint32_t m_audioFileDuration = 0;
|
||||||
float m_audioCurrentTime = 0;
|
float m_audioCurrentTime = 0;
|
||||||
uint32_t m_audioDataStart = 0; // in bytes
|
uint32_t m_audioDataStart = 0; // in bytes
|
||||||
@@ -483,6 +550,11 @@ private:
|
|||||||
int8_t m_gain0 = 0; // cut or boost filters (EQ)
|
int8_t m_gain0 = 0; // cut or boost filters (EQ)
|
||||||
int8_t m_gain1 = 0;
|
int8_t m_gain1 = 0;
|
||||||
int8_t m_gain2 = 0;
|
int8_t m_gain2 = 0;
|
||||||
|
|
||||||
|
pid_array m_pidsOfPMT;
|
||||||
|
int16_t m_pidOfAAC;
|
||||||
|
uint8_t m_packetBuff[m_tsPacketSize];
|
||||||
|
int16_t m_pesDataLength = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* libhelix_HAACDECODER
|
* libhelix_HAACDECODER
|
||||||
*
|
*
|
||||||
* Created on: 26.10.2018
|
* Created on: 26.10.2018
|
||||||
* Updated on: 10.09.2021
|
* Updated on: 27.05.2022
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
#include "aac_decoder.h"
|
#include "aac_decoder.h"
|
||||||
@@ -1654,47 +1654,42 @@ static const int8_t negMask[3] = {~0x03, ~0x07, ~0x0f};
|
|||||||
* Return: false if not enough memory, otherwise true
|
* Return: false if not enough memory, otherwise true
|
||||||
*
|
*
|
||||||
**********************************************************************************************************************/
|
**********************************************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
// ESP32-S3: If there is PSRAM, prefer it
|
||||||
|
#define __malloc_heap_psram(size) \
|
||||||
|
heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL)
|
||||||
|
#else
|
||||||
|
// ESP32, PSRAM is too slow, prefer SRAM
|
||||||
|
#define __malloc_heap_psram(size) \
|
||||||
|
heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM)
|
||||||
|
#endif
|
||||||
|
|
||||||
bool AACDecoder_AllocateBuffers(void){
|
bool AACDecoder_AllocateBuffers(void){
|
||||||
|
|
||||||
if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) malloc(sizeof(AACDecInfo_t));}
|
/* here, sizes are: AACDecInfo_t:96 PSInfoBase_t:27364 ProgConfigElement_t*16:1312 PSInfoSBR_t:50788 */
|
||||||
if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) malloc(sizeof(PSInfoBase_t));}
|
#ifdef AAC_ENABLE_SBR
|
||||||
if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) malloc(sizeof(ProgConfigElement_t)*16);}
|
if(!m_PSInfoSBR) {m_PSInfoSBR = (PSInfoSBR_t*)__malloc_heap_psram(sizeof(PSInfoSBR_t));}
|
||||||
|
|
||||||
if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) {
|
if(!m_PSInfoSBR) {
|
||||||
log_i("heap is too small, try PSRAM");
|
log_e("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR_t));
|
||||||
AACDecoder_FreeBuffers();
|
return false; // ERR_AAC_SBR_INIT;
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
goto nextStep;
|
log_d("AAC Spectral Band Replication enabled, %d additional bytes allocated", sizeof(PSInfoSBR_t));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(psramFound()) {
|
/* these could fall back to PSRAM if not enough heap available */
|
||||||
// PSRAM found, Buffer will be allocated in PSRAM
|
if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) __malloc_heap_psram(sizeof(AACDecInfo_t));}
|
||||||
if(!m_AACDecInfo) {m_AACDecInfo = (AACDecInfo_t*) ps_calloc(sizeof(AACDecInfo_t), sizeof(uint8_t));}
|
if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) __malloc_heap_psram(sizeof(PSInfoBase_t));}
|
||||||
if(!m_PSInfoBase) {m_PSInfoBase = (PSInfoBase_t*) ps_calloc(sizeof(PSInfoBase_t), sizeof(uint8_t));}
|
if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) __malloc_heap_psram(sizeof(ProgConfigElement_t)*16);}
|
||||||
if(!m_pce[0]) {m_pce[0] = (ProgConfigElement_t*) ps_calloc(sizeof(ProgConfigElement_t)*16, sizeof(uint8_t));}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) {
|
if(!m_AACDecInfo || !m_PSInfoBase || !m_pce[0]) {
|
||||||
log_e("not enough memory to allocate aacdecoder buffers");
|
log_e("not enough memory to allocate aacdecoder buffers");
|
||||||
AACDecoder_FreeBuffers();
|
AACDecoder_FreeBuffers();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log_i("AAC buffers allocated in PSRAM");
|
|
||||||
|
|
||||||
nextStep:
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef AAC_ENABLE_SBR
|
|
||||||
// can't allocated in PSRAM, because PSRAM ist too slow
|
|
||||||
if(!m_PSInfoSBR) {m_PSInfoSBR = (PSInfoSBR_t*)malloc(sizeof(PSInfoSBR_t));}
|
|
||||||
|
|
||||||
if(!m_PSInfoSBR) {
|
|
||||||
log_e("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR_t));
|
|
||||||
return false; // ERR_AAC_SBR_INIT;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Clear Buffer
|
// Clear Buffer
|
||||||
memset( m_AACDecInfo, 0, sizeof(AACDecInfo_t)); //Clear AACDecInfo
|
memset( m_AACDecInfo, 0, sizeof(AACDecInfo_t)); //Clear AACDecInfo
|
||||||
@@ -1777,7 +1772,7 @@ void AACDecoder_FreeBuffers(void) {
|
|||||||
|
|
||||||
if(m_AACDecInfo) {free(m_AACDecInfo); m_AACDecInfo=NULL;}
|
if(m_AACDecInfo) {free(m_AACDecInfo); m_AACDecInfo=NULL;}
|
||||||
if(m_PSInfoBase) {free(m_PSInfoBase); m_PSInfoBase=NULL;}
|
if(m_PSInfoBase) {free(m_PSInfoBase); m_PSInfoBase=NULL;}
|
||||||
if(m_pce[0]) {for(int i=0; i<16; i++) free(m_pce[i]); m_pce[0]=NULL;}
|
if(m_pce[0]) {free(m_pce[0]); m_pce[0]=NULL;}
|
||||||
|
|
||||||
#ifdef AAC_ENABLE_SBR
|
#ifdef AAC_ENABLE_SBR
|
||||||
if(m_PSInfoSBR) {free(m_PSInfoSBR); m_PSInfoSBR=NULL;} //Clear AACDecInfo
|
if(m_PSInfoSBR) {free(m_PSInfoSBR); m_PSInfoSBR=NULL;} //Clear AACDecInfo
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#define AAC_ENABLE_MPEG4
|
#define AAC_ENABLE_MPEG4
|
||||||
//#define AAC_ENABLE_SBR // needs additional 60KB Heap,
|
|
||||||
|
#if (defined CONFIG_IDF_TARGET_ESP32S3 && defined BOARD_HAS_PSRAM)
|
||||||
|
#define AAC_ENABLE_SBR // needs additional 60KB DRAM,
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ASSERT(x) /* do nothing */
|
#define ASSERT(x) /* do nothing */
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* libhelix_HMP3DECODER
|
* libhelix_HMP3DECODER
|
||||||
*
|
*
|
||||||
* Created on: 26.10.2018
|
* Created on: 26.10.2018
|
||||||
* Updated on: 03.01.2022
|
* Updated on: 27.05.2022
|
||||||
*/
|
*/
|
||||||
#include "mp3_decoder.h"
|
#include "mp3_decoder.h"
|
||||||
/* clip to range [-2^n, 2^n - 1] */
|
/* clip to range [-2^n, 2^n - 1] */
|
||||||
@@ -1490,8 +1490,6 @@ int MP3Decode( unsigned char *inbuf, int *bytesLeft, short *outbuf, int useSize)
|
|||||||
*
|
*
|
||||||
* Return: none
|
* Return: none
|
||||||
*
|
*
|
||||||
* Notes: if one or more mallocs fail, function frees any buffers already
|
|
||||||
* allocated before returning
|
|
||||||
**********************************************************************************************************************/
|
**********************************************************************************************************************/
|
||||||
void MP3Decoder_ClearBuffer(void) {
|
void MP3Decoder_ClearBuffer(void) {
|
||||||
|
|
||||||
@@ -1525,54 +1523,38 @@ void MP3Decoder_ClearBuffer(void) {
|
|||||||
* Return: pointer to MP3DecInfo structure (initialized with pointers to all
|
* Return: pointer to MP3DecInfo structure (initialized with pointers to all
|
||||||
* the internal buffers needed for decoding)
|
* the internal buffers needed for decoding)
|
||||||
*
|
*
|
||||||
|
* Notes: if one or more mallocs fail, function frees any buffers already
|
||||||
|
* allocated before returning
|
||||||
|
*
|
||||||
**********************************************************************************************************************/
|
**********************************************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||||
|
// ESP32-S3: If there is PSRAM, prefer it
|
||||||
|
#define __malloc_heap_psram(size) \
|
||||||
|
heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL)
|
||||||
|
#else
|
||||||
|
// ESP32, PSRAM is too slow, prefer SRAM
|
||||||
|
#define __malloc_heap_psram(size) \
|
||||||
|
heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM)
|
||||||
|
#endif
|
||||||
|
|
||||||
bool MP3Decoder_AllocateBuffers(void) {
|
bool MP3Decoder_AllocateBuffers(void) {
|
||||||
|
if(!m_MP3DecInfo) {m_MP3DecInfo = (MP3DecInfo_t*) __malloc_heap_psram(sizeof(MP3DecInfo_t) );}
|
||||||
// try first SRAM because its faster than PSRAM
|
if(!m_FrameHeader) {m_FrameHeader = (FrameHeader_t*) __malloc_heap_psram(sizeof(FrameHeader_t) );}
|
||||||
|
if(!m_SideInfo) {m_SideInfo = (SideInfo_t*) __malloc_heap_psram(sizeof(SideInfo_t) );}
|
||||||
|
if(!m_ScaleFactorJS) {m_ScaleFactorJS = (ScaleFactorJS_t*) __malloc_heap_psram(sizeof(ScaleFactorJS_t));}
|
||||||
if(!m_MP3DecInfo) {m_MP3DecInfo = (MP3DecInfo_t*) malloc(sizeof(MP3DecInfo_t) );}
|
if(!m_HuffmanInfo) {m_HuffmanInfo = (HuffmanInfo_t*) __malloc_heap_psram(sizeof(HuffmanInfo_t) );}
|
||||||
if(!m_FrameHeader) {m_FrameHeader = (FrameHeader_t*) malloc(sizeof(FrameHeader_t) );}
|
if(!m_DequantInfo) {m_DequantInfo = (DequantInfo_t*) __malloc_heap_psram(sizeof(DequantInfo_t) );}
|
||||||
if(!m_SideInfo) {m_SideInfo = (SideInfo_t*) malloc(sizeof(SideInfo_t) );}
|
if(!m_IMDCTInfo) {m_IMDCTInfo = (IMDCTInfo_t*) __malloc_heap_psram(sizeof(IMDCTInfo_t) );}
|
||||||
if(!m_ScaleFactorJS) {m_ScaleFactorJS = (ScaleFactorJS_t*) malloc(sizeof(ScaleFactorJS_t));}
|
if(!m_SubbandInfo) {m_SubbandInfo = (SubbandInfo_t*) __malloc_heap_psram(sizeof(SubbandInfo_t) );}
|
||||||
if(!m_HuffmanInfo) {m_HuffmanInfo = (HuffmanInfo_t*) malloc(sizeof(HuffmanInfo_t) );}
|
if(!m_MP3FrameInfo) {m_MP3FrameInfo = (MP3FrameInfo_t*) __malloc_heap_psram(sizeof(MP3FrameInfo_t) );}
|
||||||
if(!m_DequantInfo) {m_DequantInfo = (DequantInfo_t*) malloc(sizeof(DequantInfo_t) );}
|
|
||||||
if(!m_IMDCTInfo) {m_IMDCTInfo = (IMDCTInfo_t*) malloc(sizeof(IMDCTInfo_t) );}
|
|
||||||
if(!m_SubbandInfo) {m_SubbandInfo = (SubbandInfo_t*) malloc(sizeof(SubbandInfo_t) );}
|
|
||||||
if(!m_MP3FrameInfo) {m_MP3FrameInfo = (MP3FrameInfo_t*) malloc(sizeof(MP3FrameInfo_t) );}
|
|
||||||
|
|
||||||
if(!m_MP3DecInfo || !m_FrameHeader || !m_SideInfo || !m_ScaleFactorJS || !m_HuffmanInfo ||
|
if(!m_MP3DecInfo || !m_FrameHeader || !m_SideInfo || !m_ScaleFactorJS || !m_HuffmanInfo ||
|
||||||
!m_DequantInfo || !m_IMDCTInfo || !m_SubbandInfo || !m_MP3FrameInfo) {
|
!m_DequantInfo || !m_IMDCTInfo || !m_SubbandInfo || !m_MP3FrameInfo) {
|
||||||
log_i("heap is too small, try PSRAM");
|
|
||||||
MP3Decoder_FreeBuffers();
|
MP3Decoder_FreeBuffers();
|
||||||
}
|
|
||||||
else{
|
|
||||||
MP3Decoder_ClearBuffer();
|
|
||||||
return true; // success, all buffers allocated in SRAM (Heap)
|
|
||||||
}
|
|
||||||
|
|
||||||
if(psramFound()) {
|
|
||||||
// PSRAM found, Buffer will be allocated in PSRAM
|
|
||||||
if(!m_MP3DecInfo) {m_MP3DecInfo = (MP3DecInfo_t*) ps_calloc(sizeof(MP3DecInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_FrameHeader) {m_FrameHeader = (FrameHeader_t*) ps_calloc(sizeof(FrameHeader_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_SideInfo) {m_SideInfo = (SideInfo_t*) ps_calloc(sizeof(SideInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_ScaleFactorJS) {m_ScaleFactorJS = (ScaleFactorJS_t*) ps_calloc(sizeof(ScaleFactorJS_t), sizeof(uint8_t));}
|
|
||||||
if(!m_HuffmanInfo) {m_HuffmanInfo = (HuffmanInfo_t*) ps_calloc(sizeof(HuffmanInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_DequantInfo) {m_DequantInfo = (DequantInfo_t*) ps_calloc(sizeof(DequantInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_IMDCTInfo) {m_IMDCTInfo = (IMDCTInfo_t*) ps_calloc(sizeof(IMDCTInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_SubbandInfo) {m_SubbandInfo = (SubbandInfo_t*) ps_calloc(sizeof(SubbandInfo_t) , sizeof(uint8_t));}
|
|
||||||
if(!m_MP3FrameInfo) {m_MP3FrameInfo = (MP3FrameInfo_t*) ps_calloc(sizeof(MP3FrameInfo_t) , sizeof(uint8_t));}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log_e("not enough memory to allocate mp3decoder buffers");
|
log_e("not enough memory to allocate mp3decoder buffers");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!m_MP3DecInfo || !m_FrameHeader || !m_SideInfo || !m_ScaleFactorJS || !m_HuffmanInfo ||
|
|
||||||
!m_DequantInfo || !m_IMDCTInfo || !m_SubbandInfo || !m_MP3FrameInfo) {
|
|
||||||
log_e("not enough memory to allocate mp3decoder buffers in PSRAM");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MP3Decoder_ClearBuffer();
|
MP3Decoder_ClearBuffer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
* vs1053_ext.h
|
* vs1053_ext.h
|
||||||
*
|
*
|
||||||
* Created on: Jul 09.2017
|
* Created on: Jul 09.2017
|
||||||
* Updated on: Feb 11 2022
|
* Updated on: Aug 15.2022
|
||||||
* Author: Wolle
|
* Author: Wolle
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -10,13 +10,15 @@
|
|||||||
#define _vs1053_ext
|
#define _vs1053_ext
|
||||||
|
|
||||||
#ifndef AUDIOBUFFER_MULTIPLIER
|
#ifndef AUDIOBUFFER_MULTIPLIER
|
||||||
#define AUDIOBUFFER_MULTIPLIER 13
|
#define AUDIOBUFFER_MULTIPLIER 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VS1053VOLM 128 // 128 or 96 only
|
#define VS1053VOLM 128 // 128 or 96 only
|
||||||
#define VS1053VOL(v) (VS1053VOLM==128?log10(((float)v+1)) * 50.54571334 + 128:log10(((float)v+1)) * 64.54571334 + 96)
|
#define VS1053VOL(v) (VS1053VOLM==128?log10(((float)v+1)) * 50.54571334 + 128:log10(((float)v+1)) * 64.54571334 + 96)
|
||||||
|
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
#include <vector>
|
||||||
#include "libb64/cencode.h"
|
#include "libb64/cencode.h"
|
||||||
#include "SPI.h"
|
#include "SPI.h"
|
||||||
#include "SD.h"
|
#include "SD.h"
|
||||||
@@ -44,6 +46,8 @@ extern __attribute__((weak)) void audio_icydescription(const char*);
|
|||||||
extern __attribute__((weak)) void audio_lasthost(const char*);
|
extern __attribute__((weak)) void audio_lasthost(const char*);
|
||||||
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
extern __attribute__((weak)) void audio_eof_stream(const char*); // The webstream comes to an end
|
||||||
|
|
||||||
|
#define AUDIO_INFO(...) {char buff[512 + 64]; sprintf(buff,__VA_ARGS__); if(audio_info) audio_info(buff);}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
class AudioBuffer {
|
class AudioBuffer {
|
||||||
@@ -92,6 +96,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
const size_t m_buffSizePSRAM = 300000; // most webstreams limit the advance to 100...300Kbytes
|
||||||
|
//const size_t m_buffSizeRAM = 1600 * 10;
|
||||||
const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
const size_t m_buffSizeRAM = 1600 * AUDIOBUFFER_MULTIPLIER;
|
||||||
size_t m_buffSize = 0;
|
size_t m_buffSize = 0;
|
||||||
size_t m_freeSpace = 0;
|
size_t m_freeSpace = 0;
|
||||||
@@ -113,18 +118,22 @@ class Audio : private AudioBuffer{
|
|||||||
AudioBuffer InBuff; // instance of input buffer
|
AudioBuffer InBuff; // instance of input buffer
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WiFiClient client;
|
WiFiClient client; // @suppress("Abstract class cannot be instantiated")
|
||||||
WiFiClientSecure clientsecure;
|
WiFiClientSecure clientsecure; // @suppress("Abstract class cannot be instantiated")
|
||||||
|
WiFiClient* _client = nullptr;
|
||||||
File audiofile;
|
File audiofile;
|
||||||
|
std::vector<char*> m_playlistContent; // m3u8 playlist buffer
|
||||||
|
std::vector<char*> m_playlistURL; // m3u8 streamURLs buffer
|
||||||
|
std::vector<uint32_t> m_hashQueue;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum : int { VS1053_NONE, VS1053_HEADER , VS1053_DATA, VS1053_METADATA, VS1053_PLAYLISTINIT,
|
enum : int { AUDIO_NONE, HTTP_RESPONSE_HEADER , AUDIO_DATA, AUDIO_LOCALFILE, AUDIO_METADATA, AUDIO_PLAYLISTINIT,
|
||||||
VS1053_PLAYLISTHEADER, VS1053_PLAYLISTDATA, VS1053_SWM, VS1053_OGG};
|
AUDIO_PLAYLISTHEADER, AUDIO_PLAYLISTDATA, VS1053_SWM, VS1053_OGG};
|
||||||
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3};
|
enum : int { FORMAT_NONE = 0, FORMAT_M3U = 1, FORMAT_PLS = 2, FORMAT_ASX = 3, FORMAT_M3U8 = 4};
|
||||||
|
|
||||||
enum : int { CODEC_NONE, CODEC_WAV, CODEC_MP3, CODEC_AAC, CODEC_M4A, CODEC_FLAC, CODEC_OGG,
|
enum : int { CODEC_NONE, CODEC_WAV, CODEC_MP3, CODEC_AAC, CODEC_M4A, CODEC_FLAC, CODEC_OGG,
|
||||||
CODEC_OGG_FLAC, CODEC_OGG_OPUS};
|
CODEC_OGG_FLAC, CODEC_OGG_OPUS};
|
||||||
|
enum : int { ST_NONE = 0, ST_WEBFILE = 1, ST_WEBSTREAM = 2};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t cs_pin ; // Pin where CS line is connected
|
uint8_t cs_pin ; // Pin where CS line is connected
|
||||||
@@ -159,11 +168,16 @@ private:
|
|||||||
const uint8_t SM_LINE1 = 14 ; // Bitnumber in SCI_MODE for Line input
|
const uint8_t SM_LINE1 = 14 ; // Bitnumber in SCI_MODE for Line input
|
||||||
|
|
||||||
SPIClass* spi_VS1053 = NULL;
|
SPIClass* spi_VS1053 = NULL;
|
||||||
SPISettings VS1053_SPI; // SPI settings for this slave
|
SPISettings VS1053_SPI_DATA; // SPI settings normal speed
|
||||||
|
SPISettings VS1053_SPI_CTL; // SPI settings control mode
|
||||||
|
|
||||||
char chbuf[512];
|
char chbuf[512];
|
||||||
char m_lastHost[256]; // Store the last URL to a webstream
|
char m_lastHost[256]; // Store the last URL to a webstream
|
||||||
|
char* m_playlistBuff = NULL; // stores playlistdata
|
||||||
uint8_t m_codec = CODEC_NONE; //
|
uint8_t m_codec = CODEC_NONE; //
|
||||||
|
uint8_t m_expectedCodec = CODEC_NONE; // set in connecttohost (e.g. http://url.mp3 -> CODEC_MP3)
|
||||||
|
uint8_t m_expectedPlsFmt = FORMAT_NONE; // set in connecttohost (e.g. streaming01.m3u) -> FORMAT_M3U)
|
||||||
|
uint8_t m_streamType = ST_NONE;
|
||||||
uint8_t m_rev=0; // Revision
|
uint8_t m_rev=0; // Revision
|
||||||
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
uint8_t m_playlistFormat = 0; // M3U, PLS, ASX
|
||||||
size_t m_file_size = 0; // size of the file
|
size_t m_file_size = 0; // size of the file
|
||||||
@@ -178,15 +192,23 @@ private:
|
|||||||
bool m_f_firstchunk=true; // First chunk as input
|
bool m_f_firstchunk=true; // First chunk as input
|
||||||
bool m_f_swm = true; // Stream without metadata
|
bool m_f_swm = true; // Stream without metadata
|
||||||
bool m_f_tts = false; // text to speech
|
bool m_f_tts = false; // text to speech
|
||||||
|
bool m_f_Log = false; // set in platformio.ini -DAUDIO_LOG and -DCORE_DEBUG_LEVEL=3 or 4
|
||||||
|
bool m_f_continue = false; // next m3u8 chunk is available
|
||||||
|
bool m_f_ts = true; // transport stream
|
||||||
bool m_f_webfile = false;
|
bool m_f_webfile = false;
|
||||||
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
bool m_f_firstCall = false; // InitSequence for processWebstream and processLokalFile
|
||||||
int m_LFcount; // Detection of end of header
|
int m_LFcount; // Detection of end of header
|
||||||
uint32_t m_chunkcount = 0 ; // Counter for chunked transfer
|
uint32_t m_chunkcount = 0 ; // Counter for chunked transfer
|
||||||
uint32_t m_contentlength = 0;
|
uint32_t m_contentlength = 0;
|
||||||
|
uint32_t m_resumeFilePos = 0;
|
||||||
uint32_t m_metaint = 0; // Number of databytes between metadata
|
uint32_t m_metaint = 0; // Number of databytes between metadata
|
||||||
uint32_t m_t0 = 0; // store millis(), is needed for a small delay
|
uint32_t m_t0 = 0; // store millis(), is needed for a small delay
|
||||||
uint16_t m_bitrate = 0; // Bitrate in kb/sec
|
uint16_t m_bitrate = 0; // Bitrate in kb/sec
|
||||||
int16_t m_btp=0; // Bytes to play
|
int16_t m_btp=0; // Bytes to play
|
||||||
|
uint16_t m_streamTitleHash = 0; // remember streamtitle, ignore multiple occurence in metadata
|
||||||
|
uint16_t m_streamUrlHash = 0; // remember streamURL, ignore multiple occurence in metadata
|
||||||
|
uint16_t m_timeout_ms = 250;
|
||||||
|
uint16_t m_timeout_ms_ssl = 2700;
|
||||||
int m_metacount=0; // Number of bytes in metadata
|
int m_metacount=0; // Number of bytes in metadata
|
||||||
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
int m_controlCounter = 0; // Status within readID3data() and readWaveHeader()
|
||||||
bool m_firstmetabyte=false; // True if first metabyte (counter)
|
bool m_firstmetabyte=false; // True if first metabyte (counter)
|
||||||
@@ -203,8 +225,8 @@ private:
|
|||||||
88,90,91,92,93,94,95,96,97,98,99,100}; //22 elements
|
88,90,91,92,93,94,95,96,97,98,99,100}; //22 elements
|
||||||
protected:
|
protected:
|
||||||
inline void DCS_HIGH() {(dcs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << (dcs_pin - 32) : GPIO.out_w1ts = 1 << dcs_pin;}
|
inline void DCS_HIGH() {(dcs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << (dcs_pin - 32) : GPIO.out_w1ts = 1 << dcs_pin;}
|
||||||
inline void DCS_LOW() {(dcs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << (dcs_pin - 32) : GPIO.out_w1tc = 1 << dcs_pin;}
|
inline void DCS_LOW() {(dcs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << (dcs_pin - 32) : GPIO.out_w1tc = 1 << dcs_pin;}
|
||||||
inline void CS_HIGH() {( cs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << ( cs_pin - 32) : GPIO.out_w1ts = 1 << cs_pin;}
|
inline void CS_HIGH() {( cs_pin&0x20) ? GPIO.out1_w1ts.data = 1 << ( cs_pin - 32) : GPIO.out_w1ts = 1 << cs_pin;}
|
||||||
inline void CS_LOW() {( cs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << ( cs_pin - 32) : GPIO.out_w1tc = 1 << cs_pin;}
|
inline void CS_LOW() {( cs_pin&0x20) ? GPIO.out1_w1tc.data = 1 << ( cs_pin - 32) : GPIO.out_w1tc = 1 << cs_pin;}
|
||||||
inline void await_data_request() {while(!digitalRead(dreq_pin)) NOP();} // Very short delay
|
inline void await_data_request() {while(!digitalRead(dreq_pin)) NOP();} // Very short delay
|
||||||
inline bool data_request() {return(digitalRead(dreq_pin) == HIGH);}
|
inline bool data_request() {return(digitalRead(dreq_pin) == HIGH);}
|
||||||
@@ -231,10 +253,15 @@ protected:
|
|||||||
void showID3Tag(const char* tag, const char* value);
|
void showID3Tag(const char* tag, const char* value);
|
||||||
void processLocalFile();
|
void processLocalFile();
|
||||||
void processWebStream();
|
void processWebStream();
|
||||||
void processPlayListData();
|
size_t chunkedDataTransfer();
|
||||||
bool parseContentType(const char* ct);
|
bool readPlayListData();
|
||||||
|
const char* parsePlaylist_M3U();
|
||||||
|
const char* parsePlaylist_PLS();
|
||||||
|
const char* parsePlaylist_ASX();
|
||||||
|
// const char* parsePlaylist_M3U8();
|
||||||
|
bool parseContentType(char* ct);
|
||||||
bool latinToUTF8(char* buff, size_t bufflen);
|
bool latinToUTF8(char* buff, size_t bufflen);
|
||||||
void processAudioHeaderData();
|
bool parseHttpResponseHeader();
|
||||||
bool readMetadata(uint8_t b, bool first = false);
|
bool readMetadata(uint8_t b, bool first = false);
|
||||||
void UTF8toASCII(char* str);
|
void UTF8toASCII(char* str);
|
||||||
void unicode2utf8(char* buff, uint32_t len);
|
void unicode2utf8(char* buff, uint32_t len);
|
||||||
@@ -242,26 +269,31 @@ protected:
|
|||||||
void loadUserCode();
|
void loadUserCode();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()!
|
// Constructor. Only sets pin values. Doesn't touch the chip. Be sure to call begin()!
|
||||||
|
//Audio(uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi, uint8_t mosi, uint8_t miso, uint8_t sclk);
|
||||||
Audio ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi = VSPI, uint8_t mosi = 23, uint8_t miso = 19, uint8_t sclk = 18);
|
Audio ( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t spi = VSPI, uint8_t mosi = 23, uint8_t miso = 19, uint8_t sclk = 18);
|
||||||
~Audio();
|
~Audio();
|
||||||
|
|
||||||
void begin() ; // Begin operation. Sets pins correctly and prepares SPI bus.
|
void begin() ; // Begin operation. Sets pins correctly and prepares SPI bus.
|
||||||
void stop_mp3client();
|
uint32_t stop_mp3client();
|
||||||
void setVolume(uint8_t vol); // Set the player volume.Level from 0-21, higher is louder.
|
void setVolume(uint8_t vol); // Set the player volume.Level from 0-21, higher is louder.
|
||||||
void setTone(int8_t* rtone); // Set the player baas/treble, 4 nibbles for treble gain/freq and bass gain/freq
|
void setTone(int8_t* rtone); // Set the player baas/treble, 4 nibbles for treble gain/freq and bass gain/freq
|
||||||
uint8_t getVolume(); // Get the current volume setting, higher is louder.
|
uint8_t getVolume(); // Get the current volume setting, higher is louder.
|
||||||
void printDetails(const char* str); // Print configuration details to serial output.
|
void printDetails(const char* str); // Print configuration details to serial output.
|
||||||
const char* printVersion(); // Print ID and version of vs1053 chip
|
uint8_t printVersion(); // Returns version of vs1053 chip
|
||||||
|
uint32_t printChipID(); // Returns chipID of vs1053 chip
|
||||||
void softReset() ; // Do a soft reset
|
void softReset() ; // Do a soft reset
|
||||||
void loop();
|
void loop();
|
||||||
|
void setConnectionTimeout(uint16_t timeout_ms, uint16_t timeout_ms_ssl);
|
||||||
bool connecttohost(String host);
|
bool connecttohost(String host);
|
||||||
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
bool connecttohost(const char* host, const char* user = "", const char* pwd = "");
|
||||||
bool connecttoSD(String sdfile);
|
bool connecttoSD(String sdfile, uint32_t resumeFilePos = 0);
|
||||||
bool connecttoSD(const char* sdfile);
|
bool connecttoSD(const char* sdfile, uint32_t resumeFilePos = 0);
|
||||||
bool connecttoFS(fs::FS &fs, const char* path);
|
bool connecttoFS(fs::FS &fs, const char* path, uint32_t resumeFilePos = 0);
|
||||||
bool connecttospeech(const char* speech, const char* lang);
|
bool connecttospeech(const char* speech, const char* lang);
|
||||||
|
bool isRunning() {return m_f_running;}
|
||||||
uint32_t getFileSize();
|
uint32_t getFileSize();
|
||||||
uint32_t getFilePos();
|
uint32_t getFilePos();
|
||||||
uint32_t getAudioDataStartPos();
|
uint32_t getAudioDataStartPos();
|
||||||
@@ -269,17 +301,17 @@ public:
|
|||||||
SemaphoreHandle_t mutex_pl=NULL;
|
SemaphoreHandle_t mutex_pl=NULL;
|
||||||
size_t bufferFilled();
|
size_t bufferFilled();
|
||||||
size_t bufferFree();
|
size_t bufferFree();
|
||||||
uint32_t inBufferFilled(); // returns the number of stored bytes in the inputbuffer
|
size_t inBufferFilled(){ return bufferFilled(); }
|
||||||
uint32_t inBufferFree(); // returns the number of free bytes in the inputbuffer
|
size_t inBufferFree(){ return bufferFree(); }
|
||||||
bool isRunning() {/*Serial.printf("m_f_running=%d\n", m_f_running); */return m_f_running;}
|
void setBalance(int8_t bal = 0);
|
||||||
void setBalance(int8_t bal = 0);
|
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
||||||
void setTone(int8_t gainLowPass, int8_t gainBandPass, int8_t gainHighPass);
|
|
||||||
void setDefaults();
|
void setDefaults();
|
||||||
void forceMono(bool m) {} // TODO
|
void forceMono(bool m) {} // TODO
|
||||||
/* VU METER */
|
/* VU METER */
|
||||||
void setVUmeter();
|
void setVUmeter();
|
||||||
void getVUlevel();
|
void getVUlevel();
|
||||||
uint8_t vuLeft, vuRight;
|
uint8_t vuLeft, vuRight;
|
||||||
|
|
||||||
// implement several function with respect to the index of string
|
// implement several function with respect to the index of string
|
||||||
bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;}
|
bool startsWith (const char* base, const char* str) { return (strstr(base, str) - base) == 0;}
|
||||||
bool endsWith (const char* base, const char* str) {
|
bool endsWith (const char* base, const char* str) {
|
||||||
@@ -287,17 +319,27 @@ public:
|
|||||||
int slen = strlen(str);
|
int slen = strlen(str);
|
||||||
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
|
return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
|
||||||
}
|
}
|
||||||
int indexOf (const char* base, const char* str, int startIndex) {
|
|
||||||
int result;
|
int indexOf (const char* base, const char* str, int startIndex = 0) {
|
||||||
int baselen = strlen(base);
|
//fb
|
||||||
if (strlen(str) > baselen || startIndex > baselen) result = -1;
|
const char *p = base;
|
||||||
else {
|
for (; startIndex > 0; startIndex--)
|
||||||
char* pos = strstr(base + startIndex, str);
|
if (*p++ == '\0') return -1;
|
||||||
if (pos == NULL) result = -1;
|
char* pos = strstr(p, str);
|
||||||
else result = pos - base;
|
if (pos == nullptr) return -1;
|
||||||
}
|
return pos - base;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int indexOf (const char* base, char ch, int startIndex = 0) {
|
||||||
|
//fb
|
||||||
|
const char *p = base;
|
||||||
|
for (; startIndex > 0; startIndex--)
|
||||||
|
if (*p++ == '\0') return -1;
|
||||||
|
char *pos = strchr(p, ch);
|
||||||
|
if (pos == nullptr) return -1;
|
||||||
|
return pos - base;
|
||||||
|
}
|
||||||
|
|
||||||
int lastIndexOf(const char* base, const char* str) {
|
int lastIndexOf(const char* base, const char* str) {
|
||||||
int res = -1, result = -1;
|
int res = -1, result = -1;
|
||||||
int lenBase = strlen(base);
|
int lenBase = strlen(base);
|
||||||
@@ -355,19 +397,40 @@ public:
|
|||||||
}
|
}
|
||||||
return expectedLen;
|
return expectedLen;
|
||||||
}
|
}
|
||||||
void trim(char* s){
|
|
||||||
uint8_t l = 0;
|
void trim(char *s) {
|
||||||
while(isspace(*(s + l))) l++;
|
//fb trim in place
|
||||||
for(uint16_t i = 0; i< strlen(s) - l; i++) *(s + i) = *(s + i + l); // ltrim
|
char *pe;
|
||||||
char* back = s + strlen(s);
|
char *p = s;
|
||||||
while(isspace(*--back));
|
while ( isspace(*p) ) p++; //left
|
||||||
*(back + 1) = '\0'; // rtrim
|
pe = p; //right
|
||||||
|
while ( *pe != '\0' ) pe++;
|
||||||
|
do {
|
||||||
|
pe--;
|
||||||
|
} while ( (pe > p) && isspace(*pe) );
|
||||||
|
if (p == s) {
|
||||||
|
*++pe = '\0';
|
||||||
|
} else { //move
|
||||||
|
while ( p <= pe ) *s++ = *p++;
|
||||||
|
*s = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vector_clear_and_shrink(std::vector<char*>&vec){
|
||||||
|
uint size = vec.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if(vec[i]){
|
||||||
|
free(vec[i]);
|
||||||
|
vec[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec.clear();
|
||||||
|
vec.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
inline uint8_t getDatamode(){return m_datamode;}
|
inline uint8_t getDatamode(){return m_datamode;}
|
||||||
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
inline void setDatamode(uint8_t dm){m_datamode=dm;}
|
||||||
inline uint32_t streamavail() {if(m_f_ssl==false) return client.available(); else return clientsecure.available();}
|
inline uint32_t streamavail(){ return _client ? _client->available() : 0;}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user