summaryrefslogtreecommitdiff
path: root/src/audio
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-15 13:53:30 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-15 13:53:30 +1000
commitd6b83fcf4a1a3039c06e0b1d1a1f7e2af2351efb (patch)
tree03c6a534931736a2755aacef86e271ecc5b8e87c /src/audio
parent205e3053506191fab69d01e7523e733dccc09d77 (diff)
downloadtangara-fw-d6b83fcf4a1a3039c06e0b1d1a1f7e2af2351efb.tar.gz
Flesh out basic bluetooth support
No ui yet, and performance isn't great. It kinda works though!!
Diffstat (limited to 'src/audio')
-rw-r--r--src/audio/CMakeLists.txt2
-rw-r--r--src/audio/audio_fsm.cpp8
-rw-r--r--src/audio/bt_audio_output.cpp79
-rw-r--r--src/audio/i2s_audio_output.cpp7
-rw-r--r--src/audio/include/audio_fsm.hpp3
-rw-r--r--src/audio/include/audio_sink.hpp8
-rw-r--r--src/audio/include/bt_audio_output.hpp49
7 files changed, 148 insertions, 8 deletions
diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt
index 2d332a1e..a7dda8fd 100644
--- a/src/audio/CMakeLists.txt
+++ b/src/audio/CMakeLists.txt
@@ -6,7 +6,7 @@ idf_component_register(
SRCS "audio_task.cpp" "chunk.cpp" "fatfs_audio_input.cpp"
"stream_message.cpp" "i2s_audio_output.cpp" "stream_buffer.cpp" "track_queue.cpp"
"stream_event.cpp" "stream_info.cpp" "audio_fsm.cpp" "sink_mixer.cpp" "resample.cpp"
- "fatfs_source.cpp"
+ "fatfs_source.cpp" "bt_audio_output.cpp"
INCLUDE_DIRS "include"
REQUIRES "codecs" "drivers" "cbor" "result" "tasks" "span" "memory" "tinyfsm"
"database" "system_fsm" "playlist" "speexdsp")
diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp
index 617272b3..8791b9c4 100644
--- a/src/audio/audio_fsm.cpp
+++ b/src/audio/audio_fsm.cpp
@@ -11,6 +11,8 @@
#include "audio_decoder.hpp"
#include "audio_events.hpp"
#include "audio_task.hpp"
+#include "bluetooth.hpp"
+#include "bt_audio_output.hpp"
#include "esp_log.h"
#include "event_queue.hpp"
#include "fatfs_audio_input.hpp"
@@ -35,6 +37,7 @@ std::weak_ptr<database::Database> AudioState::sDatabase;
std::unique_ptr<AudioTask> AudioState::sTask;
std::unique_ptr<FatfsAudioInput> AudioState::sFileSource;
std::unique_ptr<I2SAudioOutput> AudioState::sI2SOutput;
+std::unique_ptr<BluetoothAudioOutput> AudioState::sBtOutput;
TrackQueue* AudioState::sTrackQueue;
std::optional<database::TrackId> AudioState::sCurrentTrack;
@@ -42,6 +45,7 @@ std::optional<database::TrackId> AudioState::sCurrentTrack;
auto AudioState::Init(drivers::IGpios* gpio_expander,
std::weak_ptr<database::Database> database,
std::shared_ptr<database::ITagParser> tag_parser,
+ drivers::Bluetooth* bluetooth,
TrackQueue* queue) -> bool {
sIGpios = gpio_expander;
sTrackQueue = queue;
@@ -55,8 +59,10 @@ auto AudioState::Init(drivers::IGpios* gpio_expander,
sFileSource.reset(new FatfsAudioInput(tag_parser));
sI2SOutput.reset(new I2SAudioOutput(sIGpios, sDac));
+ // sBtOutput.reset(new BluetoothAudioOutput(bluetooth));
AudioTask::Start(sFileSource.get(), sI2SOutput.get());
+ // AudioTask::Start(sFileSource.get(), sBtOutput.get());
return true;
}
@@ -125,6 +131,7 @@ void Standby::react(const QueueUpdate& ev) {
void Playback::entry() {
ESP_LOGI(kTag, "beginning playback");
sI2SOutput->SetInUse(true);
+ // sBtOutput->SetInUse(true);
}
void Playback::exit() {
@@ -133,6 +140,7 @@ void Playback::exit() {
// to drain.
vTaskDelay(pdMS_TO_TICKS(250));
sI2SOutput->SetInUse(false);
+ // sBtOutput->SetInUse(false);
}
void Playback::react(const QueueUpdate& ev) {
diff --git a/src/audio/bt_audio_output.cpp b/src/audio/bt_audio_output.cpp
new file mode 100644
index 00000000..71e40d02
--- /dev/null
+++ b/src/audio/bt_audio_output.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "bt_audio_output.hpp"
+#include <stdint.h>
+#include <sys/_stdint.h>
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <variant>
+
+#include "esp_err.h"
+#include "esp_heap_caps.h"
+#include "freertos/portmacro.h"
+
+#include "audio_element.hpp"
+#include "freertos/projdefs.h"
+#include "gpios.hpp"
+#include "i2c.hpp"
+#include "i2s_dac.hpp"
+#include "result.hpp"
+#include "stream_info.hpp"
+#include "wm8523.hpp"
+
+static const char* kTag = "BTOUT";
+
+namespace audio {
+
+static constexpr size_t kDrainBufferSize = 48 * 1024;
+
+BluetoothAudioOutput::BluetoothAudioOutput(drivers::Bluetooth* bt)
+ : IAudioSink(kDrainBufferSize, MALLOC_CAP_SPIRAM), bluetooth_(bt) {}
+
+BluetoothAudioOutput::~BluetoothAudioOutput() {}
+
+auto BluetoothAudioOutput::SetInUse(bool in_use) -> void {
+ if (in_use) {
+ bluetooth_->SetSource(stream());
+ } else {
+ bluetooth_->SetSource(nullptr);
+ }
+}
+
+auto BluetoothAudioOutput::SetVolumeImbalance(int_fast8_t balance) -> void {}
+
+auto BluetoothAudioOutput::SetVolume(uint_fast8_t percent) -> void {}
+
+auto BluetoothAudioOutput::GetVolume() -> uint_fast8_t {
+ return 50;
+}
+
+auto BluetoothAudioOutput::AdjustVolumeUp() -> bool {
+ return false;
+}
+
+auto BluetoothAudioOutput::AdjustVolumeDown() -> bool {
+ return false;
+}
+
+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 = 44100,
+ .num_channels = 2,
+ .bits_per_sample = 16,
+ };
+}
+
+auto BluetoothAudioOutput::Configure(const Format& fmt) -> void {
+ // No configuration necessary; the output format is fixed.
+}
+
+} // namespace audio
diff --git a/src/audio/i2s_audio_output.cpp b/src/audio/i2s_audio_output.cpp
index b7fcf104..8b7d130f 100644
--- a/src/audio/i2s_audio_output.cpp
+++ b/src/audio/i2s_audio_output.cpp
@@ -14,7 +14,9 @@
#include <memory>
#include <variant>
+#include "audio_sink.hpp"
#include "esp_err.h"
+#include "esp_heap_caps.h"
#include "freertos/portmacro.h"
#include "audio_element.hpp"
@@ -41,9 +43,12 @@ static constexpr uint16_t kMaxVolumeBeforeClipping = 0x185;
static constexpr uint16_t kLineLevelVolume = 0x13d;
static constexpr uint16_t kDefaultVolume = 0x128;
+static constexpr size_t kDrainBufferSize = 8 * 1024;
+
I2SAudioOutput::I2SAudioOutput(drivers::IGpios* expander,
std::weak_ptr<drivers::I2SDac> dac)
- : expander_(expander),
+ : IAudioSink(kDrainBufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT),
+ expander_(expander),
dac_(dac.lock()),
current_config_(),
left_difference_(0),
diff --git a/src/audio/include/audio_fsm.hpp b/src/audio/include/audio_fsm.hpp
index d10f31e1..5d44fcda 100644
--- a/src/audio/include/audio_fsm.hpp
+++ b/src/audio/include/audio_fsm.hpp
@@ -12,6 +12,7 @@
#include "audio_events.hpp"
#include "audio_task.hpp"
+#include "bt_audio_output.hpp"
#include "database.hpp"
#include "display.hpp"
#include "fatfs_audio_input.hpp"
@@ -33,6 +34,7 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
static auto Init(drivers::IGpios* gpio_expander,
std::weak_ptr<database::Database>,
std::shared_ptr<database::ITagParser>,
+ drivers::Bluetooth* bluetooth,
TrackQueue* queue) -> bool;
virtual ~AudioState() {}
@@ -68,6 +70,7 @@ class AudioState : public tinyfsm::Fsm<AudioState> {
static std::unique_ptr<AudioTask> sTask;
static std::unique_ptr<FatfsAudioInput> sFileSource;
static std::unique_ptr<I2SAudioOutput> sI2SOutput;
+ static std::unique_ptr<BluetoothAudioOutput> sBtOutput;
static TrackQueue* sTrackQueue;
static std::optional<database::TrackId> sCurrentTrack;
diff --git a/src/audio/include/audio_sink.hpp b/src/audio/include/audio_sink.hpp
index 2fb4bf63..b5d6ef57 100644
--- a/src/audio/include/audio_sink.hpp
+++ b/src/audio/include/audio_sink.hpp
@@ -18,15 +18,11 @@ namespace audio {
class IAudioSink {
private:
- static const std::size_t kDrainBufferSize = 24 * 1024;
StreamBufferHandle_t stream_;
public:
- IAudioSink()
- : stream_(xStreamBufferCreateWithCaps(
- kDrainBufferSize,
- 1,
- MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)) {}
+ IAudioSink(size_t buffer_size, uint32_t caps)
+ : stream_(xStreamBufferCreateWithCaps(buffer_size, 1, caps)) {}
virtual ~IAudioSink() { vStreamBufferDeleteWithCaps(stream_); }
diff --git a/src/audio/include/bt_audio_output.hpp b/src/audio/include/bt_audio_output.hpp
new file mode 100644
index 00000000..e11a5d44
--- /dev/null
+++ b/src/audio/include/bt_audio_output.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#pragma once
+
+#include <sys/_stdint.h>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+#include "audio_element.hpp"
+#include "audio_sink.hpp"
+#include "bluetooth.hpp"
+#include "chunk.hpp"
+#include "result.hpp"
+
+#include "gpios.hpp"
+#include "i2s_dac.hpp"
+#include "stream_info.hpp"
+
+namespace audio {
+
+class BluetoothAudioOutput : public IAudioSink {
+ public:
+ BluetoothAudioOutput(drivers::Bluetooth* bt);
+ ~BluetoothAudioOutput();
+
+ auto SetInUse(bool) -> void override;
+
+ auto SetVolumeImbalance(int_fast8_t balance) -> void override;
+ auto SetVolume(uint_fast8_t percent) -> void override;
+ auto GetVolume() -> uint_fast8_t override;
+ auto AdjustVolumeUp() -> bool override;
+ auto AdjustVolumeDown() -> bool override;
+
+ auto PrepareFormat(const Format&) -> Format override;
+ auto Configure(const Format& format) -> void override;
+
+ BluetoothAudioOutput(const BluetoothAudioOutput&) = delete;
+ BluetoothAudioOutput& operator=(const BluetoothAudioOutput&) = delete;
+
+ private:
+ drivers::Bluetooth* bluetooth_;
+};
+
+} // namespace audio