diff --git a/src/audio/bt_audio_output.cpp b/src/audio/bt_audio_output.cpp index 7d6bade2..1b8866c1 100644 --- a/src/audio/bt_audio_output.cpp +++ b/src/audio/bt_audio_output.cpp @@ -7,9 +7,9 @@ #include "bt_audio_output.hpp" #include +#include #include #include -#include #include #include @@ -32,7 +32,7 @@ namespace audio { BluetoothAudioOutput::BluetoothAudioOutput(StreamBufferHandle_t s, drivers::Bluetooth& bt, tasks::WorkerPool& p) - : IAudioOutput(s), bluetooth_(bt), bg_worker_(p), volume_(10) {} + : IAudioOutput(s), bluetooth_(bt), bg_worker_(p), volume_() {} BluetoothAudioOutput::~BluetoothAudioOutput() {} @@ -44,10 +44,16 @@ auto BluetoothAudioOutput::changeMode(Modes mode) -> void { } } -auto BluetoothAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void {} +auto BluetoothAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void { + // FIXME: Support two separate scaling factors in the bluetooth driver. +} auto BluetoothAudioOutput::SetVolume(uint16_t v) -> void { - volume_ = std::clamp(v, 0, 0x7f); + volume_ = std::clamp(v, 0, 100); + bg_worker_.Dispatch([&]() { + float factor = volume_ / 100.; + bluetooth_.SetVolumeFactor(factor); + }); } auto BluetoothAudioOutput::GetVolume() -> uint16_t { @@ -55,20 +61,19 @@ auto BluetoothAudioOutput::GetVolume() -> uint16_t { } auto BluetoothAudioOutput::GetVolumePct() -> uint_fast8_t { - return static_cast(round(static_cast(volume_) * 100.0 / 0x7f)); + return static_cast(round(static_cast(volume_))); } auto BluetoothAudioOutput::SetVolumePct(uint_fast8_t val) -> bool { if (val > 100) { return false; } - uint16_t vol = (val * (0x7f))/100; - SetVolume(vol); + SetVolume(val); return true; } auto BluetoothAudioOutput::GetVolumeDb() -> int_fast16_t { - double pct = GetVolumePct()/100.0; + double pct = GetVolumePct() / 100.0; if (pct <= 0) { pct = 0.01; } @@ -82,11 +87,11 @@ auto BluetoothAudioOutput::SetVolumeDb(int_fast16_t val) -> bool { } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { - if (volume_ == 0x7f) { + if (volume_ == 100) { return false; } volume_++; - bg_worker_.Dispatch([&]() { bluetooth_.SetVolume(volume_); }); + SetVolume(volume_); return true; } @@ -95,7 +100,7 @@ auto BluetoothAudioOutput::AdjustVolumeDown() -> bool { return false; } volume_--; - bg_worker_.Dispatch([&]() { bluetooth_.SetVolume(volume_); }); + SetVolume(volume_); return true; } diff --git a/src/audio/include/bt_audio_output.hpp b/src/audio/include/bt_audio_output.hpp index 74b0301a..cc3b2462 100644 --- a/src/audio/include/bt_audio_output.hpp +++ b/src/audio/include/bt_audio_output.hpp @@ -54,7 +54,8 @@ class BluetoothAudioOutput : public IAudioOutput { private: drivers::Bluetooth& bluetooth_; tasks::WorkerPool& bg_worker_; - uint8_t volume_; + + uint16_t volume_; }; } // namespace audio diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp index d15ffd7f..edd5f67e 100644 --- a/src/drivers/bluetooth.cpp +++ b/src/drivers/bluetooth.cpp @@ -25,6 +25,7 @@ #include "freertos/portmacro.h" #include "freertos/projdefs.h" #include "freertos/timers.h" +#include "sample.hpp" #include "tinyfsm/include/tinyfsm.hpp" #include "bluetooth_types.hpp" @@ -37,6 +38,8 @@ namespace drivers { [[maybe_unused]] static constexpr char kTag[] = "bluetooth"; DRAM_ATTR static StreamBufferHandle_t sStream = nullptr; +DRAM_ATTR static std::atomic sVolumeFactor = 1.f; + static tasks::WorkerPool* sBgWorker; auto gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t* param) -> void { @@ -69,7 +72,16 @@ IRAM_ATTR auto a2dp_data_cb(uint8_t* buf, int32_t buf_size) -> int32_t { if (stream == nullptr) { return 0; } - return xStreamBufferReceive(stream, buf, buf_size, 0); + size_t bytes_received = xStreamBufferReceive(stream, buf, buf_size, 0); + + // Apply software volume scaling. + int16_t* samples = reinterpret_cast(buf); + float factor = sVolumeFactor.load(); + for (size_t i = 0; i < bytes_received / 2; i++) { + samples[i] *= factor; + } + + return bytes_received; } Bluetooth::Bluetooth(NvsStorage& storage, tasks::WorkerPool& bg_worker) { @@ -150,10 +162,8 @@ auto Bluetooth::SetSource(StreamBufferHandle_t src) -> void { bluetooth::events::SourceChanged{}); } -auto Bluetooth::SetVolume(uint8_t vol) -> void { - auto lock = bluetooth::BluetoothState::lock(); - tinyfsm::FsmList::dispatch( - bluetooth::events::ChangeVolume{.volume = vol}); +auto Bluetooth::SetVolumeFactor(float f) -> void { + sVolumeFactor = f; } auto Bluetooth::SetEventHandler(std::function cb) @@ -654,17 +664,6 @@ void Connected::react(const events::SourceChanged& ev) { } } -void Connected::react(const events::ChangeVolume& ev) { - esp_err_t err = esp_avrc_ct_send_set_absolute_volume_cmd( - transaction_num_++, std::clamp(ev.volume, 0, 0x7f)); - if (err != ESP_OK) { - ESP_LOGW(kTag, "send vol failed %u", err); - } - if (transaction_num_ > ESP_AVRC_TRANS_LABEL_MAX) { - transaction_num_ = 0; - } -} - void Connected::react(const events::internal::Gap& ev) { sScanner_->HandleGapEvent(ev); switch (ev.type) { diff --git a/src/drivers/include/bluetooth.hpp b/src/drivers/include/bluetooth.hpp index 988c7e93..8da5ce2e 100644 --- a/src/drivers/include/bluetooth.hpp +++ b/src/drivers/include/bluetooth.hpp @@ -43,7 +43,7 @@ class Bluetooth { auto PreferredDevice() -> std::optional; auto SetSource(StreamBufferHandle_t) -> void; - auto SetVolume(uint8_t) -> void; + auto SetVolumeFactor(float) -> void; auto SetEventHandler(std::function cb) -> void; }; @@ -60,9 +60,6 @@ struct SourceChanged : public tinyfsm::Event {}; struct DeviceDiscovered : public tinyfsm::Event { const Device& device; }; -struct ChangeVolume : public tinyfsm::Event { - const uint8_t volume; -}; namespace internal { struct Gap : public tinyfsm::Event { @@ -131,7 +128,6 @@ class BluetoothState : public tinyfsm::Fsm { virtual void react(const events::ConnectTimedOut& ev){}; virtual void react(const events::PreferredDeviceChanged& ev){}; virtual void react(const events::SourceChanged& ev){}; - virtual void react(const events::ChangeVolume&) {} virtual void react(const events::DeviceDiscovered&); @@ -204,7 +200,6 @@ class Connected : public BluetoothState { void react(const events::PreferredDeviceChanged& ev) override; void react(const events::SourceChanged& ev) override; - void react(const events::ChangeVolume&) override; void react(const events::Disable& ev) override; void react(const events::internal::Gap& ev) override;