#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 ) ); 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); requestToStart = true; _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); requestToStart = true; } 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(); 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); if(MUTE_PIN!=255) digitalWrite(MUTE_PIN, isPlaying?!MUTE_VAL:MUTE_VAL); } 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); requestToStart = 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); requestToStart = 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}); }