Files
yoradio/yoRadio/src/core/player.cpp
2023-03-29 09:41:11 +03:00

279 lines
7.3 KiB
C++

#include "options.h"
#include "player.h"
#include "config.h"
#include "telnet.h"
#include "display.h"
#include "netserver.h"
Player player;
QueueHandle_t playerQueue;
#if VS1053_CS!=255 && !I2S_INTERNAL
#if VS_HSPI
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ, HSPI, 13, 12, 14) {}
#else
Player::Player(): Audio(VS1053_CS, VS1053_DCS, VS1053_DREQ) {}
#endif
void ResetChip(){
pinMode(VS1053_RST, OUTPUT);
digitalWrite(VS1053_RST, LOW);
delay(30);
digitalWrite(VS1053_RST, HIGH);
delay(100);
}
#else
#if !I2S_INTERNAL
Player::Player() {}
#else
Player::Player(): Audio(true, I2S_DAC_CHANNEL_BOTH_EN) {}
#endif
#endif
void Player::init() {
Serial.print("##[BOOT]#\tplayer.init\t");
playerQueue=NULL;
playerQueue = xQueueCreate( 5, sizeof( playerRequestParams_t ) );
setOutputPins(false);
delay(50);
memset(_plError, 0, PLERR_LN);
#ifdef MQTT_ROOT_TOPIC
memset(burl, 0, MQTT_BURL_SIZE);
#endif
if(MUTE_PIN!=255) pinMode(MUTE_PIN, OUTPUT);
#if I2S_DOUT!=255
#if !I2S_INTERNAL
setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
#endif
#else
SPI.begin();
if(VS1053_RST>0) ResetChip();
begin();
#endif
setBalance(config.store.balance);
setTone(config.store.bass, config.store.middle, config.store.trebble);
setVolume(0);
_status = STOPPED;
//setOutputPins(false);
_volTimer=false;
playmutex = xSemaphoreCreateMutex();
randomSeed(analogRead(0));
#if PLAYER_FORCE_MONO
forceMono(true);
#endif
_loadVol(config.store.volume);
setConnectionTimeout(1700, 3700);
Serial.println("done");
}
void Player::sendCommand(playerRequestParams_t request){
if(playerQueue==NULL) return;
xQueueSend(playerQueue, &request, portMAX_DELAY);
}
void Player::stopInfo() {
config.setSmartStart(0);
//telnet.info();
netserver.requestOnChange(MODE, 0);
}
void Player::setError(const char *e){
strlcpy(_plError, e, PLERR_LN);
if(hasError()) {
config.setTitle(_plError);
telnet.printf("##ERROR#:\t%s\n", e);
}
}
void Player::_stop(bool alreadyStopped){
if(config.store.play_mode==PM_SDCARD) config.sdResumePos = player.getFilePos();
_status = STOPPED;
setOutputPins(false);
if(!hasError()) config.setTitle((display.mode()==LOST || display.mode()==UPDATING)?"":const_PlStopped);
config.station.bitrate = 0;
#ifdef USE_NEXTION
nextion.bitrate(config.station.bitrate);
#endif
netserver.requestOnChange(BITRATE, 0);
display.putRequest(DBITRATE);
display.putRequest(PSTOP);
setDefaults();
if(!alreadyStopped) stopSong();
if(!lockOutput) stopInfo();
if (player_on_stop_play) player_on_stop_play();
}
void Player::initHeaders(const char *file) {
if(strlen(file)==0) return;
connecttoFS(SD,file);
eofHeader = false;
while(!eofHeader) Audio::loop();
//netserver.requestOnChange(SDPOS, 0);
setDefaults();
}
#ifndef PL_QUEUE_TICKS
#define PL_QUEUE_TICKS 0
#endif
void Player::loop() {
if(playerQueue==NULL) return;
playerRequestParams_t requestP;
if(xQueueReceive(playerQueue, &requestP, PL_QUEUE_TICKS)){
switch (requestP.type){
case PR_STOP: _stop(); break;
case PR_PLAY: {
if (requestP.payload>0) {
config.setLastStation((uint16_t)requestP.payload);
}
_play((uint16_t)abs(requestP.payload));
if (player_on_station_change) player_on_station_change();
break;
}
case PR_VOL: {
config.setVolume(requestP.payload);
Audio::setVolume(volToI2S(requestP.payload));
break;
}
default: break;
}
}
xSemaphoreTake(playmutex, portMAX_DELAY);
Audio::loop();
xSemaphoreGive(playmutex);
if(!isRunning() && _status==PLAYING) _stop(true);
if(_volTimer){
if((millis()-_volTicks)>3000){
config.saveVolume();
_volTimer=false;
}
}
#ifdef MQTT_ROOT_TOPIC
if(strlen(burl)>0){
browseUrl();
}
#endif
}
void Player::setOutputPins(bool isPlaying) {
if(LED_BUILTIN!=255) digitalWrite(LED_BUILTIN, LED_INVERT?!isPlaying:isPlaying);
bool _ml = MUTE_LOCK?!MUTE_VAL:(isPlaying?!MUTE_VAL:MUTE_VAL);
if(MUTE_PIN!=255) digitalWrite(MUTE_PIN, _ml);
}
void Player::_play(uint16_t stationId) {
setError("");
remoteStationName = false;
config.setDspOn(1);
display.putRequest(PSTOP);
setOutputPins(false);
config.setTitle(config.store.play_mode==PM_WEB?const_PlConnect:"");
config.station.bitrate=0;
config.loadStation(stationId);
_loadVol(config.store.volume);
display.putRequest(NEWSTATION);
netserver.requestOnChange(STATION, 0);
netserver.loop();
netserver.loop();
if (config.store.play_mode==PM_WEB?connecttohost(config.station.url):connecttoFS(SD,config.station.url,config.sdResumePos==0?_resumeFilePos:config.sdResumePos-player.sd_min)) {
_status = PLAYING;
if(config.store.play_mode==PM_SDCARD) config.sdResumePos = 0;
//config.setTitle("");
config.setSmartStart(1);
netserver.requestOnChange(MODE, 0);
setOutputPins(true);
display.putRequest(PSTART);
if (player_on_start_play) player_on_start_play();
}else{
telnet.printf("##ERROR#:\tError connecting to %s\n", config.station.url);
SET_PLAY_ERROR("Error connecting to %s", config.station.url);
_stop(true);
};
}
#ifdef MQTT_ROOT_TOPIC
void Player::browseUrl(){
setError("");
remoteStationName = true;
config.setDspOn(1);
resumeAfterUrl = _status==PLAYING;
display.putRequest(PSTOP);
// setDefaults();
setOutputPins(false);
config.setTitle(const_PlConnect);
if (connecttohost(burl)){
_status = PLAYING;
config.setTitle("");
netserver.requestOnChange(MODE, 0);
setOutputPins(true);
display.putRequest(PSTART);
if (player_on_start_play) player_on_start_play();
}else{
telnet.printf("##ERROR#:\tError connecting to %s\n", burl);
SET_PLAY_ERROR("Error connecting to %s", burl);
_stop(true);
}
memset(burl, 0, MQTT_BURL_SIZE);
}
#endif
void Player::prev() {
if(config.store.play_mode==PM_WEB || !config.sdSnuffle){
if (config.store.lastStation == 1) config.store.lastStation = config.store.countStation; else config.store.lastStation--;
}
sendCommand({PR_PLAY, config.store.lastStation});
}
void Player::next() {
if(config.store.play_mode==PM_WEB || !config.sdSnuffle){
if (config.store.lastStation == config.store.countStation) config.store.lastStation = 1; else config.store.lastStation++;
}else{
config.store.lastStation = random(1, config.store.countStation);
}
sendCommand({PR_PLAY, config.store.lastStation});
}
void Player::toggle() {
if (_status == PLAYING) {
sendCommand({PR_STOP, 0});
} else {
sendCommand({PR_PLAY, config.store.lastStation});
}
}
void Player::stepVol(bool up) {
if (up) {
if (config.store.volume <= 254 - config.store.volsteps) {
setVol(config.store.volume + config.store.volsteps);
}else{
setVol(254);
}
} else {
if (config.store.volume >= config.store.volsteps) {
setVol(config.store.volume - config.store.volsteps);
}else{
setVol(0);
}
}
}
uint8_t Player::volToI2S(uint8_t volume) {
int vol = map(volume, 0, 254 - config.station.ovol * 3 , 0, 254);
if (vol > 254) vol = 254;
if (vol < 0) vol = 0;
return vol;
}
void Player::_loadVol(uint8_t volume) {
setVolume(volToI2S(volume));
}
void Player::setVol(uint8_t volume) {
_volTicks = millis();
_volTimer = true;
player.sendCommand({PR_VOL, volume});
}