#include "audio.h" #include "AudioTools.h" #include "AudioTools/AudioLibs/AudioBoardStream.h" #include "AudioTools/AudioCodecs/CodecMP3Helix.h" #include "AudioTools/AudioCodecs/CodecOpus.h" #include #include #include #include "player.h" #include "wifi.h" bool audioMute = true; bool audioMute2 = true; // keep last applied mute state because we cannot retrieve it from library float audioVolume = 0.1; int copyErrors = 0; AudioBoardStream board(AudioKitEs8388V1); File file; ICYStream icy; WiFiClient wifi; OpusAudioDecoder opusDecoder; SnapClient snap(wifi, board, opusDecoder); MP3DecoderHelix mp3Decoder; EncodedAudioStream mp3Stream(&board, &mp3Decoder); StreamCopy mp3Copier; bool running = false; void audioStop() { if (running) { running = false; Serial.println("[AUDIO ] STOP"); } copyErrors = 0; mp3Copier.end(); mp3Stream.end(); mp3Decoder.end(); opusDecoder.end(); icy.end(); file.close(); // snap.end(); // TODO } bool audioPlayInit(const Entry &entry) { audioStop(); Serial.printf("[AUDIO ] [%s] Opening: %s\n", entry.type.c_str(), entry.url.c_str()); running = true; if (entry.type == "ICY" || entry.type == "SNAP") { if (!isWifiConnected()) { Serial.printf("[AUDIO ] [%s] WiFi not connected.\n", entry.type.c_str()); audioStop(); return false; } } if (entry.type == "SD") { if (!SD.begin(PIN_AUDIO_KIT_SD_CARD_CS)) { Serial.printf("[AUDIO ] [%s] Failed to mount SD-card.\n", entry.type.c_str()); audioStop(); return false; } } return true; } bool audioBeginMP3Stream(const Entry &entry, Stream &source) { if (!mp3Decoder.begin()) { Serial.printf("[AUDIO ] [%s] Failed to start MP3DecoderHelix.", entry.type.c_str()); audioStop(); return false; } if (!mp3Stream.begin()) { Serial.printf("[AUDIO ] [%s] Failed to start EncodedAudioStream.", entry.type.c_str()); audioStop(); return false; } mp3Copier.begin(mp3Stream, source); if (mp3Copier.copy() == 0) { Serial.printf("[AUDIO ] [%s] Failed to copy initial data.", entry.type.c_str()); audioStop(); return false; } Serial.printf("[AUDIO ] [%s] Stream running.\n", entry.type.c_str()); return true; } bool audioPlayICY(const Entry &entry) { if (!audioPlayInit(entry)) { return false; } if (!icy.begin(entry.url.c_str())) { Serial.printf("[AUDIO ] [%s] Failed to start ICYStream.\n", entry.type.c_str()); audioStop(); return false; } return audioBeginMP3Stream(entry, icy); } bool audioPlaySNAP(const Entry &entry) { if (!audioPlayInit(entry)) { return false; } IPAddress ip; if (!WiFiClass::hostByName(entry.url.c_str(), ip)) { Serial.printf("[AUDIO ] [%s] Failed to resolve host.\n", entry.type.c_str()); audioStop(); return false; } snap.setServerIP(ip); if (!snap.begin()) { Serial.printf("[AUDIO ] [%s] Failed to connect.\n", entry.type.c_str()); audioStop(); return false; } if (!opusDecoder.begin()) { Serial.printf("[AUDIO ] [%s] Failed to start OpusAudioDecoder.\n", entry.type.c_str()); audioStop(); return false; } if (!snap.doLoop()) { Serial.printf("[AUDIO ] [%s] Failed to copy initial data.\n", entry.type.c_str()); audioStop(); return false; } Serial.printf("[AUDIO ] [%s] Stream running.\n", entry.type.c_str()); return true; } bool audioPlaySD(const Entry &entry) { if (!audioPlayInit(entry)) { return false; } if (!SD.exists(entry.url.c_str())) { Serial.printf("[AUDIO ] [%s] File not found.\n", entry.type.c_str()); audioStop(); return false; } file = SD.open(entry.url.c_str(), FILE_READ); if (!file) { Serial.printf("[AUDIO ] [%s] Failed to open file.\n", entry.type.c_str()); audioStop(); return false; } return audioBeginMP3Stream(entry, file); } bool audioPlay(const Entry &entry) { audioStop(); if (entry.type == "") { return false; } if (entry.type == "ICY") { return audioPlayICY(entry); } if (entry.type == "SD") { return audioPlaySD(entry); } if (entry.type == "SNAP") { return audioPlaySNAP(entry); } Serial.printf("[AUDIO ] Unknown type: %s\n", entry.type.c_str()); return false; } void audioSetup() { AudioToolsLogger.setLogLevel(AudioToolsLogLevel::Error); Serial.println("[AUDIO ] Initializing board..."); board.begin(); audioMute2 = !audioMute; } bool audioLoop() { if (abs(board.volume() - audioVolume) >= 0.01f) { Serial.printf("[AUDIO ] volume = %.2f\n", audioVolume); board.setVolume(audioVolume); stateBufferUpdateRequest(); } if (audioMute2 != audioMute) { audioMute2 = audioMute; Serial.printf("[AUDIO ] mute = %s\n", audioMute ? "MUTED" : "no"); board.setMute(audioMute); stateBufferUpdateRequest(); } if (mp3Copier.copy() > 0) { copyErrors = 0; return true; } if (running) { copyErrors++; if (copyErrors < 100) { return true; } Serial.println("[AUDIO ] Stream ended!"); audioStop(); } return false; }