fresh start including: ICY, SD, SNAP
This commit is contained in:
parent
b2f7b9cc79
commit
220f959e51
4
partitions-4m-factory.csv
Normal file
4
partitions-4m-factory.csv
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Name, Type, SubType, Offset, Size, Flags
|
||||||
|
nvs, data, nvs, 0x9000, 0x6000,
|
||||||
|
phy_init, data, phy, 0xf000, 0x1000,
|
||||||
|
factory, app, factory, 0x10000, 4M
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
platform = espressif32
|
platform = espressif32
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
board_build.partitions = partitions-4m-factory.csv
|
||||||
lib_deps = https://github.com/pschatzmann/arduino-snapclient
|
lib_deps = https://github.com/pschatzmann/arduino-snapclient
|
||||||
https://github.com/pschatzmann/arduino-audio-tools
|
https://github.com/pschatzmann/arduino-audio-tools
|
||||||
https://github.com/pschatzmann/arduino-audio-driver
|
https://github.com/pschatzmann/arduino-audio-driver
|
||||||
https://github.com/pschatzmann/arduino-libopus
|
https://github.com/pschatzmann/arduino-libopus
|
||||||
https://github.com/bblanchon/ArduinoJson
|
https://github.com/bblanchon/ArduinoJson
|
||||||
|
https://github.com/pschatzmann/arduino-libhelix
|
||||||
37
src/Entry.h
37
src/Entry.h
@ -1,37 +0,0 @@
|
|||||||
#ifndef ENTRY_H
|
|
||||||
#define ENTRY_H
|
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
|
|
||||||
enum Type {
|
|
||||||
T_UNKNOWN_,
|
|
||||||
T_SNAP,
|
|
||||||
T_FILE,
|
|
||||||
T_HTTP,
|
|
||||||
};
|
|
||||||
|
|
||||||
static Type typeFromString(const String &name) {
|
|
||||||
if (name.equals("SNAP")) {
|
|
||||||
return T_SNAP;
|
|
||||||
}
|
|
||||||
if (name.equals("FILE")) {
|
|
||||||
return T_FILE;
|
|
||||||
}
|
|
||||||
if (name.equals("HTTP")) {
|
|
||||||
return T_HTTP;
|
|
||||||
}
|
|
||||||
Serial.printf("[ERROR] _isPlaying: type not implemented: %s\n", name.c_str());
|
|
||||||
return T_UNKNOWN_;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Entry {
|
|
||||||
|
|
||||||
Type type;
|
|
||||||
|
|
||||||
String url;
|
|
||||||
|
|
||||||
String title;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
222
src/Player.cpp
222
src/Player.cpp
@ -1,222 +0,0 @@
|
|||||||
#include "Player.h"
|
|
||||||
|
|
||||||
#include <LittleFS.h>
|
|
||||||
|
|
||||||
Player::Player() : board(AudioKitEs8388V1), opus(), snap(wifi, board, opus) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void Player::loop() {
|
|
||||||
if (playlistRequest) {
|
|
||||||
playlistRequest = false;
|
|
||||||
_loadPlaylist();
|
|
||||||
}
|
|
||||||
if (_isPlaying()) {
|
|
||||||
switch (should) {
|
|
||||||
case PLAY:
|
|
||||||
if (current != wanted) {
|
|
||||||
_stop();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PAUSE:
|
|
||||||
_pause();
|
|
||||||
break;
|
|
||||||
case STOP:
|
|
||||||
_stop();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (should == PLAY) {
|
|
||||||
_start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void Player::loadPlaylist(const String &path) {
|
|
||||||
playlistPath = path;
|
|
||||||
playlistRequest = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::play() {
|
|
||||||
if (entries != nullptr && playlistSize > 0 && wanted == nullptr) {
|
|
||||||
wanted = entries;
|
|
||||||
}
|
|
||||||
should = PLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::pause() {
|
|
||||||
should = PAUSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::stop() {
|
|
||||||
should = STOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::next() {
|
|
||||||
skip(+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::previous() {
|
|
||||||
skip(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::skip(const int count) {
|
|
||||||
if (entries == nullptr || playlistSize <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
playIndex(((wanted - entries + count) % playlistSize + playlistSize) % playlistSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::playIndex(const size_t index) {
|
|
||||||
if (entries == nullptr || playlistSize <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wanted = index % playlistSize + entries;
|
|
||||||
should = PLAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void Player::_loadPlaylist() {
|
|
||||||
playlistRequest = false;
|
|
||||||
|
|
||||||
_stop();
|
|
||||||
|
|
||||||
if (entries != nullptr) {
|
|
||||||
free(entries);
|
|
||||||
entries = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!LittleFS.exists(playlistPath)) {
|
|
||||||
Serial.println("Playlist file not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = LittleFS.open(playlistPath, "r");
|
|
||||||
if (!file) {
|
|
||||||
Serial.println("Failed to open playlist file.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonDocument playlist;
|
|
||||||
const auto error = deserializeJson(playlist, file);
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
Serial.println("Failed to parse playlist JSON.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto jsonEntries = playlist["entries"].as<JsonArray>();
|
|
||||||
playlistSize = jsonEntries.size();
|
|
||||||
if (playlistSize <= 0) {
|
|
||||||
Serial.printf("Loaded playlist is empty.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries = static_cast<Entry *>(malloc(sizeof(Entry) * playlistSize));
|
|
||||||
wanted = entries;
|
|
||||||
|
|
||||||
Entry *entry = entries;
|
|
||||||
for (auto jsonVar: jsonEntries) {
|
|
||||||
auto jsonEntry = jsonVar.as<JsonObject>();
|
|
||||||
if (jsonEntry == NULL) {
|
|
||||||
Serial.printf("Entry #%03d is not a JsonObject\n", entry - entries);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!jsonEntry["type"].is<String>()) {
|
|
||||||
Serial.printf("Entry #%03d has no String 'type'\n", entry - entries);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!jsonEntry["url"].is<String>()) {
|
|
||||||
Serial.printf("Entry #%03d has no String 'url'\n", entry - entries);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!jsonEntry["title"].is<String>()) {
|
|
||||||
Serial.printf("Entry #%03d has no String 'title'\n", entry - entries);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
entry->type = typeFromString(jsonEntry["type"].as<String>());
|
|
||||||
entry->url = jsonEntry["url"].as<String>();
|
|
||||||
entry->title = jsonEntry["title"].as<String>();
|
|
||||||
entry++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Player::_isPlaying() {
|
|
||||||
if (entries == nullptr || current == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (current->type) {
|
|
||||||
case T_SNAP:
|
|
||||||
return snap.doLoop();
|
|
||||||
default:
|
|
||||||
Serial.printf("[ERROR] _isPlaying: type not implemented: %d\n", current->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::_start() {
|
|
||||||
current = wanted;
|
|
||||||
if (entries == nullptr || current == nullptr) {
|
|
||||||
Serial.println("[ERROR] _start: current == null => STOP");
|
|
||||||
should = STOP;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
switch (current->type) {
|
|
||||||
case T_SNAP:
|
|
||||||
success = _snapStart(current->url);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Serial.printf("[ERROR] _start: type not implemented: %d\n", current->type);
|
|
||||||
success = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (success) {
|
|
||||||
Serial.printf("Started: #%03d: %s\n", current - entries, current->url.c_str());
|
|
||||||
} else {
|
|
||||||
Serial.printf("Failed to start: #%03d: %s\n", current - entries, current->url.c_str());
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::_pause() {
|
|
||||||
switch (current->type) {
|
|
||||||
case T_SNAP:
|
|
||||||
snap.end();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Serial.printf("[ERROR] _pause: type not implemented: %d\n", current->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::_stop() {
|
|
||||||
if (current != nullptr) {
|
|
||||||
switch (current->type) {
|
|
||||||
case T_SNAP:
|
|
||||||
snap.end();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Serial.printf("[ERROR] _stop: type not implemented: %d\n", current->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = nullptr;
|
|
||||||
wanted = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool Player::_snapStart(const String &host) {
|
|
||||||
IPAddress ip;
|
|
||||||
WiFi.hostByName(host.c_str(), ip);
|
|
||||||
snap.setServerIP(ip);
|
|
||||||
return snap.begin();
|
|
||||||
}
|
|
||||||
86
src/Player.h
86
src/Player.h
@ -1,86 +0,0 @@
|
|||||||
#ifndef PLAYER_H
|
|
||||||
#define PLAYER_H
|
|
||||||
|
|
||||||
#include "Entry.h"
|
|
||||||
|
|
||||||
#include <WString.h>
|
|
||||||
|
|
||||||
#include "SnapClient.h"
|
|
||||||
#include "AudioTools/AudioCodecs/CodecOpus.h"
|
|
||||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
STOP, PLAY, PAUSE
|
|
||||||
};
|
|
||||||
|
|
||||||
class Player {
|
|
||||||
|
|
||||||
WiFiClient wifi;
|
|
||||||
|
|
||||||
AudioBoardStream board;
|
|
||||||
|
|
||||||
OpusAudioDecoder opus;
|
|
||||||
|
|
||||||
SnapClient snap;
|
|
||||||
|
|
||||||
String playlistPath;
|
|
||||||
|
|
||||||
size_t playlistSize = 0;
|
|
||||||
|
|
||||||
bool playlistRequest = false;
|
|
||||||
|
|
||||||
Entry *entries = nullptr;
|
|
||||||
|
|
||||||
Entry *wanted = nullptr;
|
|
||||||
|
|
||||||
Entry *current = nullptr;
|
|
||||||
|
|
||||||
State should = STOP;
|
|
||||||
|
|
||||||
bool repeatAll = false;
|
|
||||||
|
|
||||||
bool repeatOne = false;
|
|
||||||
|
|
||||||
bool shuffle = false;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Player();
|
|
||||||
|
|
||||||
void loop();
|
|
||||||
|
|
||||||
void loadPlaylist(const String &path);
|
|
||||||
|
|
||||||
void play();
|
|
||||||
|
|
||||||
void pause();
|
|
||||||
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
void skip(int count);
|
|
||||||
|
|
||||||
void next();
|
|
||||||
|
|
||||||
void previous();
|
|
||||||
|
|
||||||
void playIndex(size_t index);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void _loadPlaylist();
|
|
||||||
|
|
||||||
void _start();
|
|
||||||
|
|
||||||
bool _isPlaying();
|
|
||||||
|
|
||||||
void _pause();
|
|
||||||
|
|
||||||
void _stop();
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
|
|
||||||
bool _snapStart(const String &host);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
202
src/audio.cpp
202
src/audio.cpp
@ -1,76 +1,176 @@
|
|||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
#include "SnapClient.h"
|
#include "AudioTools.h"
|
||||||
#include "wifi.h"
|
|
||||||
#include "AudioTools/AudioCodecs/CodecOpus.h"
|
|
||||||
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
#include "AudioTools/AudioLibs/AudioBoardStream.h"
|
||||||
|
#include "AudioTools/AudioCodecs/CodecMP3Helix.h"
|
||||||
|
#include "AudioTools/AudioCodecs/CodecOpus.h"
|
||||||
|
|
||||||
WiFiClient wifi;
|
#include <SPI.h>
|
||||||
|
#include <SD.h>
|
||||||
|
|
||||||
|
#include "SnapClient.h"
|
||||||
|
|
||||||
AudioBoardStream board(AudioKitEs8388V1);
|
AudioBoardStream board(AudioKitEs8388V1);
|
||||||
|
|
||||||
OpusAudioDecoder opus;
|
File file;
|
||||||
|
|
||||||
SnapClient snap(wifi, board, opus);
|
ICYStream icy;
|
||||||
|
|
||||||
unsigned long snapLast = 0;
|
WiFiClient wifi;
|
||||||
|
|
||||||
bool snapState = false;
|
OpusAudioDecoder opusDecoder;
|
||||||
|
|
||||||
void audioSetup() {
|
SnapClient snap(wifi, board, opusDecoder);
|
||||||
board.setVolume(0.1);
|
|
||||||
snap.setServerIP(IPAddress(10, 0, 0, 50));
|
MP3DecoderHelix mp3Decoder;
|
||||||
|
|
||||||
|
EncodedAudioStream mp3Stream(&board, &mp3Decoder);
|
||||||
|
|
||||||
|
StreamCopy copier;
|
||||||
|
|
||||||
|
bool running = false;
|
||||||
|
|
||||||
|
void audioStop() {
|
||||||
|
if (running) {
|
||||||
|
running = false;
|
||||||
|
Serial.println("[STOP]");
|
||||||
}
|
}
|
||||||
|
copier.end();
|
||||||
void audioStarted() {
|
mp3Stream.end();
|
||||||
Serial.printf("SNAP started\n");
|
mp3Decoder.end();
|
||||||
}
|
opusDecoder.end();
|
||||||
|
icy.end();
|
||||||
void audioStopped() {
|
file.close();
|
||||||
Serial.printf("SNAP stopped\n");
|
|
||||||
snapState = false;
|
|
||||||
snap.end();
|
snap.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioStart() {
|
bool audioBeginMP3Stream(const char *code, Stream &source) {
|
||||||
if (snapLast == 0 || millis() - snapLast >= 3000) {
|
if (!mp3Decoder.begin()) {
|
||||||
Serial.printf("SNAP connecting...\n");
|
Serial.printf("[%s] Failed to start MP3DecoderHelix.", code);
|
||||||
snapLast = max(1UL, millis());
|
audioStop();
|
||||||
snapState = snap.begin();
|
return false;
|
||||||
if (snapState) {
|
|
||||||
Serial.printf("SNAP connected\n");
|
|
||||||
} else {
|
|
||||||
Serial.printf("SNAP failed to connected\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audioLoop() {
|
if (!mp3Stream.begin()) {
|
||||||
if (!isWifiConnected()) {
|
Serial.printf("[%s] Failed to start EncodedAudioStream.", code);
|
||||||
snapLast = 0;
|
audioStop();
|
||||||
if (snapState) {
|
return false;
|
||||||
audioStopped();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto state = false;
|
copier.begin(mp3Stream, source);
|
||||||
if (snapState) {
|
|
||||||
state = snap.doLoop();
|
if (copier.copy() == 0) {
|
||||||
|
Serial.printf("[%s] Failed to copy initial data.", code);
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapState) {
|
return true;
|
||||||
if (state) {
|
|
||||||
// still running
|
|
||||||
} else {
|
|
||||||
audioStopped();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (state) {
|
bool audioPlayICY(const String &url) {
|
||||||
audioStarted();
|
audioStop();
|
||||||
} else {
|
|
||||||
audioStart();
|
Serial.printf("[ICY] %s", url.c_str());
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
if (!icy.begin(url.c_str())) {
|
||||||
|
Serial.println("[ICY] Failed to start ICYStream.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return audioBeginMP3Stream("ICY", icy);
|
||||||
}
|
}
|
||||||
snapState = state;
|
|
||||||
|
bool audioPlaySNAP(const String &host) {
|
||||||
|
audioStop();
|
||||||
|
|
||||||
|
Serial.printf("[SNAP] %s\n", host.c_str());
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
IPAddress ip;
|
||||||
|
if (!WiFiClass::hostByName(host.c_str(), ip)) {
|
||||||
|
Serial.println("[SNAP] Failed to resolve host.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
snap.setServerIP(ip);
|
||||||
|
if (!snap.begin()) {
|
||||||
|
Serial.println("[SNAP] Failed to connect.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opusDecoder.begin()) {
|
||||||
|
Serial.println("[SNAP] Failed to start OpusAudioDecoder.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!snap.doLoop()) {
|
||||||
|
Serial.println("[SNAP] Failed to copy initial data.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool audioPlaySD(const String &url) {
|
||||||
|
audioStop();
|
||||||
|
|
||||||
|
Serial.printf("[SD] %s\n", url.c_str());
|
||||||
|
running = true;
|
||||||
|
|
||||||
|
if (!SD.begin(PIN_AUDIO_KIT_SD_CARD_CS)) {
|
||||||
|
Serial.println("[SD] Failed to mount SD-card.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SD.exists(url.c_str())) {
|
||||||
|
Serial.println("[SD] File not found.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = SD.open(url.c_str(), FILE_READ);
|
||||||
|
if (!file) {
|
||||||
|
Serial.println("[SD] Failed to open file.");
|
||||||
|
audioStop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return audioBeginMP3Stream("SD", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool audioPlay(const String &url) {
|
||||||
|
if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||||
|
return audioPlayICY(url);
|
||||||
|
}
|
||||||
|
if (url.startsWith("sd://")) {
|
||||||
|
return audioPlaySD(url.substring(5));
|
||||||
|
}
|
||||||
|
if (url.startsWith("snap://") < 0) {
|
||||||
|
return audioPlaySNAP(url.substring(7));
|
||||||
|
}
|
||||||
|
Serial.printf("[ERROR] unknown protocol: %s\n", url.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void audioSetup() {
|
||||||
|
board.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool audioLoop() {
|
||||||
|
if (copier.copy() > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (running) {
|
||||||
|
Serial.println("Stream ended!");
|
||||||
|
audioStop();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/audio.h
12
src/audio.h
@ -1,8 +1,14 @@
|
|||||||
#ifndef SNAP_H
|
#ifndef AUDIO_H
|
||||||
#define SNAP_H
|
#define AUDIO_H
|
||||||
|
|
||||||
|
#include <WString.h>
|
||||||
|
|
||||||
|
bool audioPlay(const String &url);
|
||||||
|
|
||||||
|
void audioStop();
|
||||||
|
|
||||||
void audioSetup();
|
void audioSetup();
|
||||||
|
|
||||||
void audioLoop();
|
bool audioLoop();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#include "wifi.h"
|
#include "wifi.h"
|
||||||
#include "audio.h"
|
#include "player.h"
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
delay(500);
|
delay(500);
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
audioSetup();
|
playerSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
wifiLoop();
|
wifiLoop();
|
||||||
audioLoop();
|
playerLoop();
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/player.cpp
Normal file
42
src/player.cpp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
#define DELAY_MS_ADD 250UL
|
||||||
|
#define DELAY_MS_MAX 5000UL
|
||||||
|
|
||||||
|
unsigned long errorMs = 0;
|
||||||
|
|
||||||
|
unsigned long delayMs = 0;
|
||||||
|
|
||||||
|
void playerSetup() {
|
||||||
|
audioSetup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerLoop() {
|
||||||
|
if (audioLoop()) {
|
||||||
|
errorMs = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (errorMs > 0 && millis() - errorMs < delayMs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
playerNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerNext() {
|
||||||
|
playerPlay("http://liveradio.sr.de/sr/sr1/mp3/128/stream.mp3");
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerPlay(const String &url) {
|
||||||
|
if (audioPlay(url)) {
|
||||||
|
errorMs = 0;
|
||||||
|
delayMs = 0;
|
||||||
|
} else {
|
||||||
|
errorMs = max(1UL, millis());
|
||||||
|
delayMs = min(DELAY_MS_MAX, delayMs + DELAY_MS_ADD);
|
||||||
|
Serial.printf("retry delay: %d ms\n", delayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/player.h
Normal file
14
src/player.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef PLAYER_H
|
||||||
|
#define PLAYER_H
|
||||||
|
|
||||||
|
#include <WString.h>
|
||||||
|
|
||||||
|
void playerNext();
|
||||||
|
|
||||||
|
void playerPlay(const String &url);
|
||||||
|
|
||||||
|
void playerSetup();
|
||||||
|
|
||||||
|
void playerLoop();
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user