arduino-audio-tools
Loading...
Searching...
No Matches
USBAudio2DescriptorBuilder.h
Go to the documentation of this file.
1#pragma once
2#include <cstdint>
3#include <cstring>
4
5#include "USBAudioConfig.h"
6
7namespace audio_tools {
8
30 public:
31 // UAC2 entity IDs — assigned sequentially from 1.
32 // Chain 1 is used for the OUT path (or the only path in pure-IN mode).
33 // Chain 2 is used for the IN path in RXTX mode.
34 static constexpr uint8_t ENTITY_CLOCK = 1;
35 static constexpr uint8_t ENTITY_IT1 = 2;
36 static constexpr uint8_t ENTITY_FU1 = 3;
37 static constexpr uint8_t ENTITY_OT1 = 4;
38 static constexpr uint8_t ENTITY_IT2 = 5;
39 static constexpr uint8_t ENTITY_FU2 = 6;
40 static constexpr uint8_t ENTITY_OT2 = 7;
41
43
44
45 // Kept for backward compatibility with existing call sites.
46 const uint16_t buildDescriptor(uint8_t /*itf*/, uint8_t /*alt*/, uint8_t* desc) {
47 return buildFullDescriptor(desc);
48 }
49
50 // Build the complete audio-function descriptor using interface numbers from
51 // config. Returns a pointer to an internal static buffer; *outLen receives
52 // the total byte count.
53 const uint16_t buildFullDescriptor(uint8_t* desc) {
55 }
56
57 // Same but with an explicit first (AC) interface number.
58 const uint16_t buildFullDescriptor(uint8_t first_itf, uint8_t* desc) {
59 uint8_t* p = desc;
60
61 const uint8_t itf_ac = first_itf;
62 uint8_t itf_as = (uint8_t)(first_itf + 1);
63 const uint8_t num_as = (uint8_t)audioFunctionsCount();
64
65 // ── IAD ──────────────────────────────────────────────────────────────────
66 p = writeIAD(p, itf_ac, (uint8_t)(1 + num_as));
67
68 // ── Standard AC Interface ─────────────────────────────────────────────
69 const uint8_t ac_nEps = p_config->enable_interrupt_ep ? 1 : 0;
70 p = writeStdIface(p, itf_ac, 0, ac_nEps, 0x01 /*AUDIO*/, 0x01 /*CONTROL*/, 0x20 /*UAC2*/);
71
72 // ── CS AC entities — patch wTotalLength after ────────────────────────────
73 uint8_t* cs_ac_start = p;
74 p = writeCsAcHeader(p);
76
78 // OUT path: USB Streaming input → Feature Unit → Speaker output
80 0x0101 /*USB Streaming*/, ENTITY_CLOCK);
83 0x0301 /*Speaker*/, ENTITY_FU1,
85 }
86
88 // IN path: Microphone input → Feature Unit → USB Streaming output.
89 // Pure-IN mode reuses chain 1 IDs; RXTX mode uses chain 2 IDs.
90 const bool rxtx = p_config->enable_ep_out;
91 const uint8_t it = rxtx ? ENTITY_IT2 : ENTITY_IT1;
92 const uint8_t fu = rxtx ? ENTITY_FU2 : ENTITY_FU1;
93 const uint8_t ot = rxtx ? ENTITY_OT2 : ENTITY_OT1;
94 p = writeInputTerminal(p, it, 0x0201 /*Microphone*/, ENTITY_CLOCK);
95 p = writeFeatureUnit(p, fu, it);
96 p = writeOutputTerminal(p, ot, 0x0101 /*USB Streaming*/, fu,
98 }
99
100 // Patch wTotalLength (bytes 6-7 of CS AC Header) — covers only the
101 // class-specific descriptors above, not the interrupt endpoint below.
102 const uint16_t cs_ac_len = (uint16_t)(p - cs_ac_start);
103 cs_ac_start[6] = (uint8_t)(cs_ac_len & 0xFF);
104 cs_ac_start[7] = (uint8_t)(cs_ac_len >> 8);
105
106 // Interrupt EP must follow the CS AC block (USB spec §9.6.6:
107 // endpoint descriptors come after class-specific interface descriptors).
110 }
111
112 // ── OUT AS Interface ─────────────────────────────────────────────────────
113 if (p_config->enable_ep_out) {
114 const uint8_t nEps = enableFeedbackEp() ? 2 : 1;
115 p = writeStdIface(p, itf_as, 0, 0, 0x01, 0x02, 0x20); // alt=0 zero BW
116 p = writeStdIface(p, itf_as, 1, nEps, 0x01, 0x02, 0x20); // alt=1 active
117 p = writeCsAsInterface(p, ENTITY_IT1); // links to USB Streaming IT
118 p = writeFormatType(p);
120 p = writeCsIsoEndpoint(p);
121 if (enableFeedbackEp()) {
123 }
124 ++itf_as;
125 }
126
127 // ── IN AS Interface ──────────────────────────────────────────────────────
128 if (p_config->enable_ep_in) {
129 // Links to the Output Terminal that has USB Streaming type
130 const uint8_t ot = p_config->enable_ep_out ? ENTITY_OT2
131 : ENTITY_OT1;
132 p = writeStdIface(p, itf_as, 0, 0, 0x01, 0x02, 0x20); // alt=0 zero BW
133 p = writeStdIface(p, itf_as, 1, 1, 0x01, 0x02, 0x20); // alt=1 active
134 p = writeCsAsInterface(p, ot);
135 p = writeFormatType(p);
137 p = writeCsIsoEndpoint(p);
138 }
139
140 uint16_t outLen = (uint16_t)(p - desc);
141 return outLen;
142 }
143
145 return (p_config->enable_ep_in ? 1 : 0) + (p_config->enable_ep_out ? 1 : 0);
146 }
147
148
149 // True when the explicit-feedback endpoint should appear in the descriptor.
150 // Mirrors isFeedbackEpEnabled() in USBAudioDeviceBase: feedback is only valid
151 // for a pure OUT (speaker) path — with an IN endpoint present the host uses
152 // the IN stream as implicit feedback, and TX-only mode has no OUT EP at all.
153 bool enableFeedbackEp() const {
157 }
158
159 // Isochronous packet size for one 1 ms frame at a given rate.
160 // +1 extra sample provides headroom for clock-drift compensation: the host
161 // may send ceil(rate/1000)+1 samples in occasional frames to stay in sync.
162 uint16_t calcPacketSizeForRate(uint32_t rate) const {
163 const uint16_t bytes_per_sample = (p_config->bits_per_sample / 8) * p_config->channels;
164 return bytes_per_sample * (uint16_t)(((rate + 999) / 1000) + 1);
165 }
166
167 // Isochronous packet size for one 1 ms frame at the configured rate/format.
168 // +1 extra sample is required for Windows: at rates that are exact multiples
169 // of 1000 Hz (e.g. 48000 Hz = exactly 48 samples/frame), Windows' USB audio
170 // driver may deliver 49 samples in some frames for synchronisation, causing
171 // a descriptor rejection when wMaxPacketSize is set to the nominal 48-sample
172 // value. Rates like 44100 Hz already have implicit headroom from ceiling
173 // division (44.1 → 45), but the +1 makes this safe for all rates.
174 uint16_t calcMaxPacketSize() const {
175 const uint16_t bytes_per_sample = (p_config->bits_per_sample / 8) * p_config->channels;
176 return bytes_per_sample * (uint16_t)(((p_config->sample_rate + 999) / 1000) + 1);
177 }
178
179 protected:
181
182 // ── helpers ─────────────────────────────────────────────────────────────────
183
184 uint32_t channelConfig() const {
185 // Stereo: FL+FR = bits 0-1; mono: FL = bit 0; >2ch: lower N bits.
186 if (p_config->channels == 1) return 0x00000001u;
187 if (p_config->channels == 2) return 0x00000003u;
188 return (1u << p_config->channels) - 1u;
189 }
190
191 // ── descriptor writers ──────────────────────────────────────────────────────
192
193 // Interface Association Descriptor (8 bytes)
194 uint8_t* writeIAD(uint8_t* p, uint8_t first_itf, uint8_t count) {
195 *p++ = 8;
196 *p++ = 0x0B; // INTERFACE_ASSOCIATION
197 *p++ = first_itf;
198 *p++ = count;
199 *p++ = 0x01; // bFunctionClass AUDIO
200 *p++ = 0x00; // bFunctionSubClass
201 *p++ = 0x20; // bFunctionProtocol UAC2
202 *p++ = 0x00; // iFunction
203 return p;
204 }
205
206 // Standard Interface Descriptor (9 bytes)
207 uint8_t* writeStdIface(uint8_t* p, uint8_t itf, uint8_t alt,
208 uint8_t nEps, uint8_t cls, uint8_t sub, uint8_t proto) {
209 *p++ = 9;
210 *p++ = 0x04; // INTERFACE
211 *p++ = itf;
212 *p++ = alt;
213 *p++ = nEps;
214 *p++ = cls;
215 *p++ = sub;
216 *p++ = proto;
217 *p++ = 0; // iInterface
218 return p;
219 }
220
221 // UAC2 CS AC Interface Header (9 bytes).
222 // Caller patches wTotalLength at offsets [6] and [7].
223 uint8_t* writeCsAcHeader(uint8_t* p) {
224 *p++ = 9;
225 *p++ = 0x24; // CS_INTERFACE
226 *p++ = 0x01; // HEADER
227 *p++ = 0x00;
228 *p++ = 0x02; // bcdADC 2.00
229 *p++ = deviceCategory();
230 *p++ = 0x00; // wTotalLength LSB — patched by caller
231 *p++ = 0x00; // wTotalLength MSB — patched by caller
232 *p++ = 0x00; // bmControls
233 return p;
234 }
235
236 // UAC2 bCategory: Windows uses this to classify the audio endpoint.
237 // Using the wrong category (e.g. IO_BOX for a capture-only device) causes
238 // Windows to look for a playback path that does not exist and fail to
239 // enumerate the audio format (Details tab missing in microphone properties).
240 uint8_t deviceCategory() const {
241 bool has_in = p_config->enable_ep_in;
242 bool has_out = p_config->enable_ep_out;
243 if (has_in && !has_out) return 0x03; // Microphone
244 if (!has_in && has_out) return 0x01; // Desktop Speaker
245 return 0x08; // I/O Box (bidirectional)
246 }
247
248 // UAC2 Clock Source Descriptor (8 bytes)
249 //
250 // bmAttributes D1..D0 — clock type:
251 // 0x00 = external, 0x01 = internal fixed, 0x02 = internal variable,
252 // 0x03 = internal programmable
253 // bmControls — bit-pair encoding:
254 // D1..D0 = Clock Frequency (01=read-only, 11=host-programmable)
255 // D3..D2 = Clock Validity (01=read-only)
256 //
257 // Always declare "internal programmable" (0x03) with "host-programmable
258 // frequency" (0x07), even when only one rate is supported. Windows 11's
259 // usbaudio2.sys requires the ability to round-trip a SET_CUR / GET_CUR for
260 // the clock frequency before it will populate the audio format in the device
261 // properties (Details tab) and accept the device in WASAPI. With a "fixed"
262 // clock (0x01 / 0x05) Windows skips the SET_CUR step at integer rates
263 // (48000, 16000 Hz) and then fails to enumerate the format — the Details tab
264 // does not appear and Audacity returns error -9999. At fractional rates
265 // (44100 Hz) it works by accident because the ceiling arithmetic in
266 // calcMaxPacketSize already signals the irregular-frame nature of the stream.
267 // The single-rate vs multi-rate distinction is carried by GET_RANGE only.
268 uint8_t* writeClockSource(uint8_t* p, uint8_t clock_id) {
269 *p++ = 8;
270 *p++ = 0x24; // CS_INTERFACE
271 *p++ = 0x0A; // CLOCK_SOURCE
272 *p++ = clock_id;
273 *p++ = 0x03; // bmAttributes: internal programmable clock
274 *p++ = 0x07; // bmControls: freq host-programmable (11b), validity read-only (01b)
275 *p++ = 0x00; // bAssocTerminal
276 *p++ = 0x00; // iClockSource
277 return p;
278 }
279
280 // UAC2 Input Terminal Descriptor (17 bytes)
281 uint8_t* writeInputTerminal(uint8_t* p, uint8_t term_id,
282 uint16_t term_type, uint8_t clock_id) {
283 const uint32_t ch_cfg = channelConfig();
284 *p++ = 17;
285 *p++ = 0x24; // CS_INTERFACE
286 *p++ = 0x02; // INPUT_TERMINAL
287 *p++ = term_id;
288 *p++ = (uint8_t)(term_type & 0xFF);
289 *p++ = (uint8_t)(term_type >> 8);
290 *p++ = 0x00; // bAssocTerminal
291 *p++ = clock_id; // bCSourceID
292 *p++ = p_config->channels;
293 *p++ = (uint8_t)(ch_cfg & 0xFF);
294 *p++ = (uint8_t)((ch_cfg >> 8) & 0xFF);
295 *p++ = (uint8_t)((ch_cfg >> 16) & 0xFF);
296 *p++ = (uint8_t)((ch_cfg >> 24) & 0xFF);
297 *p++ = 0; // iChannelNames
298 *p++ = 0x00;
299 *p++ = 0x00; // bmControls
300 *p++ = 0; // iTerminal
301 return p;
302 }
303
304 // UAC2 Feature Unit Descriptor (6 + (channels+1)*4 bytes)
305 //
306 // bmaControls[] is a 32-bit bitmap per channel (+ master at index 0).
307 // Each control is a 2-bit pair:
308 // 00 = not present, 01 = read-only, 11 = host-programmable
309 //
310 // D1..D0 = Mute (FU_CTRL_MUTE = 0x01)
311 // D3..D2 = Volume (FU_CTRL_VOLUME = 0x02)
312 //
313 // 0x0F = Mute host-programmable (11b) | Volume host-programmable (11b)
314 //
315 // Volume uses int16 in 1/256 dB units (0x8000 = silence, 0 = 0 dB).
316 // AudioTools maps this to float 0.0 (silence) – 1.0 (0 dB).
317 // GET_RANGE reports -100 dB .. 0 dB in 1 dB steps.
318 uint8_t* writeFeatureUnit(uint8_t* p, uint8_t unit_id, uint8_t src_id) {
319 const uint8_t len = (uint8_t)(6 + (p_config->channels + 1) * 4);
320 *p++ = len;
321 *p++ = 0x24; // CS_INTERFACE
322 *p++ = 0x06; // FEATURE_UNIT
323 *p++ = unit_id;
324 *p++ = src_id;
325 // Master bmaControls[0]: Mute + Volume, host-programmable
326 *p++ = 0x0F; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
327 // Per-channel bmaControls[1..N]: same controls
328 for (uint8_t i = 0; i < p_config->channels; i++) {
329 *p++ = 0x0F; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
330 }
331 *p++ = 0x00; // iFeature
332 return p;
333 }
334
335 // UAC2 Output Terminal Descriptor (12 bytes)
336 uint8_t* writeOutputTerminal(uint8_t* p, uint8_t term_id, uint16_t term_type,
337 uint8_t src_id, uint8_t clock_id) {
338 *p++ = 12;
339 *p++ = 0x24; // CS_INTERFACE
340 *p++ = 0x03; // OUTPUT_TERMINAL
341 *p++ = term_id;
342 *p++ = (uint8_t)(term_type & 0xFF);
343 *p++ = (uint8_t)(term_type >> 8);
344 *p++ = 0x00; // bAssocTerminal
345 *p++ = src_id; // bSourceID
346 *p++ = clock_id; // bCSourceID
347 *p++ = 0x00;
348 *p++ = 0x00; // bmControls
349 *p++ = 0; // iTerminal
350 return p;
351 }
352
353 // UAC2 CS AS Interface Descriptor (16 bytes)
354 uint8_t* writeCsAsInterface(uint8_t* p, uint8_t terminal_link) {
355 const uint32_t ch_cfg = channelConfig();
356 *p++ = 16;
357 *p++ = 0x24; // CS_INTERFACE
358 *p++ = 0x01; // AS_GENERAL
359 *p++ = terminal_link;
360 *p++ = 0x00; // bmControls
361 *p++ = 0x01; // bFormatType TYPE_I
362 // bmFormats: PCM = 0x00000001
363 *p++ = 0x01; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;
364 *p++ = p_config->channels;
365 *p++ = (uint8_t)(ch_cfg & 0xFF);
366 *p++ = (uint8_t)((ch_cfg >> 8) & 0xFF);
367 *p++ = (uint8_t)((ch_cfg >> 16) & 0xFF);
368 *p++ = (uint8_t)((ch_cfg >> 24) & 0xFF);
369 *p++ = 0; // iChannelNames
370 return p;
371 }
372
373 // UAC2 Type I Format Type Descriptor (6 bytes)
374 uint8_t* writeFormatType(uint8_t* p) {
375 *p++ = 6;
376 *p++ = 0x24; // CS_INTERFACE
377 *p++ = 0x02; // FORMAT_TYPE
378 *p++ = 0x01; // FORMAT_TYPE_I
379 *p++ = (uint8_t)(p_config->bits_per_sample / 8); // bSubslotSize
380 *p++ = p_config->bits_per_sample; // bBitResolution
381 return p;
382 }
383
384 // Standard Isochronous Endpoint Descriptor (7 bytes)
385 //
386 // wMaxPacketSize must be large enough for the highest rate the device
387 // advertises in the Clock Source GET_RANGE response. The actual per-frame
388 // byte count varies with the current sample rate; the host will never
389 // send or expect more than wMaxPacketSize in a single (micro)frame.
390 uint8_t* writeIsoEndpoint(uint8_t* p, uint8_t ep_addr) {
391 // Fixed clock: wMaxPacketSize matches the configured rate.
392 // Multi-rate: covers the highest rate actually advertised via GET_RANGE
393 // (see supported_sample_rates) -- sizing for anything higher would waste
394 // buffer/FIFO space for a rate the host can never select.
395 const uint16_t pkt = p_config->enable_multi_sample_rate
398 // bmAttributes: Isochronous (01) + sync type (bits[3:2]) + usage=data (00)
399 // bits 3:2: 00=None, 01=Async, 10=Adaptive, 11=Sync
400 // IN endpoints: Asynchronous (0x05) — device drives the clock.
401 // OUT endpoints: Asynchronous (0x05) when a feedback EP is present,
402 // Adaptive (0x09) otherwise (device adapts to host rate).
403 bool const is_in = (ep_addr & 0x80u);
404 bool const is_out = !is_in;
405 uint8_t bmAttr;
406 if (is_in) bmAttr = 0x05u; // ISO + Async
407 else if (is_out && enableFeedbackEp()) bmAttr = 0x05u; // ISO + Async
408 else bmAttr = 0x09u; // ISO + Adaptive
409 *p++ = 7;
410 *p++ = 0x05; // ENDPOINT
411 *p++ = ep_addr;
412 *p++ = bmAttr;
413 *p++ = (uint8_t)(pkt & 0xFF);
414 *p++ = (uint8_t)(pkt >> 8);
415 *p++ = 0x01; // bInterval (1 = every frame for FS; host uses 125 µs for HS)
416 return p;
417 }
418
419 // Explicit Feedback Endpoint Descriptor (7 bytes, IN, no CS descriptor)
420 uint8_t* writeFeedbackEndpoint(uint8_t* p, uint8_t ep_addr) {
421 *p++ = 7;
422 *p++ = 0x05; // ENDPOINT
423 *p++ = ep_addr; // must be an IN address (bit 7 set)
424 *p++ = 0x11; // Isochronous, No Sync, Explicit Feedback usage
425 *p++ = 0x04; // wMaxPacketSize LSB (4 bytes)
426 *p++ = 0x00; // wMaxPacketSize MSB
427 *p++ = 0x01; // bInterval
428 return p;
429 }
430
431 // Audio Control Interrupt IN Endpoint Descriptor (7 bytes)
432 //
433 // Carries 6-byte UAC2 status/change notifications (bInfo, bAttribute,
434 // wValue = CS<<8|CN, wIndex = EntityID<<8|Itf) so the device can push
435 // volume, mute, or sample-rate changes to the host.
436 uint8_t* writeInterruptEndpoint(uint8_t* p, uint8_t ep_addr) {
437 *p++ = 7;
438 *p++ = 0x05; // ENDPOINT
439 *p++ = ep_addr; // IN address (bit 7 set)
440 *p++ = 0x03; // bmAttributes: Interrupt
441 *p++ = 0x06; // wMaxPacketSize LSB (6 bytes for UAC2 notification)
442 *p++ = 0x00; // wMaxPacketSize MSB
443 *p++ = 0x10; // bInterval: 2^(16-1) = 32768 frames ≈ poll only when needed
444 return p;
445 }
446
447 // UAC2 CS ISO Endpoint Descriptor (8 bytes)
448 uint8_t* writeCsIsoEndpoint(uint8_t* p) {
449 *p++ = 8;
450 *p++ = 0x25; // CS_ENDPOINT
451 *p++ = 0x01; // EP_GENERAL
452 *p++ = 0x00; // bmAttributes
453 *p++ = 0x00; // bmControls
454 *p++ = 0x00; // bLockDelayUnits (no locking)
455 *p++ = 0x00;
456 *p++ = 0x00; // wLockDelay
457 return p;
458 }
459};
460
461} // namespace audio_tools
USB Audio Class 2.0 descriptor generator.
Definition USBAudio2DescriptorBuilder.h:29
uint8_t * writeInputTerminal(uint8_t *p, uint8_t term_id, uint16_t term_type, uint8_t clock_id)
Definition USBAudio2DescriptorBuilder.h:281
uint8_t * writeFeedbackEndpoint(uint8_t *p, uint8_t ep_addr)
Definition USBAudio2DescriptorBuilder.h:420
uint8_t * writeIsoEndpoint(uint8_t *p, uint8_t ep_addr)
Definition USBAudio2DescriptorBuilder.h:390
uint8_t * writeClockSource(uint8_t *p, uint8_t clock_id)
Definition USBAudio2DescriptorBuilder.h:268
static constexpr uint8_t ENTITY_OT1
first Output Terminal
Definition USBAudio2DescriptorBuilder.h:37
uint8_t * writeCsIsoEndpoint(uint8_t *p)
Definition USBAudio2DescriptorBuilder.h:448
const uint16_t buildFullDescriptor(uint8_t *desc)
Definition USBAudio2DescriptorBuilder.h:53
static constexpr uint8_t ENTITY_FU2
second Feature Unit (RXTX)
Definition USBAudio2DescriptorBuilder.h:39
static constexpr uint8_t ENTITY_FU1
first Feature Unit
Definition USBAudio2DescriptorBuilder.h:36
uint8_t * writeInterruptEndpoint(uint8_t *p, uint8_t ep_addr)
Definition USBAudio2DescriptorBuilder.h:436
uint8_t * writeStdIface(uint8_t *p, uint8_t itf, uint8_t alt, uint8_t nEps, uint8_t cls, uint8_t sub, uint8_t proto)
Definition USBAudio2DescriptorBuilder.h:207
int audioFunctionsCount() const
Definition USBAudio2DescriptorBuilder.h:144
static constexpr uint8_t ENTITY_CLOCK
Definition USBAudio2DescriptorBuilder.h:34
uint8_t * writeOutputTerminal(uint8_t *p, uint8_t term_id, uint16_t term_type, uint8_t src_id, uint8_t clock_id)
Definition USBAudio2DescriptorBuilder.h:336
const uint16_t buildFullDescriptor(uint8_t first_itf, uint8_t *desc)
Definition USBAudio2DescriptorBuilder.h:58
uint8_t deviceCategory() const
Definition USBAudio2DescriptorBuilder.h:240
static constexpr uint8_t ENTITY_IT2
second Input Terminal (RXTX)
Definition USBAudio2DescriptorBuilder.h:38
uint32_t channelConfig() const
Definition USBAudio2DescriptorBuilder.h:184
uint8_t * writeIAD(uint8_t *p, uint8_t first_itf, uint8_t count)
Definition USBAudio2DescriptorBuilder.h:194
uint8_t * writeCsAcHeader(uint8_t *p)
Definition USBAudio2DescriptorBuilder.h:223
static constexpr uint8_t ENTITY_OT2
second Output Terminal (RXTX)
Definition USBAudio2DescriptorBuilder.h:40
static constexpr uint8_t ENTITY_IT1
first Input Terminal
Definition USBAudio2DescriptorBuilder.h:35
uint16_t calcPacketSizeForRate(uint32_t rate) const
Definition USBAudio2DescriptorBuilder.h:162
const uint16_t buildDescriptor(uint8_t, uint8_t, uint8_t *desc)
Definition USBAudio2DescriptorBuilder.h:46
USBAudioConfig * p_config
Definition USBAudio2DescriptorBuilder.h:180
uint8_t * writeFormatType(uint8_t *p)
Definition USBAudio2DescriptorBuilder.h:374
uint16_t calcMaxPacketSize() const
Definition USBAudio2DescriptorBuilder.h:174
bool enableFeedbackEp() const
Definition USBAudio2DescriptorBuilder.h:153
uint8_t * writeFeatureUnit(uint8_t *p, uint8_t unit_id, uint8_t src_id)
Definition USBAudio2DescriptorBuilder.h:318
uint8_t * writeCsAsInterface(uint8_t *p, uint8_t terminal_link)
Definition USBAudio2DescriptorBuilder.h:354
USBAudio2DescriptorBuilder(USBAudioConfig &cfg)
Definition USBAudio2DescriptorBuilder.h:42
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
uint32_t highestSupportedSampleRate(const USBAudioConfig &cfg)
Definition USBAudioConfig.h:278
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:55
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:57
Configuration for USB Audio (inherits sample_rate / channels / bits_per_sample from AudioInfo).
Definition USBAudioConfig.h:117
bool enable_interrupt_ep
Definition USBAudioConfig.h:190
int16_t ep_fb
ISO IN (explicit feedback, RX-only mode)
Definition USBAudioConfig.h:134
int16_t ep_in
ISO IN (device → host, capture/microphone)
Definition USBAudioConfig.h:132
bool enable_multi_sample_rate
Definition USBAudioConfig.h:170
int16_t ep_int
INT IN (AC status/change notifications)
Definition USBAudioConfig.h:135
bool enable_feedback_ep
Enable isochronous feedback endpoint so the host can adjust its clock.
Definition USBAudioConfig.h:161
int16_t ep_out
ISO OUT (host → device, playback/speaker)
Definition USBAudioConfig.h:133
bool enable_ep_in
device → host (capture / microphone)
Definition USBAudioConfig.h:120
uint8_t itf_num_ac
Definition USBAudioConfig.h:140
bool enable_ep_out
host → device (playback / speaker)
Definition USBAudioConfig.h:121