summaryrefslogtreecommitdiff
path: root/src/drivers/include
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2022-11-15 13:25:58 +1100
committerjacqueline <me@jacqueline.id.au>2022-11-15 13:25:58 +1100
commit530fd15e66a2c89c0dcd6edd1b2a318958c349a4 (patch)
tree2b4b75a644587440a6a5cf6620f1b6e36f81c2d6 /src/drivers/include
parent37041b810fbd10aab0834a33ae1dbd9edbb8bcb9 (diff)
downloadtangara-fw-530fd15e66a2c89c0dcd6edd1b2a318958c349a4.tar.gz
WIP audio play and pause
Diffstat (limited to 'src/drivers/include')
-rw-r--r--src/drivers/include/a2dp_audio_output.hpp15
-rw-r--r--src/drivers/include/audio_output.hpp27
-rw-r--r--src/drivers/include/audio_playback.hpp99
-rw-r--r--src/drivers/include/i2s_audio_output.hpp30
-rw-r--r--src/drivers/include/playback.hpp67
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