/* * Copyright 2023 jacqueline * * SPDX-License-Identifier: GPL-3.0-only */ #include "audio/bt_audio_output.hpp" #include #include #include #include #include #include #include "esp_err.h" #include "esp_heap_caps.h" #include "freertos/portmacro.h" #include "freertos/projdefs.h" #include "gpios.hpp" #include "i2c.hpp" #include "i2s_dac.hpp" #include "result.hpp" #include "tasks.hpp" #include "wm8523.hpp" [[maybe_unused]] static const char* kTag = "BTOUT"; namespace audio { static constexpr uint16_t kVolumeRange = 60; BluetoothAudioOutput::BluetoothAudioOutput(StreamBufferHandle_t s, drivers::Bluetooth& bt, tasks::WorkerPool& p) : IAudioOutput(s), bluetooth_(bt), bg_worker_(p), volume_() {} BluetoothAudioOutput::~BluetoothAudioOutput() {} auto BluetoothAudioOutput::changeMode(Modes mode) -> void { if (mode == Modes::kOnPlaying) { bluetooth_.SetSource(stream()); } else { bluetooth_.SetSource(nullptr); } } 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, 100); bg_worker_.Dispatch([&]() { float factor = pow(10, static_cast(kVolumeRange) * (volume_ - 100) / 100 / 20); bluetooth_.SetVolumeFactor(factor); }); } auto BluetoothAudioOutput::GetVolume() -> uint16_t { return volume_; } auto BluetoothAudioOutput::GetVolumePct() -> uint_fast8_t { return static_cast(round(static_cast(volume_))); } auto BluetoothAudioOutput::SetVolumePct(uint_fast8_t val) -> bool { if (val > 100) { return false; } SetVolume(val); return true; } auto BluetoothAudioOutput::GetVolumeDb() -> int_fast16_t { double pct = GetVolumePct() / 100.0; if (pct <= 0) { pct = 0.01; } int_fast16_t db = log(pct) * 20; return db; } auto BluetoothAudioOutput::SetVolumeDb(int_fast16_t val) -> bool { double pct = exp(val / 20.0) * 100; return SetVolumePct(pct); } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { if (volume_ == 100 || !bluetooth_.IsConnected()) { return false; } volume_++; SetVolume(volume_); return true; } auto BluetoothAudioOutput::AdjustVolumeDown() -> bool { if (volume_ == 0 || !bluetooth_.IsConnected()) { return false; } volume_--; SetVolume(volume_); return true; } auto BluetoothAudioOutput::PrepareFormat(const Format& orig) -> Format { // ESP-IDF's current Bluetooth implementation currently handles SBC encoding, // but requires a fixed input format. return Format{ .sample_rate = 48000, .num_channels = 2, .bits_per_sample = 16, }; } auto BluetoothAudioOutput::Configure(const Format& fmt) -> void { // No configuration necessary; the output format is fixed. } } // namespace audio