Files
yoradio/yoRadio/yoRadio.ino
2022-12-26 17:42:37 +03:00

210 lines
6.4 KiB
C++

/* ============================================================================================================
* ёRadio
* ============================================================================================================
* Web-radio based on
* ESP32-audioI2S https://github.com/schreibfaul1/ESP32-audioI2S
* or/and
* ESP32-vs1053_ext https://github.com/schreibfaul1/ESP32-vs1053_ext
* libraries
* ============================================================================================================
* Project home https://github.com/e2002/yoradio
* Wiki https://github.com/e2002/yoradio/wiki
* Описание на 4PDA https://4pda.to/forum/index.php?s=&showtopic=1010378&view=findpost&p=112992611
* Как это прошить? https://4pda.to/forum/index.php?act=findpost&pid=112992611&anchor=Spoil-112992611-2
* ============================================================================================================
* Here goes!
* ============================================================================================================
*/
#include "Arduino.h"
#include "src/core/options.h"
#include "src/core/config.h"
#include "src/core/telnet.h"
#include "src/core/player.h"
#include "src/core/display.h"
#include "src/core/network.h"
#include "src/core/netserver.h"
#include "src/core/controls.h"
#include "src/core/mqtt.h"
#include "src/core/optionschecker.h"
extern __attribute__((weak)) void yoradio_on_setup();
void setup() {
Serial.begin(115200);
if(LED_BUILTIN!=255) pinMode(LED_BUILTIN, OUTPUT);
if (yoradio_on_setup) yoradio_on_setup();
config.init();
display.init();
player.init();
network.begin();
if (network.status != CONNECTED) {
netserver.begin();
display.putRequest(DSP_START);
while(!display.ready()) delay(10);
return;
}
netserver.begin();
telnet.begin();
#if PLAYER_FORCE_MONO
player.forceMono(true);
#endif
player.setVol(config.store.volume, true);
initControls();
display.putRequest(DSP_START);
while(!display.ready()) delay(10);
#ifdef MQTT_HOST
mqttInit();
#endif
if (config.store.play_mode==PM_SDCARD) player.initHeaders(config.station.url);
player.lockOutput=false;
if (config.store.smartstart == 1) player.play(config.store.lastStation);
}
void loop() {
telnet.loop();
if (network.status == CONNECTED) {
player.loop();
loopControls();
checkConnection();
}
netserver.loop();
}
void checkConnection(){
static uint32_t checkMillis = 0;
static uint32_t checkInterval = 3000;
if ((WiFi.status() != WL_CONNECTED) && (millis() - checkMillis >=checkInterval)) {
bool playing = player.isRunning();
if (playing) player.mode = STOPPED;
display.putRequest(NEWMODE, LOST);
Serial.println("Lost connection, reconnecting...");
while(true){
if (WiFi.status() == WL_CONNECTED) break;
WiFi.disconnect();
WiFi.reconnect();
delay(3000);
}
display.putRequest(NEWMODE, PLAYER);
if (playing) player.request.station = config.store.lastStation;
checkMillis = millis();
#ifdef MQTT_HOST
connectToMqtt();
#endif
}
}
//=============================================//
// Audio handlers //
//=============================================//
void audio_info(const char *info) {
if(player.lockOutput) return;
if(config.store.audioinfo) telnet.printf("##AUDIO.INFO#: %s\n", info);
#ifdef USE_NEXTION
nextion.audioinfo(info);
#endif
if (strstr(info, "skip metadata") != NULL){
config.setTitle(config.station.name);
netserver.requestOnChange(TITLE, 0);
}
if (strstr(info, "failed!") != NULL || strstr(info, " 404") != NULL || strstr(info, " 403") != NULL || strstr(info, "address is empty") != NULL) player.stop(info);
if (strstr(info, "not supported") != NULL || strstr(info, "Account already in use") != NULL || strstr(info, "HTTP/1.0 401") != NULL) player.stop(info);
char* ici; char b[20]={0};
if ((ici = strstr(info, "BitRate: ")) != NULL) {
strlcpy(b, ici + 9, 50);
audio_bitrate(b);
}
}
void audio_bitrate(const char *info)
{
if(config.store.audioinfo) telnet.printf("%s %s\n", "##AUDIO.BITRATE#:", info);
config.station.bitrate = atoi(info) / 1000;
display.putRequest(DBITRATE);
#ifdef USE_NEXTION
nextion.bitrate(config.station.bitrate);
#endif
netserver.requestOnChange(BITRATE, 0);
}
bool printable(const char *info) {
bool p = true;
for (int c = 0; c < strlen(info); c++)
{
if ((uint8_t)info[c] > 0x7e || (uint8_t)info[c] < 0x20) p = false;
}
if (!p) p = (uint8_t)info[0] >= 0xC2 && (uint8_t)info[1] >= 0x80 && (uint8_t)info[1] <= 0xBF;
return p;
}
void audio_showstation(const char *info) {
if (strlen(info) > 0) {
bool p = printable(info);
config.setTitle(p?info:config.station.name);
netserver.requestOnChange(TITLE, 0);
}
}
void audio_showstreamtitle(const char *info) {
DBGH();
if (strstr(info, "Account already in use") != NULL || strstr(info, "HTTP/1.0 401") != NULL){
player.stop(info);
return;
}
if (strlen(info) > 0) {
bool p = printable(info);
#ifdef DEBUG_TITLES
config.setTitle(DEBUG_TITLES);
#else
config.setTitle(p?info:config.station.name);
#endif
netserver.requestOnChange(TITLE, 0);
}
}
void audio_id3artist(const char *info){
if(printable(info)) config.setStation(info);
display.putRequest(NEWSTATION);
netserver.requestOnChange(STATION, 0);
}
void audio_id3album(const char *info){
if(player.lockOutput) return;
if(printable(info)){
if(strlen(config.station.title)==0){
config.setTitle(info);
}else{
char out[BUFLEN]= {0};
strlcat(out, config.station.title, BUFLEN);
strlcat(out, " - ", BUFLEN);
strlcat(out, info, BUFLEN);
config.setTitle(out);
}
netserver.requestOnChange(TITLE, 0);
}
}
void audio_id3title(const char *info){
audio_id3album(info);
}
void audio_beginSDread(){
config.setTitle("");
netserver.requestOnChange(TITLE, 0);
}
void audio_id3data(const char *info){ //id3 metadata
if(player.lockOutput) return;
telnet.printf("##AUDIO.ID3#: %s\n", info);
}
void audio_eof_mp3(const char *info){ //end of file
config.sdResumePos = 0;
player.play(random(1, config.store.countStation));
}
void audio_progress(uint32_t startpos, uint32_t endpos){
player.sd_min = startpos;
player.sd_max = endpos;
netserver.requestOnChange(SDLEN, 0);
}