diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index b060d3e4..31d006fe 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -171,7 +171,8 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { sFileSource.reset( new FatfsAudioInput(sServices->tag_parser(), sServices->bg_worker())); sI2SOutput.reset(new I2SAudioOutput(stream, sServices->gpios())); - sBtOutput.reset(new BluetoothAudioOutput(stream, sServices->bluetooth())); + sBtOutput.reset(new BluetoothAudioOutput(stream, sServices->bluetooth(), + sServices->bg_worker())); auto& nvs = sServices->nvs(); sI2SOutput->SetMaxVolume(nvs.AmpMaxVolume()); diff --git a/src/audio/bt_audio_output.cpp b/src/audio/bt_audio_output.cpp index 0c11481b..41c89069 100644 --- a/src/audio/bt_audio_output.cpp +++ b/src/audio/bt_audio_output.cpp @@ -21,6 +21,7 @@ #include "i2c.hpp" #include "i2s_dac.hpp" #include "result.hpp" +#include "tasks.hpp" #include "wm8523.hpp" [[maybe_unused]] static const char* kTag = "BTOUT"; @@ -28,8 +29,9 @@ namespace audio { BluetoothAudioOutput::BluetoothAudioOutput(StreamBufferHandle_t s, - drivers::Bluetooth& bt) - : IAudioOutput(s), bluetooth_(bt) {} + drivers::Bluetooth& bt, + tasks::WorkerPool& p) + : IAudioOutput(s), bluetooth_(bt), bg_worker_(p), volume_(10) {} BluetoothAudioOutput::~BluetoothAudioOutput() {} @@ -43,14 +45,16 @@ auto BluetoothAudioOutput::SetMode(Modes mode) -> void { auto BluetoothAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void {} -auto BluetoothAudioOutput::SetVolume(uint16_t) -> void {} +auto BluetoothAudioOutput::SetVolume(uint16_t v) -> void { + volume_ = std::clamp(v, 0, 0x7f); +} auto BluetoothAudioOutput::GetVolume() -> uint16_t { - return 0; + return volume_; } auto BluetoothAudioOutput::GetVolumePct() -> uint_fast8_t { - return 0; + return static_cast(static_cast(volume_) * 100 / 0x7f); } auto BluetoothAudioOutput::GetVolumeDb() -> int_fast16_t { @@ -58,11 +62,21 @@ auto BluetoothAudioOutput::GetVolumeDb() -> int_fast16_t { } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { - return false; + if (volume_ == 0x7f) { + return false; + } + volume_++; + bg_worker_.Dispatch([&]() { bluetooth_.SetVolume(volume_); }); + return true; } auto BluetoothAudioOutput::AdjustVolumeDown() -> bool { - return false; + if (volume_ == 0) { + return false; + } + volume_--; + bg_worker_.Dispatch([&]() { bluetooth_.SetVolume(volume_); }); + return true; } auto BluetoothAudioOutput::PrepareFormat(const Format& orig) -> Format { diff --git a/src/audio/include/bt_audio_output.hpp b/src/audio/include/bt_audio_output.hpp index f23ccd6a..f6d2200c 100644 --- a/src/audio/include/bt_audio_output.hpp +++ b/src/audio/include/bt_audio_output.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -16,12 +17,15 @@ #include "bluetooth.hpp" #include "gpios.hpp" #include "i2s_dac.hpp" +#include "tasks.hpp" namespace audio { class BluetoothAudioOutput : public IAudioOutput { public: - BluetoothAudioOutput(StreamBufferHandle_t, drivers::Bluetooth& bt); + BluetoothAudioOutput(StreamBufferHandle_t, + drivers::Bluetooth& bt, + tasks::WorkerPool&); ~BluetoothAudioOutput(); auto SetMode(Modes) -> void override; @@ -46,6 +50,8 @@ class BluetoothAudioOutput : public IAudioOutput { private: drivers::Bluetooth& bluetooth_; + tasks::WorkerPool& bg_worker_; + uint8_t volume_; }; } // namespace audio diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp index 4ea56ab0..b6cd40a9 100644 --- a/src/drivers/bluetooth.cpp +++ b/src/drivers/bluetooth.cpp @@ -17,6 +17,7 @@ #include "esp_bt_defs.h" #include "esp_bt_device.h" #include "esp_bt_main.h" +#include "esp_err.h" #include "esp_gap_bt_api.h" #include "esp_log.h" #include "esp_mac.h" @@ -149,6 +150,11 @@ auto Bluetooth::SetSource(StreamBufferHandle_t src) -> void { bluetooth::events::SourceChanged{}); } +auto Bluetooth::SetVolume(uint8_t vol) -> void { + tinyfsm::FsmList::dispatch( + bluetooth::events::ChangeVolume{.volume = vol}); +} + auto Bluetooth::SetEventHandler(std::function cb) -> void { bluetooth::BluetoothState::event_handler(cb); @@ -401,6 +407,8 @@ void Disabled::entry() { sScanner_->StopScanningNow(); + esp_a2d_source_deinit(); + esp_avrc_ct_deinit(); esp_bluedroid_disable(); esp_bluedroid_deinit(); esp_bt_controller_disable(); @@ -603,6 +611,7 @@ void Connecting::react(const events::internal::A2dp& ev) { void Connected::entry() { ESP_LOGI(kTag, "entering connected state"); + transaction_num_ = 0; connected_to_ = sConnectingDevice_->mac; sPreferredDevice_ = sConnectingDevice_; sConnectingDevice_ = {}; @@ -639,6 +648,18 @@ void Connected::react(const events::SourceChanged& ev) { } } +void Connected::react(const events::ChangeVolume& ev) { + ESP_LOGI(kTag, "send vol %u", ev.volume); + 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 291d049d..00ddb0c0 100644 --- a/src/drivers/include/bluetooth.hpp +++ b/src/drivers/include/bluetooth.hpp @@ -11,6 +11,7 @@ #include #include +#include #include "bluetooth_types.hpp" #include "esp_a2dp_api.h" #include "esp_avrc_api.h" @@ -48,6 +49,8 @@ class Bluetooth { auto PreferredDevice() -> std::optional; auto SetSource(StreamBufferHandle_t) -> void; + auto SetVolume(uint8_t) -> void; + auto SetEventHandler(std::function cb) -> void; }; @@ -63,6 +66,9 @@ struct DiscoveryChanged : 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 { @@ -129,6 +135,7 @@ class BluetoothState : public tinyfsm::Fsm { virtual void react(const events::PreferredDeviceChanged& ev){}; virtual void react(const events::SourceChanged& ev){}; virtual void react(const events::DiscoveryChanged&); + virtual void react(const events::ChangeVolume&) {} virtual void react(const events::DeviceDiscovered&); @@ -198,6 +205,7 @@ 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; @@ -207,6 +215,7 @@ class Connected : public BluetoothState { using BluetoothState::react; private: + uint8_t transaction_num_; mac_addr_t connected_to_; };