summaryrefslogtreecommitdiff
path: root/src/tangara/audio/bt_audio_output.cpp
blob: c6c64fd1c3d8a805872fb96d3bf4eee2097932a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright 2023 jacqueline <me@jacqueline.id.au>
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#include "audio/bt_audio_output.hpp"

#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <variant>

#include "drivers/bluetooth.hpp"
#include "esp_err.h"
#include "esp_heap_caps.h"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"

#include "drivers/gpios.hpp"
#include "drivers/i2c.hpp"
#include "drivers/i2s_dac.hpp"
#include "drivers/pcm_buffer.hpp"
#include "drivers/wm8523.hpp"
#include "result.hpp"
#include "tasks.hpp"

[[maybe_unused]] static const char* kTag = "BTOUT";

namespace audio {

static constexpr uint16_t kVolumeRange = 60;

using ConnectionState = drivers::Bluetooth::ConnectionState;

BluetoothAudioOutput::BluetoothAudioOutput(drivers::Bluetooth& bt,
                                           drivers::OutputBuffers& bufs,
                                           tasks::WorkerPool& p)
    : IAudioOutput(),
      bluetooth_(bt),
      buffers_(bufs),
      bg_worker_(p),
      volume_() {}

BluetoothAudioOutput::~BluetoothAudioOutput() {}

auto BluetoothAudioOutput::changeMode(Modes mode) -> void {
  if (mode == Modes::kOnPlaying) {
    bluetooth_.sources(&buffers_);
  } else {
    bluetooth_.sources(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<uint16_t>(v, 0, 100);
  bg_worker_.Dispatch<void>([&]() {
    float factor =
        pow(10, static_cast<double>(kVolumeRange) * (volume_ - 100) / 100 / 20);
    bluetooth_.softVolume(factor);
  });
}

auto BluetoothAudioOutput::GetVolume() -> uint16_t {
  return volume_;
}

auto BluetoothAudioOutput::GetVolumePct() -> uint_fast8_t {
  return static_cast<uint_fast8_t>(round(static_cast<int>(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) {
    return false;
  }
  volume_++;
  SetVolume(volume_);
  return true;
}

auto BluetoothAudioOutput::AdjustVolumeDown() -> bool {
  if (volume_ == 0) {
    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