#pragma once #include "PowerFSM.h" #include "concurrency/OSThread.h" #include "configuration.h" #include "main.h" #include "sleep.h" #include #ifdef HAS_I2S #include #include #include #include #ifdef USE_XL9555 #include "ExtensionIOXL9555.hpp" extern ExtensionIOXL9555 io; #endif #define AUDIO_THREAD_INTERVAL_MS 100 class AudioThread : public concurrency::OSThread { public: AudioThread() : OSThread("Audio") { initOutput(); } void beginRttl(const void *data, uint32_t len) { #ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, HIGH); #endif setCPUFast(true); rtttlFile = std::unique_ptr(new AudioFileSourcePROGMEM(data, len)); i2sRtttl = std::unique_ptr(new AudioGeneratorRTTTL()); i2sRtttl->begin(rtttlFile.get(), audioOut.get()); } // Also handles actually playing the RTTTL, needs to be called in loop bool isPlaying() { if (i2sRtttl != nullptr) { return i2sRtttl->isRunning() && i2sRtttl->loop(); } return false; } void stop() { if (i2sRtttl != nullptr) { i2sRtttl->stop(); i2sRtttl = nullptr; } rtttlFile = nullptr; setCPUFast(false); #ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, LOW); #endif } void readAloud(const char *text) { if (i2sRtttl != nullptr) { i2sRtttl->stop(); i2sRtttl = nullptr; } #ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, HIGH); #endif auto sam = std::unique_ptr(new ESP8266SAM); sam->Say(audioOut.get(), text); setCPUFast(false); #ifdef T_LORA_PAGER io.digitalWrite(EXPANDS_AMP_EN, LOW); #endif } protected: int32_t runOnce() override { canSleep = true; // Assume we should not keep the board awake // if (i2sRtttl != nullptr && i2sRtttl->isRunning()) { // i2sRtttl->loop(); // } return AUDIO_THREAD_INTERVAL_MS; } private: void initOutput() { audioOut = std::unique_ptr(new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S)); audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_MCLK); audioOut->SetGain(0.2); }; std::unique_ptr i2sRtttl = nullptr; std::unique_ptr audioOut = nullptr; std::unique_ptr rtttlFile = nullptr; }; #endif