arduino-audio-tools
Loading...
Searching...
No Matches
USBAudioStreamBase.h
Go to the documentation of this file.
1#pragma once
2
3// See USBAudioDeviceBase.h: some cores #define abs(x), which breaks <chrono>
4// (pulled in by <mutex>/<functional> on some toolchains).
5#pragma push_macro("abs")
6#undef abs
7
8#include <cstddef>
9#include <cstdint>
10#include <functional>
11#include <vector>
12
13#pragma pop_macro("abs")
14
15#include "AudioLogger.h"
21
22namespace audio_tools {
23
40 public:
42 inline bool isEpInEnabled() const { return config_.enable_ep_in; }
43
45 inline bool isEpOutEnabled() const { return config_.enable_ep_out; }
46
48 const USBAudioConfig& config() const { return config_; }
49
50 // ── Volume / Mute API ───────────────────────────────────────────────────
51
53 float volume() override { return volume(0); }
54
56 bool setVolume(float volume) override { return setVolume(volume, 0); }
57
61 float volume(uint8_t channel) {
62 return (channel < volume_.size()) ? volume_[channel] : 0.0f;
63 }
64
69 bool setVolume(float vol, uint8_t channel) {
70 LOGW("setVolume %f channel: %d", vol, channel);
71 if (channel >= volume_.size()) return false;
72 volume_[channel] = vol;
73 if (volume_cb_) volume_cb_(vol, channel);
74 onVolumeChanged(channel);
75 return true;
76 }
77
80 bool isMute(uint8_t channel = 0) const {
81 return (channel < mute_.size()) ? mute_[channel] : false;
82 }
83
88 bool setMute(bool m, uint8_t channel = 0) {
89 LOGW("setMute %s channel: %d", m ? "true" : "false", channel);
90 if (channel >= mute_.size()) return false;
91 mute_[channel] = m;
92 if (mute_cb_) mute_cb_(m, channel);
93 onMuteChanged(channel);
94 return true;
95 }
96
99 void setVolumeCallback(std::function<void(float, uint8_t)> cb) {
100 volume_cb_ = std::move(cb);
101 }
102
105 void setMuteCallback(std::function<void(bool, uint8_t)> cb) {
106 mute_cb_ = std::move(cb);
107 }
108
111 void setSampleRateCallback(std::function<void(uint32_t)> cb) {
112 sample_rate_cb_ = std::move(cb);
113 }
114
118 void setStreamingStateCallback(std::function<void(bool, bool)> cb) {
119 streaming_state_cb_ = std::move(cb);
120 }
121
123 bool isStreamingActive() const {
125 }
126
128 virtual bool isStreamingActiveTx() const = 0;
129
131 virtual bool isStreamingActiveRx() const = 0;
132
135 virtual bool mounted() = 0;
136
140 size_t write(const uint8_t* data, size_t len) {
141 if (!is_started_) return 0;
142 serviceUSB();
143
144 // disregard data if the TX stream has not been opened (alt=0)
145 if (!isStreamingActiveTx()) return len;
146
147 // update the volume
148 if (config_.volume_active) processVolume((uint8_t*)data, len);
149
150 // Write all data, retrying if the buffer is full. On single-core
151 // platforms (RP2040), serviceUSB() drains the buffer by running
152 // the USB stack task → xfer_cb. On dual-core (ESP32), the USB task
153 // drains independently and the RTOS buffer blocks internally.
154 size_t written = 0;
155 while (written < len) {
156 int n = bufferTx().writeArray(data + written, len - written);
157 written += n;
158 if (written < len) {
159 serviceUSB(); // drain buffer to make space
160 if (!isStreamingActiveTx()) break; // stream stopped
161 }
162 }
163 return written;
164 }
165
171 size_t readBytes(uint8_t* buffer, size_t bufsize) {
172 if (!is_started_) return 0;
173 serviceUSB();
174
175 if (!rx_primed_) {
176 uint8_t start_fill = config_.rx_start_fill_percent > 100
177 ? 100
179 if (start_fill > 0 && bufferRx().levelPercent() < start_fill) return 0;
180 rx_primed_ = true;
181 }
182
183 // get the data from the buffer
184 size_t ret = bufferRx().readArray(buffer, bufsize);
185 // upate the volume
186 if (config_.volume_active) processVolume(buffer, ret);
187
188 return ret;
189 }
190
192 int available() override {
193 if (!is_started_) return 0;
194 return bufferRx().available();
195 }
196
198 int availableForWrite() override {
199 if (!is_started_) return 0;
200 return bufferTx().availableForWrite();
201 }
202
205 operator bool() override { return is_started_ && mounted(); }
206
209
212
215 virtual void serviceUSB() = 0;
216
218 virtual int getActualCore() const { return -1; }
219
220 protected:
221 bool is_started_ = false;
222 // true while a dedicated FreeRTOS task is running the USB stack task
223 bool usb_task_active_ = false;
224 int core = -1;
225 bool rx_primed_ = false;
226 bool is_active_ = false;
227
228 // ── Volume / mute state (sized to channels+1 in begin()) ─────────────────
229 std::vector<float> volume_;
230 std::vector<bool> mute_;
231 std::function<void(float, uint8_t)> volume_cb_;
232 std::function<void(bool, uint8_t)> mute_cb_;
233 std::function<void(uint32_t)> sample_rate_cb_;
234 std::function<void(bool, bool)> streaming_state_cb_;
236
239 virtual void onVolumeChanged(uint8_t /*channel*/) {}
240
243 virtual void onMuteChanged(uint8_t /*channel*/) {}
244
246 virtual bool beginUSB() = 0;
247
249 virtual void resizeBuffers() = 0;
250
252 void setConfig(const USBAudioConfig& cfg) { config_ = cfg; }
253
254 bool configChanged(const USBAudioConfig& n) { return config_ != n; }
255
258 const size_t vol_sz = (size_t)config_.channels + 1;
259 volume_.assign(vol_sz, 1.0f);
260 mute_.assign(vol_sz, false);
261 }
262
264 void processVolume(uint8_t* data, size_t len) {
265 switch (config_.bits_per_sample) {
266 case 8:
267 processVolume<int8_t>((int8_t*)data, len);
268 break;
269 case 16:
270 processVolume<int16_t>((int16_t*)data, len / 2);
271 break;
272 case 24:
273 processVolume<int24_3bytes_t>((int24_3bytes_t*)data, len / 3);
274 break;
275 case 32:
276 processVolume<int32_t>((int32_t*)data, len / 4);
277 break;
278 default:
279 // Unsupported bit depth; do nothing.
280 break;
281 }
282 }
283
286 float getVolumeExt(uint8_t channel) const {
287 if (volume_.empty()) return 1.0f;
288 if (mute_[0]) return 0.0f; // master mute
289 float master = volume_[0];
290 if (channel >= volume_.size()) return master; // no per-channel entry
291 if (mute_[channel]) return 0.0f; // per-channel mute
292 return master * volume_[channel];
293 }
294
295 template <typename T>
296 void processVolume(T* data, size_t sample_count) {
297 uint8_t ch_count = config_.channels;
298 for (size_t i = 0; i < sample_count; i++) {
299 uint8_t ch = (uint8_t)(i % ch_count) + 1; // 1-based per-channel index
300 float vol = getVolumeExt(ch);
301 data[i] = (T)(data[i] * vol);
302 }
303 }
304
307 static constexpr int16_t kVolumeMinDb256 = -25600; // -100 dB in 1/256 dB
308
311 static int16_t floatToUac2(float vol) {
312 if (vol <= 0.0f) return (int16_t)0x8000;
313 if (vol >= 1.0f) return 0;
314 return (int16_t)((1.0f - vol) * kVolumeMinDb256);
315 }
316
319 static float uac2ToFloat(int16_t v) {
320 if (v == (int16_t)0x8000) return 0.0f;
321 if (v >= 0) return 1.0f;
322 if (v <= kVolumeMinDb256) return 0.0f;
323 return 1.0f - (float)v / (float)kVolumeMinDb256;
324 }
325
326 static bool isValidBitsPerSample(uint8_t bps) {
327 return bps == 16 || bps == 24 || bps == 32;
328 }
329
334};
335
336} // namespace audio_tools
#define LOGW(...)
Definition AudioLoggerIDF.h:29
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
Shared functionality of all buffers.
Definition Buffers.h:23
virtual int readArray(T data[], int len)
reads multiple values
Definition Buffers.h:34
virtual int writeArray(const T data[], int len)
Fills the buffer data.
Definition Buffers.h:56
virtual int availableForWrite()=0
provides the number of entries that are available to write
virtual int available()=0
provides the number of entries that are available to read
Role-independent front end shared by USB Audio devices (USBAudioDeviceBase, aliased as USBAudioStream...
Definition USBAudioStreamBase.h:39
std::function< void(float, uint8_t)> volume_cb_
Definition USBAudioStreamBase.h:231
bool setVolume(float vol, uint8_t channel)
Set the volume for a channel and notify the USB peer.
Definition USBAudioStreamBase.h:69
static constexpr int16_t kVolumeMinDb256
Convert AudioTools volume (0.0–1.0) to UAC2 int16 (1/256 dB). 0.0 maps to 0x8000 (silence),...
Definition USBAudioStreamBase.h:307
std::vector< float > volume_
Definition USBAudioStreamBase.h:229
bool isEpInEnabled() const
Returns true if the IN endpoint is enabled.
Definition USBAudioStreamBase.h:42
void setVolumeCallback(std::function< void(float, uint8_t)> cb)
Register a callback invoked when the volume changes.
Definition USBAudioStreamBase.h:99
int core
Definition USBAudioStreamBase.h:224
bool isMute(uint8_t channel=0) const
Returns the current mute state for the given channel.
Definition USBAudioStreamBase.h:80
static int16_t floatToUac2(float vol)
Convert linear volume (0.0–1.0) to UAC2 int16 (1/256 dB). Linear mapping: 0.0 → -100 dB (min),...
Definition USBAudioStreamBase.h:311
float volume(uint8_t channel)
Returns the current volume for the given channel.
Definition USBAudioStreamBase.h:61
virtual bool isStreamingActiveTx() const =0
Returns true if the stream used by write() is open.
virtual BaseBuffer< uint8_t > & bufferTx()=0
Returns the TX audio buffer. Must be overridden by subclasses.
USBAudioConfig config_
Definition USBAudioStreamBase.h:235
void setConfig(const USBAudioConfig &cfg)
Set the USB audio configuration (use begin(cfg) instead).
Definition USBAudioStreamBase.h:252
bool is_started_
Definition USBAudioStreamBase.h:221
bool usb_task_active_
Definition USBAudioStreamBase.h:223
virtual bool mounted()=0
Returns true if the USB connection is established (device: enumerated by the host; host: an audio dev...
bool rx_primed_
Definition USBAudioStreamBase.h:225
bool setVolume(float volume) override
sets the volume for the master channel (channel 0)
Definition USBAudioStreamBase.h:56
int available() override
Bytes of received audio waiting in the RX buffer.
Definition USBAudioStreamBase.h:192
bool is_active_
Definition USBAudioStreamBase.h:226
std::function< void(bool, bool)> streaming_state_cb_
Definition USBAudioStreamBase.h:234
void setupVolumeState()
(Re)sizes the volume and mute state: master (index 0) + one per channel
Definition USBAudioStreamBase.h:257
float volume() override
gets the volume for the master channel (channel 0)
Definition USBAudioStreamBase.h:53
static bool isValidBitsPerSample(uint8_t bps)
Definition USBAudioStreamBase.h:326
void setMuteCallback(std::function< void(bool, uint8_t)> cb)
Register a callback invoked when the mute state changes.
Definition USBAudioStreamBase.h:105
virtual BaseBuffer< uint8_t > & bufferRx()=0
Returns the RX audio buffer. Must be overridden by subclasses.
std::function< void(uint32_t)> sample_rate_cb_
Definition USBAudioStreamBase.h:233
int availableForWrite() override
Bytes of free space in the TX buffer.
Definition USBAudioStreamBase.h:198
void processVolume(uint8_t *data, size_t len)
Process audio data for volume control.
Definition USBAudioStreamBase.h:264
virtual bool isStreamingActiveRx() const =0
Returns true if the stream used by readBytes() is open.
virtual bool beginUSB()=0
Override in platform subclasses to start the USB stack.
std::function< void(bool, uint8_t)> mute_cb_
Definition USBAudioStreamBase.h:232
static float uac2ToFloat(int16_t v)
Convert UAC2 int16 (1/256 dB) to linear volume (0.0–1.0). Linear mapping within the -100....
Definition USBAudioStreamBase.h:319
const USBAudioConfig & config() const
Provides the active configuration.
Definition USBAudioStreamBase.h:48
virtual void resizeBuffers()=0
Resize the platform audio buffers.
virtual void onMuteChanged(uint8_t)
Definition USBAudioStreamBase.h:243
void setSampleRateCallback(std::function< void(uint32_t)> cb)
Register a callback invoked when the sample rate changes.
Definition USBAudioStreamBase.h:111
virtual int getActualCore() const
Returns the actual core on which the call is running (for RP2040)
Definition USBAudioStreamBase.h:218
virtual void onVolumeChanged(uint8_t)
Definition USBAudioStreamBase.h:239
float getVolumeExt(uint8_t channel) const
Returns the effective volume for a per-channel index (1-based). Combines master volume (index 0) with...
Definition USBAudioStreamBase.h:286
std::vector< bool > mute_
Definition USBAudioStreamBase.h:230
bool isStreamingActive() const
Returns true if either the TX or RX stream is open.
Definition USBAudioStreamBase.h:123
void setStreamingStateCallback(std::function< void(bool, bool)> cb)
Register a callback invoked when the streaming state changes (a streaming interface was opened or clo...
Definition USBAudioStreamBase.h:118
void notifyStreamingState()
Definition USBAudioStreamBase.h:330
bool isEpOutEnabled() const
Returns true if the OUT endpoint is enabled.
Definition USBAudioStreamBase.h:45
bool configChanged(const USBAudioConfig &n)
Definition USBAudioStreamBase.h:254
size_t readBytes(uint8_t *buffer, size_t bufsize)
Receive audio data from the USB peer. Until bufferRx() has filled past config.rx_start_fill_percent a...
Definition USBAudioStreamBase.h:171
virtual void serviceUSB()=0
Process pending USB events on platforms where the application drives the stack. No-op where a dedicat...
void processVolume(T *data, size_t sample_count)
Definition USBAudioStreamBase.h:296
bool setMute(bool m, uint8_t channel=0)
Set the mute state for a channel and notify the USB peer.
Definition USBAudioStreamBase.h:88
size_t write(const uint8_t *data, size_t len)
Send audio data to the USB peer. Silently discards data while the TX stream is not open so StreamCopy...
Definition USBAudioStreamBase.h:140
Supports the setting and getting of the volume.
Definition AudioTypes.h:193
24bit integer which is used for I2S sound processing. The values are really using 3 bytes....
Definition int24_3bytes_t.h:21
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62
Configuration for USB Audio (inherits sample_rate / channels / bits_per_sample from AudioInfo).
Definition USBAudioConfig.h:117
uint8_t rx_start_fill_percent
Definition USBAudioConfig.h:155
bool enable_ep_in
device → host (capture / microphone)
Definition USBAudioConfig.h:120
bool volume_active
Definition USBAudioConfig.h:230
bool enable_ep_out
host → device (playback / speaker)
Definition USBAudioConfig.h:121