summaryrefslogtreecommitdiff
path: root/src/drivers/include
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/include')
-rw-r--r--src/drivers/include/drivers/bluetooth.hpp10
-rw-r--r--src/drivers/include/drivers/i2s_dac.hpp11
-rw-r--r--src/drivers/include/drivers/pcm_buffer.hpp72
3 files changed, 82 insertions, 11 deletions
diff --git a/src/drivers/include/drivers/bluetooth.hpp b/src/drivers/include/drivers/bluetooth.hpp
index ad61fcc1..030907d9 100644
--- a/src/drivers/include/drivers/bluetooth.hpp
+++ b/src/drivers/include/drivers/bluetooth.hpp
@@ -14,6 +14,7 @@
#include <stdint.h>
#include "drivers/bluetooth_types.hpp"
#include "drivers/nvs.hpp"
+#include "drivers/pcm_buffer.hpp"
#include "esp_a2dp_api.h"
#include "esp_avrc_api.h"
#include "esp_gap_bt_api.h"
@@ -42,9 +43,8 @@ class Bluetooth {
auto SetPreferredDevice(std::optional<bluetooth::MacAndName> dev) -> void;
auto PreferredDevice() -> std::optional<bluetooth::MacAndName>;
- auto SetSource(StreamBufferHandle_t) -> void;
+ auto SetSource(PcmBuffer*) -> void;
auto SetVolumeFactor(float) -> void;
- auto SamplesUsed() -> uint32_t;
auto SetEventHandler(std::function<void(bluetooth::Event)> cb) -> void;
};
@@ -114,8 +114,8 @@ class BluetoothState : public tinyfsm::Fsm<BluetoothState> {
static auto discovery() -> bool;
static auto discovery(bool) -> void;
- static auto source() -> StreamBufferHandle_t;
- static auto source(StreamBufferHandle_t) -> void;
+ static auto source() -> PcmBuffer*;
+ static auto source(PcmBuffer*) -> void;
static auto event_handler(std::function<void(Event)>) -> void;
@@ -147,7 +147,7 @@ class BluetoothState : public tinyfsm::Fsm<BluetoothState> {
static std::optional<bluetooth::MacAndName> sConnectingDevice_;
static int sConnectAttemptsRemaining_;
- static std::atomic<StreamBufferHandle_t> sSource_;
+ static std::atomic<PcmBuffer*> sSource_;
static std::function<void(Event)> sEventHandler_;
auto connect(const bluetooth::MacAndName&) -> bool;
diff --git a/src/drivers/include/drivers/i2s_dac.hpp b/src/drivers/include/drivers/i2s_dac.hpp
index 0776dbab..138a0c03 100644
--- a/src/drivers/include/drivers/i2s_dac.hpp
+++ b/src/drivers/include/drivers/i2s_dac.hpp
@@ -16,6 +16,7 @@
#include "driver/i2s_std.h"
#include "driver/i2s_types.h"
+#include "drivers/pcm_buffer.hpp"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
@@ -39,9 +40,9 @@ constexpr size_t kI2SBufferLengthFrames = 1024;
*/
class I2SDac {
public:
- static auto create(IGpios& expander) -> std::optional<I2SDac*>;
+ static auto create(IGpios& expander, PcmBuffer&) -> std::optional<I2SDac*>;
- I2SDac(IGpios& gpio, i2s_chan_handle_t i2s_handle);
+ I2SDac(IGpios& gpio, PcmBuffer&, i2s_chan_handle_t i2s_handle);
~I2SDac();
auto Start() -> void;
@@ -69,9 +70,6 @@ class I2SDac {
auto Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate) -> void;
auto WriteData(const std::span<const std::byte>& data) -> void;
- auto SetSource(StreamBufferHandle_t buffer) -> void;
-
- auto SamplesUsed() -> uint32_t;
// Not copyable or movable.
I2SDac(const I2SDac&) = delete;
@@ -81,9 +79,10 @@ class I2SDac {
auto set_channel(bool) -> void;
IGpios& gpio_;
+ PcmBuffer& buffer_;
i2s_chan_handle_t i2s_handle_;
+
bool i2s_active_;
- StreamBufferHandle_t buffer_;
std::mutex configure_mutex_;
i2s_std_clk_config_t clock_config_;
diff --git a/src/drivers/include/drivers/pcm_buffer.hpp b/src/drivers/include/drivers/pcm_buffer.hpp
new file mode 100644
index 00000000..6630f720
--- /dev/null
+++ b/src/drivers/include/drivers/pcm_buffer.hpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2024 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <atomic>
+#include <cstddef>
+#include <span>
+
+#include "freertos/FreeRTOS.h"
+
+#include "freertos/ringbuf.h"
+#include "portmacro.h"
+
+namespace drivers {
+
+/*
+ * A circular buffer of signed, 16-bit PCM samples. PcmBuffers are the main
+ * data structure used for shuffling large amounts of read-to-play samples
+ * throughout the system.
+ */
+class PcmBuffer {
+ public:
+ PcmBuffer(size_t size_in_samples);
+ ~PcmBuffer();
+
+ /* Adds samples to the buffer. */
+ auto send(std::span<const int16_t>) -> void;
+
+ /*
+ * Fills the given span with samples. If enough samples are available in
+ * the buffer, then the span will be filled with samples from the buffer. Any
+ * shortfall is made up by padding the given span with zeroes.
+ */
+ auto receive(std::span<int16_t>, bool isr) -> BaseType_t;
+
+ auto clear() -> void;
+ auto isEmpty() -> bool;
+
+ /*
+ * How many samples have been added to this buffer since it was created. This
+ * method overflows by wrapping around to zero.
+ */
+ auto totalSent() -> uint32_t;
+
+ /*
+ * How many samples have been removed from this buffer since it was created.
+ * This method overflows by wrapping around to zero.
+ */
+ auto totalReceived() -> uint32_t;
+
+ // Not copyable or movable.
+ PcmBuffer(const PcmBuffer&) = delete;
+ PcmBuffer& operator=(const PcmBuffer&) = delete;
+
+ private:
+ auto readSingle(std::span<int16_t>, bool isr)
+ -> std::pair<size_t, BaseType_t>;
+
+ StaticRingbuffer_t meta_;
+ uint8_t* buf_;
+
+ std::atomic<uint32_t> sent_;
+ std::atomic<uint32_t> received_;
+ RingbufHandle_t ringbuf_;
+};
+
+} // namespace drivers