summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-05-08 16:03:03 +1000
committerjacqueline <me@jacqueline.id.au>2024-05-08 16:03:03 +1000
commit265049c5192cf0ce862c7db7b4745636afb6c17b (patch)
tree6729bc947c6c2d2d196c9e7baa994a35aeea76ee /src/drivers
parentb242ba998699208c87dc066158964de0866b61e2 (diff)
downloadtangara-fw-265049c5192cf0ce862c7db7b4745636afb6c17b.tar.gz
Count samples going in and out of the drain buffer
This is a more accurate way of knowing which track is playing when, and also simplifies a lot of fragile logic in audio_fsm
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/bluetooth.cpp16
-rw-r--r--src/drivers/i2s_dac.cpp22
-rw-r--r--src/drivers/include/drivers/bluetooth.hpp3
-rw-r--r--src/drivers/include/drivers/i2s_dac.hpp4
4 files changed, 37 insertions, 8 deletions
diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp
index 4caffae7..fcb764f6 100644
--- a/src/drivers/bluetooth.cpp
+++ b/src/drivers/bluetooth.cpp
@@ -38,6 +38,7 @@ namespace drivers {
DRAM_ATTR static StreamBufferHandle_t sStream = nullptr;
DRAM_ATTR static std::atomic<float> sVolumeFactor = 1.f;
+DRAM_ATTR static std::atomic<uint32_t> sSamplesUsed = 0;
static tasks::WorkerPool* sBgWorker;
@@ -47,8 +48,8 @@ auto gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t* param) -> void {
bluetooth::events::internal::Gap{.type = event, .param = param});
}
-auto avrcp_cb(esp_avrc_ct_cb_event_t event,
- esp_avrc_ct_cb_param_t* param) -> void {
+auto avrcp_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t* param)
+ -> void {
esp_avrc_ct_cb_param_t copy = *param;
sBgWorker->Dispatch<void>([=]() {
auto lock = bluetooth::BluetoothState::lock();
@@ -73,6 +74,13 @@ IRAM_ATTR auto a2dp_data_cb(uint8_t* buf, int32_t buf_size) -> int32_t {
}
size_t bytes_received = xStreamBufferReceive(stream, buf, buf_size, 0);
+ size_t samples_received = bytes_received / 2;
+ if (UINT32_MAX - sSamplesUsed < samples_received) {
+ sSamplesUsed = samples_received - (UINT32_MAX - sSamplesUsed);
+ } else {
+ sSamplesUsed += samples_received;
+ }
+
// Apply software volume scaling.
int16_t* samples = reinterpret_cast<int16_t*>(buf);
float factor = sVolumeFactor.load();
@@ -165,6 +173,10 @@ auto Bluetooth::SetVolumeFactor(float f) -> void {
sVolumeFactor = f;
}
+auto Bluetooth::SamplesUsed() -> uint32_t {
+ return sSamplesUsed;
+}
+
auto Bluetooth::SetEventHandler(std::function<void(bluetooth::Event)> cb)
-> void {
auto lock = bluetooth::BluetoothState::lock();
diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp
index a271fce0..e5efe198 100644
--- a/src/drivers/i2s_dac.cpp
+++ b/src/drivers/i2s_dac.cpp
@@ -5,6 +5,7 @@
*/
#include "drivers/i2s_dac.hpp"
+#include <stdint.h>
#include <cmath>
#include <cstdint>
@@ -140,11 +141,10 @@ auto I2SDac::SetPaused(bool paused) -> void {
}
}
-static volatile bool sSwapWords = false;
+DRAM_ATTR static volatile bool sSwapWords = false;
-auto I2SDac::Reconfigure(Channels ch,
- BitsPerSample bps,
- SampleRate rate) -> void {
+auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate)
+ -> void {
std::lock_guard<std::mutex> lock(configure_mutex_);
if (i2s_active_) {
@@ -217,6 +217,8 @@ auto I2SDac::WriteData(const std::span<const std::byte>& data) -> void {
}
}
+DRAM_ATTR static volatile uint32_t sSamplesRead = 0;
+
extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle,
i2s_event_data_t* event,
void* user_ctx) -> bool {
@@ -235,6 +237,14 @@ extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle,
size_t bytes_written =
xStreamBufferReceiveFromISR(src, buf, event->size, &ret);
+ // Assume 16 bit samples.
+ size_t samples = bytes_written / 2;
+ if (UINT32_MAX - sSamplesRead < samples) {
+ sSamplesRead = samples - (UINT32_MAX - sSamplesRead);
+ } else {
+ sSamplesRead = sSamplesRead + samples;
+ }
+
// The ESP32's I2S peripheral has a different endianness to its processors.
// ESP-IDF handles this difference for stereo channels, but not for mono
// channels. We therefore sometimes need to swap each pair of words as they're
@@ -276,6 +286,10 @@ auto I2SDac::SetSource(StreamBufferHandle_t buffer) -> void {
}
}
+auto I2SDac::SamplesUsed() -> uint32_t {
+ return sSamplesRead;
+}
+
auto I2SDac::set_channel(bool enabled) -> void {
if (i2s_active_ == enabled) {
return;
diff --git a/src/drivers/include/drivers/bluetooth.hpp b/src/drivers/include/drivers/bluetooth.hpp
index 5960de7e..ad61fcc1 100644
--- a/src/drivers/include/drivers/bluetooth.hpp
+++ b/src/drivers/include/drivers/bluetooth.hpp
@@ -13,10 +13,10 @@
#include <freertos/stream_buffer.h>
#include <stdint.h>
#include "drivers/bluetooth_types.hpp"
+#include "drivers/nvs.hpp"
#include "esp_a2dp_api.h"
#include "esp_avrc_api.h"
#include "esp_gap_bt_api.h"
-#include "drivers/nvs.hpp"
#include "tasks.hpp"
#include "tinyfsm.hpp"
#include "tinyfsm/include/tinyfsm.hpp"
@@ -44,6 +44,7 @@ class Bluetooth {
auto SetSource(StreamBufferHandle_t) -> void;
auto SetVolumeFactor(float) -> void;
+ auto SamplesUsed() -> uint32_t;
auto SetEventHandler(std::function<void(bluetooth::Event)> cb) -> void;
};
diff --git a/src/drivers/include/drivers/i2s_dac.hpp b/src/drivers/include/drivers/i2s_dac.hpp
index 5e81f875..0776dbab 100644
--- a/src/drivers/include/drivers/i2s_dac.hpp
+++ b/src/drivers/include/drivers/i2s_dac.hpp
@@ -11,8 +11,8 @@
#include <functional>
#include <memory>
#include <optional>
-#include <utility>
#include <span>
+#include <utility>
#include "driver/i2s_std.h"
#include "driver/i2s_types.h"
@@ -71,6 +71,8 @@ class I2SDac {
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;
I2SDac& operator=(const I2SDac&) = delete;