diff options
| author | jacqueline <me@jacqueline.id.au> | 2022-11-15 13:25:58 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2022-11-15 13:25:58 +1100 |
| commit | 530fd15e66a2c89c0dcd6edd1b2a318958c349a4 (patch) | |
| tree | 2b4b75a644587440a6a5cf6620f1b6e36f81c2d6 /src/drivers/include | |
| parent | 37041b810fbd10aab0834a33ae1dbd9edbb8bcb9 (diff) | |
| download | tangara-fw-530fd15e66a2c89c0dcd6edd1b2a318958c349a4.tar.gz | |
WIP audio play and pause
Diffstat (limited to 'src/drivers/include')
| -rw-r--r-- | src/drivers/include/a2dp_audio_output.hpp | 15 | ||||
| -rw-r--r-- | src/drivers/include/audio_output.hpp | 27 | ||||
| -rw-r--r-- | src/drivers/include/audio_playback.hpp | 99 | ||||
| -rw-r--r-- | src/drivers/include/i2s_audio_output.hpp | 30 | ||||
| -rw-r--r-- | src/drivers/include/playback.hpp | 67 |
5 files changed, 171 insertions, 67 deletions
diff --git a/src/drivers/include/a2dp_audio_output.hpp b/src/drivers/include/a2dp_audio_output.hpp new file mode 100644 index 00000000..43b55956 --- /dev/null +++ b/src/drivers/include/a2dp_audio_output.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "audio_common.h" +#include "audio_element.h" +#include "audio_output.hpp" +#include <cstdint> + +namespace drivers { + +class A2DPAudioOutput : IAudioOutput { + public: + virtual auto SetVolume(uint8_t volume) -> void; +}; + +} // namespace drivers diff --git a/src/drivers/include/audio_output.hpp b/src/drivers/include/audio_output.hpp new file mode 100644 index 00000000..63cba465 --- /dev/null +++ b/src/drivers/include/audio_output.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "audio_common.h" +#include "audio_element.h" +#include <cstdint> + +namespace drivers { + +class IAudioOutput { + public: + IAudioOutput(audio_element_handle_t element) : element_(element) {} + virtual ~IAudioOutput() { + audio_element_deinit(element_); + } + + auto GetAudioElement() -> audio_element_handle_t { + return element_; + } + + virtual auto SetVolume(uint8_t volume) -> void = 0; + virtual auto Configure(audio_element_info_t info) -> void = 0; + + protected: + audio_element_handle_t element_; +}; + +} // namespace drivers diff --git a/src/drivers/include/audio_playback.hpp b/src/drivers/include/audio_playback.hpp new file mode 100644 index 00000000..dd0f7f7a --- /dev/null +++ b/src/drivers/include/audio_playback.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include "audio_output.hpp" +#include "dac.hpp" +#include "storage.hpp" + +#include <cstdint> +#include <memory> +#include <string> + +#include "audio_common.h" +#include "audio_element.h" +#include "audio_event_iface.h" +#include "audio_pipeline.h" +#include "esp_err.h" +#include "fatfs_stream.h" +#include "i2s_stream.h" +#include "mp3_decoder.h" +#include "result.hpp" + +namespace drivers { + +/* + * Sends an I2S audio stream to the DAC. Includes basic controls for pausing + * and resuming the stream, as well as support for gapless playback of the next + * queued song, but does not implement any kind of sophisticated queing or + * playback control; these should be handled at a higher level. + */ +class AudioPlayback { + public: + enum Error { FATFS_INIT, I2S_INIT, PIPELINE_INIT }; + static auto create(std::unique_ptr<IAudioOutput> output) + -> cpp::result<std::unique_ptr<AudioPlayback>, Error>; + + AudioPlayback(std::unqiue_ptr<IAudioOutput> output, + audio_pipeline_handle_t pipeline, + audio_element_handle_t source_element, + audio_event_iface_handle_t event_interface); + ~AudioPlayback(); + + /* + * Replaces any currently playing file with the one given, and begins + * playback. + * + * Any value set in `set_next_file` is cleared by this method. + */ + void Play(const std::string& filename); + /* Toogle between resumed and paused. */ + void Toggle(); + void Resume(); + void Pause(); + + enum PlaybackState { PLAYING, PAUSED, STOPPED }; + auto GetPlaybackState() -> PlaybackState; + + /* + * Handles any pending events from the underlying audio pipeline. This must + * be called regularly in order to handle configuring the I2S stream for + * different audio types (e.g. sample rate, bit depth), and for gapless + * playback. + */ + void ProcessEvents(uint16_t max_time_ms); + + /* + * Sets the file that should be played immediately after the current file + * finishes. This is used for gapless playback + */ + void set_next_file(const std::string& filename); + + void set_volume(uint8_t volume); + auto volume() -> uint8_t; + + // Not copyable or movable. + AudioPlayback(const AudioPlayback&) = delete; + AudioPlayback& operator=(const AudioPlayback&) = delete; + + private: + PlaybackState current_state_; + + enum Decoder {NONE, MP3, AMR, OPUS, OGG, FLAC, WAV, AAC}; + auto GetDecoderForFilename(std::string filename) -> Decoder; + auto CreateDecoder(Decoder decoder) -> audio_element_handle_t; + void ReconfigurePipeline(); + + std::unique_ptr<IAudioOutput> output_; + std::mutex playback_lock_; + + std::string next_filename_ = ""; + uint8_t volume_; + + audio_pipeline_handle_t pipeline_; + audio_element_handle_t source_element_; + audio_event_iface_handle_t event_interface_; + + audio_element_handle_t decoder_ = nullptr; + Decoder decoder_type_ = NONE; +}; + +} // namespace drivers diff --git a/src/drivers/include/i2s_audio_output.hpp b/src/drivers/include/i2s_audio_output.hpp new file mode 100644 index 00000000..531bddbc --- /dev/null +++ b/src/drivers/include/i2s_audio_output.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "audio_common.h" +#include "audio_element.h" +#include "audio_output.hpp" +#include "gpio-expander.hpp" +#include <cstdint> +#include <memory> +#include "result.hpp" +#include "dac.hpp" + +namespace drivers { + +class I2SAudioOutput : public IAudioOutput { + public: + enum Error { DAC_CONFIG, I2S_CONFIG, STREAM_INIT }; + static auto create(GpioExpander* expander) + -> cpp::result<std::unique_ptr<I2SAudioOutput>, Error>; + + I2SAudioOutput(AudioDac* dac, audio_element_handle_t element); + ~I2SAudioOutput(); + + virtual auto SetVolume(uint8_t volume) -> void; + virtual auto Configure(audio_element_info_t info) -> void; + + private: + std::unique_ptr<AudioDac> dac_; +}; + +} // namespace drivers diff --git a/src/drivers/include/playback.hpp b/src/drivers/include/playback.hpp deleted file mode 100644 index 5fa7ab38..00000000 --- a/src/drivers/include/playback.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "dac.hpp" -#include "storage.hpp" - -#include <cstdint> -#include <memory> -#include <string> - -#include "audio_common.h" -#include "audio_element.h" -#include "audio_event_iface.h" -#include "audio_pipeline.h" -#include "esp_err.h" -#include "fatfs_stream.h" -#include "i2s_stream.h" -#include "mp3_decoder.h" -#include "result.hpp" - -namespace drivers { - -class DacAudioPlayback { - public: - enum Error { PIPELINE_INIT }; - static auto create(AudioDac* dac) - -> cpp::result<std::unique_ptr<DacAudioPlayback>, Error>; - - DacAudioPlayback(AudioDac* dac, - audio_pipeline_handle_t pipeline, - audio_element_handle_t fatfs_stream_reader, - audio_element_handle_t i2s_stream_writer, - audio_event_iface_handle_t event_interface, - audio_element_handle_t mp3_decoder); - ~DacAudioPlayback(); - - void Play(const std::string& filename); - void Resume(); - void Pause(); - - void ProcessEvents(); - - /* for gapless */ - void set_next_file(const std::string& filename); - - void set_volume(uint8_t volume); - auto volume() -> uint8_t; - - // Not copyable or movable. - DacAudioPlayback(const DacAudioPlayback&) = delete; - DacAudioPlayback& operator=(const DacAudioPlayback&) = delete; - - private: - AudioDac* dac_; - std::mutex playback_lock_; - - std::string next_filename_; - uint8_t volume_; - - audio_pipeline_handle_t pipeline_; - audio_element_handle_t fatfs_stream_reader_; - audio_element_handle_t i2s_stream_writer_; - audio_event_iface_handle_t event_interface_; - - audio_element_handle_t mp3_decoder_; -}; - -} // namespace drivers |
