summaryrefslogtreecommitdiff
path: root/src/audio/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/include')
-rw-r--r--src/audio/include/audio_fsm.hpp1
-rw-r--r--src/audio/include/audio_sink.hpp13
-rw-r--r--src/audio/include/audio_source.hpp24
-rw-r--r--src/audio/include/audio_task.hpp27
-rw-r--r--src/audio/include/fatfs_audio_input.hpp79
-rw-r--r--src/audio/include/i2s_audio_output.hpp6
-rw-r--r--src/audio/include/sink_mixer.hpp38
7 files changed, 58 insertions, 130 deletions
diff --git a/src/audio/include/audio_fsm.hpp b/src/audio/include/audio_fsm.hpp
index cc3dae0e..d10f31e1 100644
--- a/src/audio/include/audio_fsm.hpp
+++ b/src/audio/include/audio_fsm.hpp
@@ -95,6 +95,7 @@ class Playback : public AudioState {
void entry() override;
void exit() override;
+ void react(const PlayFile&) override;
void react(const QueueUpdate&) override;
void react(const PlaybackUpdate&) override;
diff --git a/src/audio/include/audio_sink.hpp b/src/audio/include/audio_sink.hpp
index 28acdc31..2fb4bf63 100644
--- a/src/audio/include/audio_sink.hpp
+++ b/src/audio/include/audio_sink.hpp
@@ -7,6 +7,7 @@
#pragma once
#include <stdint.h>
+#include <cstdint>
#include "audio_element.hpp"
#include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h"
@@ -37,8 +38,16 @@ class IAudioSink {
virtual auto AdjustVolumeUp() -> bool = 0;
virtual auto AdjustVolumeDown() -> bool = 0;
- virtual auto PrepareFormat(const StreamInfo::Pcm&) -> StreamInfo::Pcm = 0;
- virtual auto Configure(const StreamInfo::Pcm& format) -> void = 0;
+ struct Format {
+ uint32_t sample_rate;
+ uint_fast8_t num_channels;
+ uint_fast8_t bits_per_sample;
+
+ bool operator==(const Format&) const = default;
+ };
+
+ virtual auto PrepareFormat(const Format&) -> Format = 0;
+ virtual auto Configure(const Format& format) -> void = 0;
auto stream() -> StreamBufferHandle_t { return stream_; }
};
diff --git a/src/audio/include/audio_source.hpp b/src/audio/include/audio_source.hpp
index 055a92cd..6c54a882 100644
--- a/src/audio/include/audio_source.hpp
+++ b/src/audio/include/audio_source.hpp
@@ -15,7 +15,10 @@
#include "freertos/portmacro.h"
#include "freertos/semphr.h"
+#include "codec.hpp"
#include "stream_info.hpp"
+#include "track.hpp"
+#include "types.hpp"
namespace audio {
@@ -23,25 +26,8 @@ class IAudioSource {
public:
virtual ~IAudioSource() {}
- class Flags {
- public:
- Flags(bool is_start, bool is_end) {
- flags_[0] = is_start;
- flags_[1] = is_end;
- }
-
- auto is_start() -> bool { return flags_[0]; }
- auto is_end() -> bool { return flags_[1]; }
-
- private:
- std::bitset<2> flags_;
- };
-
- /*
- * Synchronously fetches data from this source.
- */
- virtual auto Read(std::function<void(Flags, InputStream&)>, TickType_t)
- -> void = 0;
+ virtual auto HasNewStream() -> bool = 0;
+ virtual auto NextStream() -> std::shared_ptr<codecs::IStream> = 0;
};
} // namespace audio
diff --git a/src/audio/include/audio_task.hpp b/src/audio/include/audio_task.hpp
index b27aa039..48f5502c 100644
--- a/src/audio/include/audio_task.hpp
+++ b/src/audio/include/audio_task.hpp
@@ -16,6 +16,8 @@
#include "pipeline.hpp"
#include "sink_mixer.hpp"
#include "stream_info.hpp"
+#include "track.hpp"
+#include "types.hpp"
namespace audio {
@@ -52,32 +54,27 @@ class AudioTask {
auto Main() -> void;
+ AudioTask(const AudioTask&) = delete;
+ AudioTask& operator=(const AudioTask&) = delete;
+
private:
AudioTask(IAudioSource* source, IAudioSink* sink);
- auto HandleNewStream(const InputStream&) -> bool;
-
- auto BeginDecoding(InputStream&) -> bool;
- auto ContinueDecoding(InputStream&) -> bool;
- auto FinishDecoding(InputStream&) -> void;
-
- auto ForwardPcmStream(StreamInfo::Pcm&, cpp::span<const std::byte>) -> bool;
-
- auto ConfigureSink(const StreamInfo::Pcm&, const Duration&) -> bool;
- auto SendToSink(InputStream&) -> void;
+ auto BeginDecoding(std::shared_ptr<codecs::IStream>) -> bool;
+ auto ContinueDecoding() -> bool;
IAudioSource* source_;
IAudioSink* sink_;
+
+ std::shared_ptr<codecs::IStream> stream_;
std::unique_ptr<codecs::ICodec> codec_;
std::unique_ptr<SinkMixer> mixer_;
std::unique_ptr<Timer> timer_;
- bool has_begun_decoding_;
- std::optional<StreamInfo::Format> current_input_format_;
- std::optional<StreamInfo::Pcm> current_output_format_;
- std::optional<StreamInfo::Pcm> current_sink_format_;
+ std::optional<codecs::ICodec::OutputFormat> current_format_;
+ std::optional<IAudioSink::Format> current_sink_format_;
- std::unique_ptr<RawStream> codec_buffer_;
+ cpp::span<sample::Sample> codec_buffer_;
};
} // namespace audio
diff --git a/src/audio/include/fatfs_audio_input.hpp b/src/audio/include/fatfs_audio_input.hpp
index e13e49e2..df40696a 100644
--- a/src/audio/include/fatfs_audio_input.hpp
+++ b/src/audio/include/fatfs_audio_input.hpp
@@ -12,6 +12,7 @@
#include <memory>
#include <string>
+#include "codec.hpp"
#include "ff.h"
#include "audio_source.hpp"
@@ -24,54 +25,6 @@
namespace audio {
/*
- * Handles coordination with a persistent background task to asynchronously
- * read files from disk into a StreamBuffer.
- */
-class FileStreamer {
- public:
- FileStreamer(StreamBufferHandle_t dest, SemaphoreHandle_t first_read);
- ~FileStreamer();
-
- /*
- * Continues reading data into the destination buffer until the destination
- * is full.
- */
- auto Fetch() -> void;
-
- /* Returns true if the streamer has run out of data from the current file. */
- auto HasFinished() -> bool;
-
- /*
- * Clears any remaining buffered data, and begins reading again from the
- * given file. This function respects any seeking/reading that has already
- * been done on the new source file.
- */
- auto Restart(std::unique_ptr<FIL>) -> void;
-
- FileStreamer(const FileStreamer&) = delete;
- FileStreamer& operator=(const FileStreamer&) = delete;
-
- private:
- // Note: private methods here should only be called from the streamer's task.
-
- auto Main() -> void;
- auto CloseFile() -> void;
-
- enum Command {
- kRestart,
- kRefillBuffer,
- kQuit,
- };
- QueueHandle_t control_;
- StreamBufferHandle_t destination_;
- SemaphoreHandle_t data_was_read_;
-
- std::atomic<bool> has_data_;
- std::unique_ptr<FIL> file_;
- std::unique_ptr<FIL> next_file_;
-};
-
-/*
* Audio source that fetches data from a FatFs (or exfat i guess) filesystem.
*
* All public methods are safe to call from any task.
@@ -89,43 +42,27 @@ class FatfsAudioInput : public IAudioSource {
auto SetPath(const std::string&) -> void;
auto SetPath() -> void;
- auto Read(std::function<void(Flags, InputStream&)>, TickType_t)
- -> void override;
+ auto HasNewStream() -> bool override;
+ auto NextStream() -> std::shared_ptr<codecs::IStream> override;
FatfsAudioInput(const FatfsAudioInput&) = delete;
FatfsAudioInput& operator=(const FatfsAudioInput&) = delete;
private:
- // Note: private methods assume that the appropriate locks have already been
- // acquired.
-
- auto OpenFile(const std::string& path) -> void;
- auto CloseCurrentFile() -> void;
- auto HasDataRemaining() -> bool;
+ auto OpenFile(const std::string& path) -> bool;
- auto ContainerToStreamType(database::Encoding)
+ auto ContainerToStreamType(database::Container)
-> std::optional<codecs::StreamType>;
- auto IsCurrentFormatMp3() -> bool;
std::shared_ptr<database::ITagParser> tag_parser_;
- // Semaphore used to block when this source is out of data. This should be
- // acquired before attempting to read data, and returned after each incomplete
- // read.
- SemaphoreHandle_t has_data_;
-
- StreamBufferHandle_t streamer_buffer_;
- std::unique_ptr<FileStreamer> streamer_;
-
- std::unique_ptr<RawStream> input_buffer_;
+ std::mutex new_stream_mutex_;
+ std::shared_ptr<codecs::IStream> new_stream_;
- // Mutex guarding the current file/stream associated with this source. Must be
- // held during readings, and before altering the current file.
- std::mutex source_mutex_;
+ SemaphoreHandle_t has_new_stream_;
std::unique_ptr<database::FutureFetcher<std::optional<std::string>>>
pending_path_;
- bool is_first_read_;
};
} // namespace audio
diff --git a/src/audio/include/i2s_audio_output.hpp b/src/audio/include/i2s_audio_output.hpp
index e0f791c5..717e6519 100644
--- a/src/audio/include/i2s_audio_output.hpp
+++ b/src/audio/include/i2s_audio_output.hpp
@@ -35,8 +35,8 @@ class I2SAudioOutput : public IAudioSink {
auto AdjustVolumeUp() -> bool override;
auto AdjustVolumeDown() -> bool override;
- auto PrepareFormat(const StreamInfo::Pcm&) -> StreamInfo::Pcm override;
- auto Configure(const StreamInfo::Pcm& format) -> void override;
+ auto PrepareFormat(const Format&) -> Format override;
+ auto Configure(const Format& format) -> void override;
I2SAudioOutput(const I2SAudioOutput&) = delete;
I2SAudioOutput& operator=(const I2SAudioOutput&) = delete;
@@ -45,7 +45,7 @@ class I2SAudioOutput : public IAudioSink {
drivers::IGpios* expander_;
std::shared_ptr<drivers::I2SDac> dac_;
- std::optional<StreamInfo::Pcm> current_config_;
+ std::optional<Format> current_config_;
int_fast8_t left_difference_;
uint16_t current_volume_;
uint16_t max_volume_;
diff --git a/src/audio/include/sink_mixer.hpp b/src/audio/include/sink_mixer.hpp
index d1e9aa8a..b4d25781 100644
--- a/src/audio/include/sink_mixer.hpp
+++ b/src/audio/include/sink_mixer.hpp
@@ -28,44 +28,42 @@ namespace audio {
*/
class SinkMixer {
public:
- SinkMixer(StreamBufferHandle_t dest);
+ SinkMixer(IAudioSink* sink);
~SinkMixer();
- auto MixAndSend(InputStream&, const StreamInfo::Pcm&) -> std::size_t;
+ auto MixAndSend(cpp::span<sample::Sample>,
+ const IAudioSink::Format& format,
+ bool is_eos) -> void;
private:
auto Main() -> void;
auto SetTargetFormat(const StreamInfo::Pcm& format) -> void;
- auto HandleBytes() -> void;
+ auto HandleSamples(cpp::span<sample::Sample>, bool) -> size_t;
- auto Resample(InputStream&, OutputStream&) -> bool;
auto ApplyDither(cpp::span<sample::Sample> samples, uint_fast8_t bits)
-> void;
- auto Downscale(cpp::span<sample::Sample>, cpp::span<int16_t>) -> void;
-
- enum class Command {
- kReadBytes,
- kSetSourceFormat,
- kSetTargetFormat,
- };
struct Args {
- Command cmd;
- StreamInfo::Pcm format;
+ IAudioSink::Format format;
+ size_t samples_available;
+ bool is_end_of_stream;
};
-
QueueHandle_t commands_;
- SemaphoreHandle_t is_idle_;
std::unique_ptr<Resampler> resampler_;
- std::unique_ptr<RawStream> input_stream_;
- std::unique_ptr<RawStream> resampled_stream_;
-
- StreamInfo::Pcm target_format_;
StreamBufferHandle_t source_;
- StreamBufferHandle_t sink_;
+ cpp::span<sample::Sample> input_buffer_;
+ cpp::span<std::byte> input_buffer_as_bytes_;
+
+ cpp::span<sample::Sample> resampled_buffer_;
+
+ IAudioSink* sink_;
+ IAudioSink::Format source_format_;
+ IAudioSink::Format target_format_;
+ size_t leftover_bytes_;
+ size_t leftover_offset_;
};
} // namespace audio