arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Modules Pages
USBDeviceAudio.h
1#pragma once
2
3#include <vector>
4
5#include "Arduino.h"
6#include "USBDeviceAudioAPI.h"
7#include "common/tusb_types.h"
8
9//--------------------------------------------------------------------
10// Debugging Logging and Testing
11//--------------------------------------------------------------------
12#define AUDIO_LOG(...) \
13 { \
14 char msg[160]; \
15 snprintf(msg, 160, __VA_ARGS__); \
16 LOG_AUDIO_OUTPUT.println(msg); \
17 LOG_AUDIO_OUTPUT.flush(); \
18 }
19#define AUDIO_NO_LOG(...)
20
21#define LOG_AUDIO_OUTPUT Serial
22#define AUDIO_DEBUG false
23#define LOG_AUDIO_ERROR AUDIO_LOG
24#define LOG_AUDIO_DEBUG AUDIO_LOG
25
26#ifdef ESP32
27#define ISO_FB_EP 3
28#else
29#define ISO_FB_EP 3
30#endif
31
32//--------------------------------------------------------------------
33// Unit numbers are arbitrary selected
34//--------------------------------------------------------------------
35
36#define UAC2_ENTITY_CLOCK 0x10
37
38// Speaker path
39#define UAC2_ENTITY_SPK_INPUT_TERMINAL 0x15
40#define UAC2_ENTITY_SPK_FEATURE_UNIT 0x16
41#define UAC2_ENTITY_SPK_OUTPUT_TERMINAL 0x17
42
43// Microphone path
44#define UAC2_ENTITY_MIC_INPUT_TERMINAL 0x11
45#define UAC2_ENTITY_MIC_FEATURE_UNIT 0x12
46#define UAC2_ENTITY_MIC_OUTPUT_TERMINAL 0x13
47
48// output using 5 debug pins
49#if AUDIO_DEBUG
50#define debugWrite(pin, active) digitalWrite(pin, active);
51#else
52#define debugWrite(pin, active)
53#endif
54
56enum class AudioProcessingStatus {
57 INACTIVE = 0,
58 ERROR = 500,
59 PLAYING = 1000,
60 ACTIVE = 2000
61};
62
65 public:
66 // resizes the buffer
67 void resize(int size) { vector.resize(size); }
68 // provides access to the first byte of the data
69 uint8_t *data() { return vector.data(); }
70 // remove first n bytes
71 void consume(int n) {
72 pos -= n;
73 if (pos > 0) {
74 memmove(data(), data() + n, pos);
75 }
76 }
77 // provides the available byte count
78 int available() { return pos; }
79 // provides the size of the buffer
80 int size() { return vector.size(); }
81 // sets the available byte count to 0
82 void reset() { int pos = 0; }
83 // clears the memory by setting the content to 0
84 void clear() { memset(data(), 0, size()); }
85 // inform about number of available bytes
86 void setAvailable(int av) { pos = av; }
87
88 protected:
89 std::vector<uint8_t> vector;
90 int pos = 0;
91};
92
93/***
94 * USB Audio Device:
95 * - provide data access via callbacks
96 * - configure audio info via begin method
97 * - provide all potential methods so that we can easily overwrite them
98 * - implement Speaker (device is audio sink)
99 * - implement Microphone (device is audio source)
100 * - dont change the audio based on mute or volume changes: this is the
101 * respondibility of the implementor
102 */
103
105 public:
106 //USBDeviceAudio() { setupDebugPins(); }
107 USBDeviceAudio() = default;
108
111 void setWriteCallback(size_t (*write_cb)(const uint8_t *data, size_t len,
112 USBDeviceAudio &ref)) {
113 cfg.p_write_callback = write_cb;
114 }
115
118 void setReadCallback(size_t (*read_cb)(uint8_t *data, size_t len,
119 USBDeviceAudio &ref)) {
120 cfg.p_read_callback = read_cb;
121 }
122
124 void setOutput(Print &out) {
125 p_print = &out;
126 setWriteCallback(defaultWriteCB);
127 }
128
130 void setInput(Stream &in) {
131 p_stream = &in;
132 setReadCallback(defaultReadCB);
133 }
134
135 USBAudioConfig defaultConfig() {
136 USBAudioConfig result;
137 return result;
138 }
139
140 /*------------- MAIN -------------*/
141 virtual bool begin(USBAudioConfig config) {
142 _itf_number_total = 0;
143 cfg = config;
144
146
147 _api.begin(this, cfg);
148 _mute.resize(cfg.channels + 1);
149 _volume.resize(cfg.channels + 1);
150
151 // check data
152 if (!isMicrophone() && !isSpeaker()) {
153 LOG_AUDIO_ERROR("No callback has been defined");
154 setStatus(AudioProcessingStatus::ERROR);
155 return false;
156 }
157
158 // calculate descriptor length;
159 if (interfaceDescriptor(nullptr, 1024) == 0) {
160 setStatus(AudioProcessingStatus::ERROR);
161 LOG_AUDIO_ERROR("Interface Descriptor length was 0");
162 return false;
163 }
164
165 _clk_is_valid = 1;
166 setStatus(AudioProcessingStatus::ACTIVE);
167
168 return true;
169 }
170
171 void end() {
172 tud_deinit(cfg.rh_port);
173 setStatus(AudioProcessingStatus::INACTIVE);
174 if (_out_buffer.size() > 0) _out_buffer.resize(0);
175 if (_in_buffer.size() > 0) _out_buffer.resize(0);
176 }
177
178 // If is mounted
179 bool active(void) {
180 return status() == AudioProcessingStatus::ACTIVE ||
181 status() == AudioProcessingStatus::PLAYING;
182 }
183
184 operator bool() { return active(); }
185
186 // get sample rate
187 uint32_t rate() { return cfg.sample_rate; }
188
189 // get number of channels
190 int channels() { return cfg.channels; }
191
192 // provides the volume for the indicated channel (from 1 to 100)
193 uint16_t volume(int channel) { return _volume[channel]; }
194
195 // checks if the channel is muted
196 bool isMute(int channel) { return _mute[channel]; }
197
199 bool updateLED(int pin) {
200 if (_is_led_setup) {
201 pinMode(pin, OUTPUT);
202 _is_led_setup = false;
203 }
204
205 // led must be active
206 if (_processing_status != AudioProcessingStatus::INACTIVE &&
207 millis() > _led_timeout) {
208 _led_timeout = millis() + (uint16_t)_processing_status;
209 _led_active = !_led_active;
210 digitalWrite(pin, _led_active);
211 return true;
212 }
213
214 // led is inactive
215 if (_processing_status == AudioProcessingStatus::INACTIVE) {
216 if (_led_active) {
217 _led_active = false;
218 digitalWrite(pin, _led_active);
219 }
220 }
221 return false;
222 }
223
225 AudioProcessingStatus status() { return _processing_status; }
226
227 bool isMicrophone() {
228 return (cfg.p_read_callback != nullptr && cfg.p_read_callback != defaultReadCB) ||
229 (cfg.p_read_callback == defaultReadCB && p_stream != nullptr);
230 }
231
232 bool isSpeaker() {
233 return (cfg.p_write_callback != nullptr &&
234 cfg.p_write_callback != defaultWriteCB) ||
235 (cfg.p_write_callback == defaultWriteCB && p_print != nullptr);
236 }
237
238 bool isHeadset() { return isSpeaker() && isMicrophone(); }
239
240 // USBD_Device device() { return TinyUSBDevice; }
241
242 //--------------------------------------------------------------------+
243 // Application Callback API Implementations
244 //--------------------------------------------------------------------+
245 // from USBD_Interface
246
247 virtual uint16_t getMaxEPSize() {
248 return TUD_AUDIO_EP_SIZE(cfg.sample_rate, cfg.bits_per_sample / 8,
249 cfg.channels);
250 }
251
252 virtual uint16_t getIOSize() {
253 return TUD_AUDIO_EP_SIZE(cfg.sample_rate, cfg.bits_per_sample / 8,
254 cfg.channels);
255 }
256
257 virtual uint8_t getFeatureUnitLength() { return (6 + (channels() + 1) * 4); }
258
259 // Invoked when set interface is called, typically on start/stop streaming or
260 // format change
261 bool set_itf_cb(uint8_t rhport,
262 tusb_control_request_t const *p_request) override {
263 uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex));
264 uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue));
265
266 if (alt != 0) setStatus(AudioProcessingStatus::PLAYING);
267
268 return true;
269 }
270
271 // Invoked when audio class specific set request received for an EP
272 bool set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request,
273 uint8_t *pBuff) override {
274 (void)rhport;
275 (void)pBuff;
276
277 // We do not support any set range requests here, only current value
278 // requests
279 TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
280
281 // Page 91 in UAC2 specification
282 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
283 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
284 uint8_t ep = TU_U16_LOW(p_request->wIndex);
285
286 (void)channelNum;
287 (void)ctrlSel;
288 (void)ep;
289
290 return false; // Yet not implemented
291 }
292
293 // Invoked when audio class specific set request received for an interface
294 bool set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request,
295 uint8_t *pBuff) override {
296 (void)rhport;
297 (void)pBuff;
298
299 // We do not support any set range requests here, only current value
300 // requests
301 TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
302
303 // Page 91 in UAC2 specification
304 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
305 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
306 uint8_t itf = TU_U16_LOW(p_request->wIndex);
307
308 (void)channelNum;
309 (void)ctrlSel;
310 (void)itf;
311
312 return false; // Yet not implemented
313 }
314
315 // Invoked when audio class specific set request received for an entity
316 bool set_req_entity_cb(uint8_t rhport,
317 tusb_control_request_t const *p_request,
318 uint8_t *buf) override {
319 // Page 91 in UAC2 specification
320 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
321 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
322 uint8_t itf = TU_U16_LOW(p_request->wIndex);
323 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
324 audio_control_request_t const *request =
325 (audio_control_request_t const *)p_request;
326
327 debugWrite(5, HIGH);
328
329 // for speaker
330 if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) {
331 bool rc = feature_unit_set_request(rhport, p_request, buf);
332 debugWrite(5, LOW);
333 return rc;
334 }
335 if (request->bEntityID == UAC2_ENTITY_CLOCK) {
336 bool rc = clock_set_request(rhport, p_request, buf);
337 debugWrite(5, LOW);
338 return rc;
339 }
340
341 debugWrite(5, HIGH);
342 LOG_AUDIO_DEBUG(
343 "Set request not handled, entity = %d, selector = %d, request = %d",
344 request->bEntityID, request->bControlSelector, request->bRequest);
345 return false; // Yet not implemented
346 }
347
348 // Invoked when audio class specific get request received for an EP
349 bool get_req_ep_cb(uint8_t rhport,
350 tusb_control_request_t const *p_request) override {
351 (void)rhport;
352
353 // Page 91 in UAC2 specification
354 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
355 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
356 uint8_t ep = TU_U16_LOW(p_request->wIndex);
357
358 (void)channelNum;
359 (void)ctrlSel;
360 (void)ep;
361
362 // return tud_control_xfer(rhport, p_request, &tmp, 1);
363
364 return false; // Yet not implemented
365 }
366
367 // Invoked when audio class specific get request received for an interface
368 bool get_req_itf_cb(uint8_t rhport,
369 tusb_control_request_t const *p_request) override {
370 (void)rhport;
371
372 // Page 91 in UAC2 specification
373 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
374 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
375 uint8_t itf = TU_U16_LOW(p_request->wIndex);
376
377 (void)channelNum;
378 (void)ctrlSel;
379 (void)itf;
380
381 return false; // Yet not implemented
382 }
383
384 // Invoked when audio class specific get request received for an entity
385 bool get_req_entity_cb(uint8_t rhport,
386 tusb_control_request_t const *p_request) override {
387 cfg.rh_port = rhport;
388 // Page 91 in UAC2 specification
389 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
390 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
391 // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since
392 // we have only one audio function implemented, we do not need the itf value
393 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
394 audio_control_request_t const *request =
395 (audio_control_request_t const *)p_request;
396
397 debugWrite(6, HIGH);
398
399 // Clock Source
400 if (request->bEntityID == UAC2_ENTITY_CLOCK) {
401 bool rc = clock_get_request(rhport, p_request);
402 if (rc) debugWrite(6, LOW);
403 return rc;
404 }
405
406 // Fueature unit speaker
407 if (request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT) {
408 bool rc = feature_unit_get_request(rhport, p_request);
409 if (rc) debugWrite(6, LOW);
410 return rc;
411 }
412
413 // Feature unit mic
414 if (entityID == UAC2_ENTITY_MIC_FEATURE_UNIT) {
415 bool rc = feature_unit_get_request(rhport, p_request);
416 if (rc) debugWrite(6, LOW);
417 return rc;
418 }
419
420 // Input terminal (Microphone input)
421 if (entityID == UAC2_ENTITY_MIC_INPUT_TERMINAL ||
422 entityID == UAC2_ENTITY_SPK_INPUT_TERMINAL) {
423 switch (ctrlSel) {
424 case AUDIO_TE_CTRL_CONNECTOR: {
425 // The terminal connector control only has a get request with only the
426 // CUR attribute.
427 audio_desc_channel_cluster_t ret;
428 ret.bNrChannels = cfg.channels;
429 ret.bmChannelConfig = (audio_channel_config_t)0;
430 ret.iChannelNames = 0;
431
432 LOG_AUDIO_DEBUG(" Get terminal connector");
433
434 bool rc = _api.tud_audio_buffer_and_schedule_control_xfer(
435 rhport, p_request, (void *)&ret, sizeof(ret));
436 if (rc) debugWrite(6, LOW);
437 return rc;
438 } break;
439
440 // Unknown/Unsupported control selector
441 default:
442 LOG_AUDIO_DEBUG(" Unsupported selector: %d", entityID);
443 debugWrite(6, HIGH);
444 return false;
445 }
446 }
447
448 LOG_AUDIO_DEBUG(" Unsupported entity: %d", entityID);
449 debugWrite(6, HIGH);
450 return false; // Yet not implemented
451 }
452
453 bool tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in,
454 uint8_t cur_alt_setting) override {
455 // (void)rhport;
456 // (void)itf;
457 // (void)ep_in;
458 // (void)cur_alt_setting;
459
460 // fill buffer from "microphone" input
461 if (isMicrophone()) {
462 debugWrite(1, HIGH);
463 // manage buffer size
464 uint16_t len = getIOSize() - 2; // CFG_TUD_AUDIO_EP_SZ_IN - 2;
465 if (_out_buffer.size() < len) _out_buffer.resize(len);
466
467 // return if the buffer is already filled
468 if (_out_buffer.available() != 0) {
469 return true;
470 }
471
472 // fill the buffer with data
473 uint8_t *adr = _out_buffer.data();
474 _out_buffer.clear();
475 int len_eff = (*cfg.p_read_callback)(adr, len, *this);
476 _out_buffer.setAvailable(len_eff);
477 debugWrite(1, LOW);
478 }
479
480 return true;
481 }
482
483 bool tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied,
484 uint8_t itf, uint8_t ep_in,
485 uint8_t cur_alt_setting) override {
486 (void)rhport;
487 (void)itf;
488 (void)ep_in;
489 (void)cur_alt_setting;
490
491 // output audio from "microphone" buffer to usb
492 if (isMicrophone()) {
493 debugWrite(2, HIGH);
494 uint8_t *adr = _out_buffer.data();
495 _api.tud_audio_n_write(func_id, adr, _out_buffer.available());
496 _out_buffer.reset();
497 debugWrite(2, LOW);
498 }
499
500 return true;
501 }
502
503 bool rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received,
504 uint8_t func_id, uint8_t ep_out,
505 uint8_t cur_alt_setting) override {
506 // read audio from usb
507 if (isSpeaker() && _in_buffer.available() == 0) {
508 debugWrite(3, HIGH);
509 uint16_t len = _api.tud_audio_n_available(func_id);
510 if (len > 0) {
511 if (_in_buffer.size() < len) _in_buffer.resize(len);
512 uint8_t *adr = _in_buffer.data();
513 int len_eff = _api.tud_audio_n_read(func_id, adr, len);
514 _in_buffer.setAvailable(len_eff);
515 }
516 debugWrite(3, LOW);
517 return true;
518 }
519 return true;
520 }
521
522 bool rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received,
523 uint8_t func_id, uint8_t ep_out,
524 uint8_t cur_alt_setting) override {
525 // read audio from usb
526 if (isSpeaker() && _in_buffer.available() > 0) {
527 debugWrite(4, HIGH);
528 uint8_t *adr = _in_buffer.data();
529 size_t rc = cfg.p_write_callback(adr, _in_buffer.available(), *this);
530 _in_buffer.consume(rc);
531 debugWrite(4, LOW);
532 }
533 return true;
534 }
535
536 bool set_itf_close_EP_cb(uint8_t rhport,
537 tusb_control_request_t const *p_request) override {
538 (void)rhport;
539 uint8_t const itf = tu_u16_low(tu_le16toh(p_request->wIndex));
540 uint8_t const alt = tu_u16_low(tu_le16toh(p_request->wValue));
541 if (alt == 0) setStatus(AudioProcessingStatus::ACTIVE);
542
543 return true;
544 }
545 // for speaker
546 void feedback_params_cb(uint8_t func_id, uint8_t alt_itf,
547 audio_feedback_params_t *feedback_param) override {
548 (void)func_id;
549 (void)alt_itf;
550 // Set feedback method to fifo counting
551 feedback_param->method = AUDIO_FEEDBACK_METHOD_FIFO_COUNT;
552 feedback_param->sample_freq = cfg.sample_rate;
553 }
554
556 size_t getInterfaceDescriptorLength(uint8_t itfnum) override {
557 return getInterfaceDescriptor(nullptr, 0);
558 }
559
560 // build interface descriptor
561 uint16_t getInterfaceDescriptor(uint8_t *buf,
562 uint16_t bufsize) {
563 // if no source or sink then audio is not active
564 if (!isMicrophone() && !isSpeaker()) {
565 return 0;
566 }
567
568 // if we know the len, we can return it
569 if (buf == nullptr && _desc_len > 0) {
570 return _desc_len;
571 }
572
573 // the buffer was too small
574 if (_desc_len > 0 && bufsize < _desc_len) {
575 return 0;
576 }
577
578 return interfaceDescriptor(buf, bufsize);
579 }
580
581 inline USBDeviceAudioAPI& api() { return _api; }
582
583 protected:
584 bool _is_led_setup = true;
585 AudioProcessingStatus _processing_status = AudioProcessingStatus::INACTIVE;
586 std::vector<bool> _mute; // +1 for master channel 0
587 std::vector<uint16_t> _volume; // +1 for master channel 0
588 uint8_t _clk_is_valid = true;
589 ByteBuffer _in_buffer;
590 ByteBuffer _out_buffer;
591 bool _led_active = false;
592 uint64_t _led_timeout = 0;
593
594 // persisted descriptor data
595 uint8_t _itfnum_spk = 0;
596 uint8_t _itfnum_mic = 0;
597 uint8_t _itf_number_total = 0;
598 uint8_t _itfnum_ctl = 0;
599 uint8_t _ep_ctl = 0;
600 uint8_t _ep_mic = 0;
601 uint8_t _ep_spk = 0;
602 uint8_t _ep_fb = 0;
603 uint8_t _ep_int = 0;
604 uint8_t _stridx = 0;
605 int _desc_append_pos = 0;
606 int _desc_len = 0;
607
608 // input/output callbacks
609 Stream *p_stream = nullptr;
610 Print *p_print = nullptr;
612 USBAudioConfig cfg;
613 std::vector<uint8_t> interface_descriptor;
614
616 void setStatus(AudioProcessingStatus status) { _processing_status = status; }
617
620 void setupDebugPins() {
621#if AUDIO_DEBUG
622 for (int j = 0; j < 8; j++) {
623 pinMode(j, OUTPUT);
624 }
625#endif
626 }
627
628 void append(uint8_t *to, uint8_t *str, int len) {
629 if (to != nullptr) memcpy(to + _desc_append_pos, str, len);
630 _desc_append_pos += len;
631 }
632
633 static size_t defaultWriteCB(const uint8_t *data, size_t len,
634 USBDeviceAudio &ref) {
635 Print *p_print = ref.p_print;
636 if (p_print) return p_print->write((const uint8_t *)data, len);
637 return 0;
638 }
639
640 static size_t defaultReadCB(uint8_t *data, size_t len, USBDeviceAudio &ref) {
641 Stream *p_stream = ref.p_stream;
642 if (p_stream) return p_stream->readBytes((uint8_t *)data, len);
643 return 0;
644 }
645
646 // Helper methods
647 virtual bool feature_unit_get_request(
648 uint8_t rhport, tusb_control_request_t const *p_request) {
649 // Page 91 in UAC2 specification
650 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
651 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
652 // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since
653 // we have only one audio function implemented, we do not need the itf value
654 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
655 switch (ctrlSel) {
656 case AUDIO_FU_CTRL_MUTE: {
657 // Audio control mute cur parameter block consists of only one byte - we
658 // thus can send it right away There does not exist a range parameter
659 // block for mute
660 LOG_AUDIO_DEBUG(" Get Mute of channel: %u", channelNum);
661 bool current_mute = _mute[channelNum];
662 bool rc = tud_control_xfer(rhport, p_request, &current_mute, 1);
663 _mute[channelNum] = current_mute;
664 return rc;
665 }
666
667 case AUDIO_FU_CTRL_VOLUME:
668 switch (p_request->bRequest) {
669 case AUDIO_CS_REQ_CUR:
670 LOG_AUDIO_DEBUG(" Get Volume of channel: %u", channelNum);
671 return tud_control_xfer(rhport, p_request, &_volume[channelNum],
672 sizeof(_volume[channelNum]));
673
674 case AUDIO_CS_REQ_RANGE:
675 LOG_AUDIO_DEBUG(" Get Volume range of channel: %u", channelNum);
676
677 // Copy values - only for testing - better is version below
678 audio_control_range_2_n_t(1) ret;
679
680 ret.wNumSubRanges = 1;
681 ret.subrange[0].bMin = 0; // -90 dB
682 ret.subrange[0].bMax = 100; // +90 dB
683 ret.subrange[0].bRes = 1; // 1 dB steps
684
685 return _api.tud_audio_buffer_and_schedule_control_xfer(
686 rhport, p_request, (void *)&ret, sizeof(ret));
687
688 // Unknown/Unsupported control
689 default:
690 // TU_BREAKPOINT();
691 return false;
692 }
693 break;
694
695 // Unknown/Unsupported control
696 default:
697 // TU_BREAKPOINT();
698 return false;
699 }
700 return false;
701 }
702
703 virtual bool feature_unit_set_request(uint8_t rhport,
704 tusb_control_request_t const *p_request,
705 uint8_t const *buf) {
706 (void)rhport;
707 audio_control_request_t const *request =
708 (audio_control_request_t const *)p_request;
709
710 // TU_ASSERT(request->bEntityID == UAC2_ENTITY_SPK_FEATURE_UNIT);
711 TU_VERIFY(request->bRequest == AUDIO_CS_REQ_CUR);
712
713 if (request->bControlSelector == AUDIO_FU_CTRL_MUTE) {
714 TU_VERIFY(request->wLength == sizeof(audio_control_cur_1_t));
715
716 _mute[request->bChannelNumber] =
717 ((audio_control_cur_1_t const *)buf)->bCur;
718
719 LOG_AUDIO_DEBUG("Set channel %d Mute: %d", request->bChannelNumber,
720 _mute[request->bChannelNumber]);
721
722 return true;
723 } else if (request->bControlSelector == AUDIO_FU_CTRL_VOLUME) {
724 TU_VERIFY(request->wLength == sizeof(audio_control_cur_2_t));
725
726 _volume[request->bChannelNumber] =
727 ((audio_control_cur_2_t const *)buf)->bCur;
728
729 LOG_AUDIO_DEBUG("Set channel %d volume: %d dB", request->bChannelNumber,
730 _volume[request->bChannelNumber] / 256);
731
732 return true;
733 } else {
734 LOG_AUDIO_DEBUG(
735 "Feature unit set request not supported, entity = %u, selector = %u, "
736 "request = %u",
737 request->bEntityID, request->bControlSelector, request->bRequest);
738 return false;
739 }
740 }
741
742 virtual bool clock_get_request(uint8_t rhport,
743 tusb_control_request_t const *p_request) {
744 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
745 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
746 // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since
747 // we have only one audio function implemented, we do not need the itf value
748 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
749 switch (ctrlSel) {
750 case AUDIO_CS_CTRL_SAM_FREQ:
751 // channelNum is always zero in this case
752 switch (p_request->bRequest) {
753 case AUDIO_CS_REQ_CUR:
754 LOG_AUDIO_DEBUG(" Get Sample Freq. -> %d", cfg.sample_rate);
755 // Buffered control transfer is needed for IN flow control to work
756 return _api.tud_audio_buffer_and_schedule_control_xfer(
757 rhport, p_request, &cfg.sample_rate, sizeof(cfg.sample_rate));
758
759 case AUDIO_CS_REQ_RANGE:
760 LOG_AUDIO_DEBUG(" Get Sample Freq. range -> %d - %d",
761 cfg.sample_rate, cfg.sample_rate);
762 audio_control_range_4_n_t(2) sampleFreqRng;
763 sampleFreqRng.wNumSubRanges = 1;
764 sampleFreqRng.subrange[0].bMin = cfg.sample_rate;
765 sampleFreqRng.subrange[0].bMax = cfg.sample_rate;
766 sampleFreqRng.subrange[0].bRes = 0;
767 // sampleFreqRng.subrange[1].bMin = cfg.sample_rate;
768 // sampleFreqRng.subrange[1].bMax = AUDIO_FREQ_MAX;
769 // sampleFreqRng.subrange[1].bRes = 0;
770 return tud_control_xfer(rhport, p_request, &sampleFreqRng,
771 sizeof(sampleFreqRng));
772
773 // Unknown/Unsupported control
774 default:
775 // TU_BREAKPOINT();
776 return false;
777 }
778 break;
779
780 case AUDIO_CS_CTRL_CLK_VALID:
781 // Only cur attribute exists for this request
782 LOG_AUDIO_DEBUG(" Get Sample Freq. valid");
783 return tud_control_xfer(rhport, p_request, &_clk_is_valid,
784 sizeof(_clk_is_valid));
785
786 // Unknown/Unsupported control
787 default:
788 // TU_BREAKPOINT();
789 return false;
790 }
791 }
792
793 virtual bool clock_set_request(uint8_t rhport,
794 tusb_control_request_t const *p_request,
795 uint8_t const *buf) {
796 (void)rhport;
797 uint8_t channelNum = TU_U16_LOW(p_request->wValue);
798 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
799 // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since
800 // we have only one audio function implemented, we do not need the itf value
801 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
802
803 // TU_ASSERT(request->bEntityID == UAC2_ENTITY_CLOCK);
804 // TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
805
806 if (ctrlSel == AUDIO_CS_CTRL_SAM_FREQ) {
807 TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_4_t));
808 cfg.sample_rate = (uint32_t)((audio_control_cur_4_t const *)buf)->bCur;
809 LOG_AUDIO_DEBUG("Clock set current freq: %ld", cfg.sample_rate);
810 return true;
811 } else {
812 LOG_AUDIO_DEBUG(
813 "Clock set request not supported, entity = %u, selector = %u, "
814 "request "
815 "= %u",
816 entityID, ctrlSel, p_request->bRequest);
817 return false;
818 }
819 }
820
821 uint16_t interfaceDescriptor(uint8_t *buf, uint16_t bufsize) {
822 // Generate the descriptor and calculate it's length
823 uint8_t feature_unit_len = getFeatureUnitLength();
824 _desc_append_pos = 0;
825
826 // setup control interface and endpoint
827 if (_desc_len == 0) {
828 _itf_number_total = 1;
829 _itfnum_ctl = allocInterface();
830 _ep_ctl = allocEndpoint(TUSB_DIR_IN);
831 }
832
833 // Setup endpints and interfaces
834 if (isHeadset() && _desc_len == 0) {
835 _itfnum_mic = allocInterface(); // input interface
836 _itfnum_spk = allocInterface(); // output interface
837 _ep_mic = allocEndpoint(TUSB_DIR_IN); // intput
838 _ep_int = allocEndpoint(TUSB_DIR_IN); // input
839 _ep_spk = allocEndpoint(TUSB_DIR_OUT); // output
840 _itf_number_total += 2;
841 } else if (isMicrophone() && _desc_len == 0) {
842 _itfnum_mic = allocInterface();
843 _ep_mic = allocEndpoint(TUSB_DIR_IN);
844 _itf_number_total++;
845 } else if (isSpeaker() && _desc_len == 0) {
846 _itfnum_spk = allocInterface(); // output interface
847 _ep_spk = allocEndpoint(TUSB_DIR_OUT);
848 _ep_fb = allocEndpoint(TUSB_DIR_IN);
849 _itf_number_total++;
850 }
851
852 // generate descriptor
853 if (isHeadset()) {
854 uint8_t total_len = TUD_AUDIO_DESC_CLK_SRC_LEN + feature_unit_len +
855 (2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN +
856 TUD_AUDIO_DESC_OUTPUT_TERM_LEN));
857 interfaceDescriptorHeadset(buf, total_len);
858 } else if (isMicrophone()) {
859 uint8_t total_len = TUD_AUDIO_DESC_CLK_SRC_LEN + feature_unit_len +
860 TUD_AUDIO_DESC_INPUT_TERM_LEN +
861 TUD_AUDIO_DESC_OUTPUT_TERM_LEN;
862 interfaceDescriptorMicrophone(buf, total_len);
863 } else if (isSpeaker()) {
864 uint8_t total_len = TUD_AUDIO_DESC_CLK_SRC_LEN + feature_unit_len +
865 TUD_AUDIO_DESC_INPUT_TERM_LEN +
866 TUD_AUDIO_DESC_OUTPUT_TERM_LEN;
867 interfaceDescriptorSpeaker(buf, total_len);
868 }
869
870 // record descriptor length
871 if (_desc_len == 0) {
872 _desc_len = _desc_append_pos;
873 }
874
875 return _desc_len;
876 }
877
878 void interfaceDescriptorHeader(uint8_t *buf, uint8_t total_len,
879 uint8_t category) {
880 /* Standard Interface Association Descriptor (IAD) */
881 uint8_t d1[] = {TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum_ctl,
882 /*_nitfs*/ _itf_number_total,
883 /*_stridx*/ 0)};
884 append(buf, d1, sizeof(d1));
885
886 /* Standard AC Interface Descriptor(4.7.1) */
887 uint8_t d2[] = {TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum_ctl,
888 /*_nEPs*/ 0x00, /*_stridx*/ _stridx)};
889 append(buf, d2, sizeof(d2));
890
891 /* Class-Specific AC Interface Header Descriptor(4.7.2) AUDIO_FUNC_OTHER */
892 uint8_t d3[] = {TUD_AUDIO_DESC_CS_AC(
893 /*_bcdADC*/ 0x0200, /*_category*/ category, /*_totallen*/ total_len,
894 /*_ctrl*/ AUDIO_CTRL_NONE << AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS)};
895 append(buf, d3, sizeof(d3));
896 }
897 void interfaceDescriptorMicrophone(uint8_t *buf, uint8_t total_len) {
898 interfaceDescriptorHeader(buf, total_len, AUDIO_FUNC_MICROPHONE);
899 /* Clock Source Descriptor(4.7.2.1) */
900 // TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/
901 // AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R <<
902 // AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/
903 // 0x00),
904 uint8_t d4[] = {TUD_AUDIO_DESC_CLK_SRC(
905 /*_clkid*/ UAC2_ENTITY_CLOCK,
906 /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK,
907 /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS),
908 /*_assocTerm*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_stridx*/ 0x00)};
909 append(buf, d4, sizeof(d4));
910
911 /* Input Terminal Descriptor(4.7.2.4) */
912 // TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/
913 // AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x03, /*_clkid*/ 0x04,
914 // /*_nchannelslogical*/ 0x02, /*_channelcfg*/
915 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/
916 // AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00),
917 uint8_t d7[] = {TUD_AUDIO_DESC_INPUT_TERM(
918 /*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL,
919 /*_termtype*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL,
920 /*_assocTerm*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL,
921 /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ cfg.channels,
922 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED,
923 /*_idxchannelnames*/ 0x00,
924 /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS,
925 /*_stridx*/ 0x00)};
926 append(buf, d7, sizeof(d7));
927 /* Output Terminal Descriptor(4.7.2.5) */
928 // TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/
929 // AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x01, /*_srcid*/ 0x02,
930 // /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),
931 uint8_t d8[] = {TUD_AUDIO_DESC_OUTPUT_TERM(
932 /*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL,
933 /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING,
934 /*_assocTerm*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
935 /*_srcid*/ UAC2_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK,
936 /*_ctrl*/ 0x0000, /*_stridx*/ 0x00)};
937 append(buf, d8, sizeof(d8));
938
939 /* Feature Unit Descriptor(4.7.2.8) */
940 // #define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid,
941 // _ctrlch0master, _ctrlch1, _ctrlch2, _stridx)
942 // TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE,
943 // AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid,
944 // U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1),
945 // U32_TO_U8S_LE(_ctrlch2), _stridx
946 // TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/
947 // 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW <<
948 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
949 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW <<
950 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
951 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW <<
952 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
953 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00),\
954
955 uint8_t feature_unit_len = getFeatureUnitLength();
956 uint8_t df1[] = {feature_unit_len, TUSB_DESC_CS_INTERFACE,
957 AUDIO_CS_AC_INTERFACE_FEATURE_UNIT,
958 /*_unitid*/ UAC2_ENTITY_MIC_FEATURE_UNIT,
959 /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL};
960 append(buf, df1, sizeof(df1));
961 for (int j = 0; j < cfg.channels + 1; j++) {
962 uint8_t df2[] = {
963 U32_TO_U8S_LE(AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS |
964 AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS)};
965 append(buf, df2, sizeof(df2));
966 }
967 // _stridx
968 uint8_t df3[1] = {0x00};
969 append(buf, df3, sizeof(df3));
970
971 /* Standard AS Interface Descriptor(4.9.1) */ /* Interface 2, Alternate 0 -
972 default alternate setting
973 with 0 bandwidth */
974 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
975 // (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
976 // /*_stridx*/ 0x00),
977 uint8_t d15[] = {TUD_AUDIO_DESC_STD_AS_INT(
978 /*_itfnum*/ (uint8_t)(_itfnum_mic), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
979 /*_stridx*/ 0x00)};
980 append(buf, d15, sizeof(d15));
981 /* Standard AS Interface Descriptor(4.9.1) */
982 /* Interface 2, Alternate 1 - alternate interface for data streaming */
983 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
984 // (uint8_t)((_itfnum)+1), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
985 // /*_stridx*/ 0x00),
986 uint8_t d16[] = {TUD_AUDIO_DESC_STD_AS_INT(
987 /*_itfnum*/ (uint8_t)(_itfnum_mic), /*_altset*/ 0x01, /*_nEPs*/ 0x01,
988 /*_stridx*/ 0x00)};
989 append(buf, d16, sizeof(d16));
990 /* Class-Specific AS Interface Descriptor(4.9.2) */
991 // TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/
992 // AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I,
993 // /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM,
994 // /*_nchannelsphysical*/ 0x02, /*_channelcfg*/
995 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),
996 uint8_t d17[] = {TUD_AUDIO_DESC_CS_AS_INT(
997 /*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE,
998 /*_formattype*/ AUDIO_FORMAT_TYPE_I,
999 /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM,
1000 /*_nchannelsphysical*/ cfg.channels,
1001 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00)};
1002 append(buf, d17, sizeof(d17));
1003 /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
1004 // TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample,
1005 // _nBitsUsedPerSample),
1006 uint8_t d18[] = {TUD_AUDIO_DESC_TYPE_I_FORMAT(
1007 (uint8_t)(cfg.bits_per_sample / 8), (uint8_t)cfg.bits_per_sample)};
1008 append(buf, d18, sizeof(d18));
1009 /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
1010 // TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/
1011 // (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS |
1012 // (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS |
1013 // (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize,
1014 // /*_interval*/ 0x01),
1015 uint8_t attr = static_cast<uint8_t>(TUSB_XFER_ISOCHRONOUS) |
1016 static_cast<uint8_t>(TUSB_ISO_EP_ATT_ASYNCHRONOUS) |
1017 static_cast<uint8_t>(TUSB_ISO_EP_ATT_DATA);
1018 uint8_t d19[] = {TUD_AUDIO_DESC_STD_AS_ISO_EP(
1019 /*_ep*/ _ep_mic, /*_attr*/ attr, /*_maxEPsize*/ getMaxEPSize(),
1020 /*_interval*/ 0x01)};
1021 append(buf, d19, sizeof(d19));
1022 /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
1023 // TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/
1024 // AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/
1025 // AUDIO_CTRL_NONE, /*_lockdelayunit*/
1026 // AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED,
1027 // /*_lockdelay*/ 0x0000)
1028 uint8_t d20[] = {TUD_AUDIO_DESC_CS_AS_ISO_EP(
1029 /*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK,
1030 /*_ctrl*/ AUDIO_CTRL_NONE,
1031 /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED,
1032 /*_lockdelay*/ 0x0000)};
1033 append(buf, d20, sizeof(d20));
1034 }
1035
1036 void interfaceDescriptorSpeaker(uint8_t *buf, uint8_t total_len) {
1037 interfaceDescriptorHeader(buf, total_len, AUDIO_FUNC_DESKTOP_SPEAKER);
1038 /* Clock Source Descriptor(4.7.2.1) */
1039 // TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/
1040 // AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R <<
1041 // AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x01, /*_stridx*/
1042 // 0x00),
1043 uint8_t d4[] = {TUD_AUDIO_DESC_CLK_SRC(
1044 /*_clkid*/ UAC2_ENTITY_CLOCK,
1045 /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK,
1046 /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS),
1047 /*_assocTerm*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00)};
1048 append(buf, d4, sizeof(d4));
1049 /* Input Terminal Descriptor(4.7.2.4) */
1050 // TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/
1051 // AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00,
1052 // /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, /*_channelcfg*/
1053 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/
1054 // 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R <<
1055 // AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),
1056 uint8_t d7[] = {TUD_AUDIO_DESC_INPUT_TERM(
1057 /*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1058 /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00,
1059 /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ cfg.channels,
1060 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED,
1061 /*_idxchannelnames*/ 0x00,
1062 /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS),
1063 /*_stridx*/ 0x00)};
1064 append(buf, d7, sizeof(d7));
1065 /* Output Terminal Descriptor(4.7.2.5) */
1066 // TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/
1067 // AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x01,
1068 // /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000,
1069 // /*_stridx*/ 0x00),
1070 uint8_t d8[] = {TUD_AUDIO_DESC_OUTPUT_TERM(
1071 /*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL,
1072 /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER,
1073 /*_assocTerm*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1074 /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK,
1075 /*_ctrl*/ 0x0000, /*_stridx*/ 0x00)};
1076 append(buf, d8, sizeof(d8));
1077
1078 /* Feature Unit Descriptor(4.7.2.8) */
1079 // #define TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(_unitid, _srcid,
1080 // _ctrlch0master, _ctrlch1, _ctrlch2, _stridx)
1081 // TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, TUSB_DESC_CS_INTERFACE,
1082 // AUDIO_CS_AC_INTERFACE_FEATURE_UNIT, _unitid, _srcid,
1083 // U32_TO_U8S_LE(_ctrlch0master), U32_TO_U8S_LE(_ctrlch1),
1084 // U32_TO_U8S_LE(_ctrlch2), _stridx
1085 // TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/
1086 // 0x01, /*_ctrlch0master*/ AUDIO_CTRL_RW <<
1087 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1088 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW <<
1089 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1090 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW <<
1091 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1092 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS,/*_stridx*/ 0x00),\ uint8_t dfu[] =
1093 // {TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/
1094 // UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1095 // /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS |
1096 // AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/
1097 // AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1098 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW <<
1099 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1100 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00)}; append(buf, dfu,
1101 // sizeof(dfu));
1102
1103 uint8_t feature_unit_len = getFeatureUnitLength();
1104 uint8_t df1[] = {feature_unit_len, TUSB_DESC_CS_INTERFACE,
1105 AUDIO_CS_AC_INTERFACE_FEATURE_UNIT,
1106 /*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT,
1107 /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL};
1108 append(buf, df1, sizeof(df1));
1109 for (int j = 0; j < cfg.channels + 1; j++) {
1110 uint8_t df2[] = {
1111 U32_TO_U8S_LE(AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS |
1112 AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS)};
1113 append(buf, df2, sizeof(df2));
1114 }
1115 /*_stridx 0x00*/
1116 uint8_t df3[1] = {0x00};
1117 append(buf, df3, sizeof(df3));
1118
1119 /* Standard AS Interface Descriptor(4.9.1) */ /* Interface 2, Alternate 0 -
1120 default alternate setting
1121 with 0 bandwidth */
1122 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)
1123 // + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),
1124 uint8_t d15[] = {TUD_AUDIO_DESC_STD_AS_INT(
1125 /*_itfnum*/ (uint8_t)(_itfnum_spk), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
1126 /*_stridx*/ 0x00)};
1127 append(buf, d15, sizeof(d15));
1128 /* Standard AS Interface Descriptor(4.9.1) */
1129 /* Interface 2, Alternate 1 - alternate interface for data streaming */
1130 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum)
1131 // + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x02, /*_stridx*/ 0x00),
1132 uint8_t d16[] = {TUD_AUDIO_DESC_STD_AS_INT(
1133 /*_itfnum*/ (uint8_t)(_itfnum_spk), /*_altset*/ 0x01, /*_nEPs*/ 0x02,
1134 /*_stridx*/ 0x00)};
1135 append(buf, d16, sizeof(d16));
1136 // // TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x03, /*_ctrl*/
1137 // AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/
1138 // AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02,
1139 // /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),
1140 uint8_t d17[] = {TUD_AUDIO_DESC_CS_AS_INT(
1141 /*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE,
1142 /*_formattype*/ AUDIO_FORMAT_TYPE_I,
1143 /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM,
1144 /*_nchannelsphysical*/ cfg.channels,
1145 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00)};
1146 append(buf, d17, sizeof(d17));
1147
1148 /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
1149 // TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample,
1150 // _nBitsUsedPerSample),
1151 uint8_t d18[] = {TUD_AUDIO_DESC_TYPE_I_FORMAT(
1152 (uint8_t)(cfg.bits_per_sample / 8), (uint8_t)cfg.bits_per_sample)};
1153 append(buf, d18, sizeof(d18));
1154 // /* Class-Specific AS Interface Descriptor(4.9.2) */
1155 /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
1156 // TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/
1157 // (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS |
1158 // (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS |
1159 // (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epoutsize,
1160 // /*_interval*/ 0x01),
1161 uint8_t d19[] = {TUD_AUDIO_DESC_STD_AS_ISO_EP(
1162 /*_ep*/ _ep_spk, /*_attr*/
1163 (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS |
1164 (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS |
1165 (uint8_t)TUSB_ISO_EP_ATT_DATA),
1166 /*_maxEPsize*/ getMaxEPSize(), /*_interval*/ 0x01)};
1167 append(buf, d19, sizeof(d19));
1168 /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
1169 // TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/
1170 // AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/
1171 // AUDIO_CTRL_NONE, /*_lockdelayunit*/
1172 // AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC,
1173 // /*_lockdelay*/ 0x0001)
1174 uint8_t d20[] = {TUD_AUDIO_DESC_CS_AS_ISO_EP(
1175 /*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK,
1176 /*_ctrl*/ AUDIO_CTRL_NONE,
1177 /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC,
1178 /*_lockdelay*/ 0x0001)};
1179 append(buf, d20, sizeof(d20));
1180
1181 // /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */
1182#if ISO_FB_EP==3
1183 // TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(/*_ep*/ _epfb, /*_epsize*/ _epfbsize, /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1)
1184 uint8_t d21[] = {TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(
1185 /*_ep*/ _ep_fb, /*_epsize*/ 0X04,
1186 /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1)};
1187#else
1188 uint8_t d21[] = {TUD_AUDIO_DESC_STD_AS_ISO_FB_EP(
1189 /*_ep*/ _ep_fb, /*_epsize 0X04,*/
1190 /*_interval*/ TUD_OPT_HIGH_SPEED ? 4 : 1)};
1191#endif
1192 append(buf, d21, sizeof(d21));
1193 }
1194
1195 void interfaceDescriptorHeadset(uint8_t *buf, uint8_t total_len) {
1196 interfaceDescriptorHeader(buf, total_len, AUDIO_FUNC_HEADSET);
1197
1198 /* Clock Source Descriptor(4.7.2.1) */
1199 // TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ UAC2_ENTITY_CLOCK, /*_attr*/ 3,
1200 // /*_ctrl*/ 7, /*_assocTerm*/ 0x00, /*_stridx*/ 0x00),
1201 uint8_t d1[] = {TUD_AUDIO_DESC_CLK_SRC(
1202 /*_clkid*/ UAC2_ENTITY_CLOCK,
1203 /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_PRO_CLK, /*_ctrl*/ 7,
1204 /*_assocTerm*/ 00, /*_stridx*/ 0x00)};
1205 append(buf, d1, sizeof(d1));
1206
1207 /* Input Terminal Descriptor(4.7.2.4) */
1208 // TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1209 // /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00,
1210 // /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x02, /*_channelcfg*/
1211 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/
1212 // 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/
1213 // 0x00),
1214 uint8_t d2[] = {TUD_AUDIO_DESC_INPUT_TERM(
1215 /*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1216 /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00,
1217 /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ cfg.channels,
1218 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED,
1219 /*_idxchannelnames*/ 0x00,
1220 /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS),
1221 /*_stridx*/ 0x00)};
1222 append(buf, d2, sizeof(d2));
1223
1224 /* Feature Unit Descriptor(4.7.2.8) */
1225 // TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/
1226 // UAC2_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1227 // /*_ctrlch0master*/ (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS |
1228 // AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch1*/
1229 // (AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1230 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_ctrlch2*/ (AUDIO_CTRL_RW <<
1231 // AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW <<
1232 // AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), /*_stridx*/ 0x00),
1233 uint8_t feature_unit_len = getFeatureUnitLength();
1234 uint8_t df1[] = {feature_unit_len, TUSB_DESC_CS_INTERFACE,
1235 AUDIO_CS_AC_INTERFACE_FEATURE_UNIT,
1236 /*_unitid*/ UAC2_ENTITY_SPK_FEATURE_UNIT,
1237 /*_srcid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL};
1238 append(buf, df1, sizeof(df1));
1239 // first is master channel
1240 for (int j = 0; j < cfg.channels + 1; j++) {
1241 uint8_t df2[] = {
1242 U32_TO_U8S_LE((AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS |
1243 AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS))};
1244 append(buf, df2, sizeof(df2));
1245 }
1246 /*_stridx 0x00*/
1247 uint8_t df3[1] = {0x00};
1248 append(buf, df3, sizeof(df3));
1249
1250 //-- out ---
1251
1252 /* Output Terminal Descriptor(4.7.2.5) */
1253 // TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL,
1254 // /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 0x00,
1255 // /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK,
1256 // /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),
1257 uint8_t d3[] = {TUD_AUDIO_DESC_OUTPUT_TERM(
1258 /*_termid*/ UAC2_ENTITY_SPK_OUTPUT_TERMINAL,
1259 /*_termtype*/ AUDIO_TERM_TYPE_OUT_HEADPHONES, /*_assocTerm*/ 00,
1260 /*_srcid*/ UAC2_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ UAC2_ENTITY_CLOCK,
1261 /*_ctrl*/ 0x0000, /*_stridx*/ 0x00)};
1262 append(buf, d3, sizeof(d3));
1263
1264 /* Input Terminal Descriptor(4.7.2.4) */
1265 // TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL,
1266 // /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00,
1267 // /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/
1268 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/
1269 // 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/
1270 // 0x00),
1271 uint8_t d4[] = {TUD_AUDIO_DESC_INPUT_TERM(
1272 /*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL,
1273 /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 00,
1274 /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ cfg.channels,
1275 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED,
1276 /*_idxchannelnames*/ 0x00,
1277 /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS),
1278 /*_stridx*/ 0x00)};
1279 append(buf, d4, sizeof(d4));
1280
1281 /* Output Terminal Descriptor(4.7.2.5) */
1282 // TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL,
1283 // /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00,
1284 // /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK,
1285 // /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),
1286 uint8_t d5[] = {TUD_AUDIO_DESC_OUTPUT_TERM(
1287 /*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL,
1288 /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 00,
1289 /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK,
1290 /*_ctrl*/ 0x0000, /*_stridx*/ 0x00)};
1291 append(buf, d5, sizeof(d5));
1292
1293 /* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */
1294 // TUD_AUDIO_DESC_STD_AC_INT_EP(/*_ep*/ _epint, /*_interval*/ 0x01),
1295 uint8_t d6[] = {
1296 TUD_AUDIO_DESC_STD_AC_INT_EP(/*_ep*/ _ep_int, /*_interval*/ 0x01)};
1297 append(buf, d6, sizeof(d6));
1298
1299 // -- SPK ---
1300
1301 /* Standard AS Interface Descriptor(4.9.1) */
1302 /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */
1303 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
1304 // (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
1305 // /*_stridx*/ 0x05),
1306 uint8_t d7[] = {TUD_AUDIO_DESC_STD_AS_INT(
1307 /*_itfnum*/ (uint8_t)(_itfnum_spk), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
1308 /*_stridx*/ 0x05)};
1309 append(buf, d7, sizeof(d7));
1310
1311 /* Standard AS Interface Descriptor(4.9.1) */
1312 /* Interface 1, Alternate 1 - alternate interface for data streaming */
1313 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
1314 // (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x01, /*_nEPs*/ 0x01,
1315 // /*_stridx*/ 0x05),
1316 uint8_t d8[] = {TUD_AUDIO_DESC_STD_AS_INT(
1317 /*_itfnum*/ (uint8_t)(_itfnum_spk), /*_altset*/ 0x01, /*_nEPs*/ 0x01,
1318 /*_stridx*/ 0x05)};
1319 append(buf, d8, sizeof(d8));
1320
1321 /* Class-Specific AS Interface Descriptor(4.9.2) */
1322 // TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL,
1323 // /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I,
1324 // /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/
1325 // CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX, /*_channelcfg*/
1326 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),
1327 uint8_t d9[] = {TUD_AUDIO_DESC_CS_AS_INT(
1328 /*_termid*/ UAC2_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE,
1329 /*_formattype*/ AUDIO_FORMAT_TYPE_I,
1330 /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM,
1331 /*_nchannelsphysical*/ cfg.channels,
1332 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00)};
1333 append(buf, d9, sizeof(d9));
1334
1335 /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
1336 // TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX,
1337 // CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),
1338 uint8_t d10[] = {TUD_AUDIO_DESC_TYPE_I_FORMAT(
1339 (uint8_t)(cfg.bits_per_sample / 8), (uint8_t)cfg.bits_per_sample)};
1340 append(buf, d10, sizeof(d10));
1341
1342 /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
1343 // TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)
1344 // ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE |
1345 // (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/
1346 // TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE,
1347 // CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX,
1348 // CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),
1349 uint8_t d11[] = {TUD_AUDIO_DESC_STD_AS_ISO_EP(
1350 /*_ep*/ _ep_spk, /*_attr*/
1351 (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS |
1352 (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE |
1353 (uint8_t)TUSB_ISO_EP_ATT_DATA),
1354 /*_maxEPsize*/ getMaxEPSize(), /*_interval*/ 0x01)};
1355 append(buf, d11, sizeof(d11));
1356
1357 /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
1358 // TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/
1359 // AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/
1360 // AUDIO_CTRL_NONE, /*_lockdelayunit*/
1361 // AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),
1362 uint8_t d12[] = {TUD_AUDIO_DESC_CS_AS_ISO_EP(
1363 /*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK,
1364 /*_ctrl*/ AUDIO_CTRL_NONE,
1365 /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC,
1366 /*_lockdelay*/ 0x0001)};
1367 append(buf, d12, sizeof(d12));
1368
1369 // -- MIC ---
1370 /* Standard AS Interface Descriptor(4.9.1) */
1371 /* Interface 2, Alternate 0 - default alternate setting with 0 bandwidth */
1372 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
1373 // (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
1374 // /*_stridx*/ 0x04),
1375 uint8_t d13[] = {TUD_AUDIO_DESC_STD_AS_INT(
1376 /*_itfnum*/ (uint8_t)(_itfnum_mic), /*_altset*/ 0x00, /*_nEPs*/ 0x00,
1377 /*_stridx*/ 0x04)};
1378 append(buf, d13, sizeof(d13));
1379
1380 /* Standard AS Interface Descriptor(4.9.1) */
1381 /* Interface 2, Alternate 1 - alternate interface for data streaming */
1382 // TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/
1383 // (uint8_t)(ITF_NUM_AUDIO_STREAMING_MIC), /*_altset*/ 0x01, /*_nEPs*/ 0x01,
1384 // /*_stridx*/ 0x04),
1385 uint8_t d14[] = {TUD_AUDIO_DESC_STD_AS_INT(
1386 /*_itfnum*/ (uint8_t)(_itfnum_mic), /*_altset*/ 0x01, /*_nEPs*/ 0x01,
1387 /*_stridx*/ 0x04)};
1388 append(buf, d14, sizeof(d14));
1389
1390 /* Class-Specific AS Interface Descriptor(4.9.2) */
1391 // TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL,
1392 // /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I,
1393 // /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/
1394 // CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX, /*_channelcfg*/
1395 // AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),
1396 uint8_t d15[] = {TUD_AUDIO_DESC_CS_AS_INT(
1397 /*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE,
1398 /*_formattype*/ AUDIO_FORMAT_TYPE_I,
1399 /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM,
1400 /*_nchannelsphysical*/ cfg.channels,
1401 /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00)};
1402 append(buf, d15, sizeof(d15));
1403
1404 /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */
1405 // TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX,
1406 // CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),
1407 uint8_t d16[] = {TUD_AUDIO_DESC_TYPE_I_FORMAT(
1408 (uint8_t)(cfg.bits_per_sample / 8), (uint8_t)cfg.bits_per_sample)};
1409 append(buf, d16, sizeof(d16));
1410
1411 /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */
1412 // TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)
1413 // ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS |
1414 // (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/
1415 // TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE,
1416 // CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX,
1417 // CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),
1418 uint8_t d17[] = {TUD_AUDIO_DESC_STD_AS_ISO_EP(
1419 /*_ep*/ _ep_mic, /*_attr*/
1420 (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS |
1421 (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS |
1422 (uint8_t)TUSB_ISO_EP_ATT_DATA),
1423 /*_maxEPsize*/ getMaxEPSize(), /*_interval*/ 0x01)};
1424 append(buf, d17, sizeof(d17));
1425
1426 /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */
1427 // TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/
1428 // AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/
1429 // AUDIO_CTRL_NONE, /*_lockdelayunit*/
1430 // AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/
1431 // 0x0000),
1432 uint8_t d18[] = {TUD_AUDIO_DESC_CS_AS_ISO_EP(
1433 /*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK,
1434 /*_ctrl*/ AUDIO_CTRL_NONE,
1435 /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED,
1436 /*_lockdelay*/ 0x0000)};
1437 append(buf, d18, sizeof(d18));
1438 }
1439};
A resizable buffer of bytes which manages the available bytes.
Definition USBDeviceAudio.h:64
Definition USBDeviceAudioAPI.h:103
Configuration for TinyUSB Audio.
Definition USBDeviceAudioAPI.h:43
Definition USBDeviceAudioAPI.h:177
uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len)
Write data to EP in buffer.
Definition USBDeviceAudioAPI.h:231
Definition USBDeviceAudio.h:104
void setupDebugPins()
Definition USBDeviceAudio.h:619
AudioProcessingStatus status()
Provide the actual status.
Definition USBDeviceAudio.h:225
void setWriteCallback(size_t(*write_cb)(const uint8_t *data, size_t len, USBDeviceAudio &ref))
Definition USBDeviceAudio.h:111
void setStatus(AudioProcessingStatus status)
Define the led delay.
Definition USBDeviceAudio.h:615
void setReadCallback(size_t(*read_cb)(uint8_t *data, size_t len, USBDeviceAudio &ref))
Definition USBDeviceAudio.h:118
size_t getInterfaceDescriptorLength(uint8_t itfnum) override
Determine the interface descriptor length.
Definition USBDeviceAudio.h:555
bool updateLED(int pin)
Call from loop to blink led.
Definition USBDeviceAudio.h:199
void setOutput(Print &out)
Alternative to setWriteCallback.
Definition USBDeviceAudio.h:124
void setInput(Stream &in)
Alternaive to setReadCallback.
Definition USBDeviceAudio.h:130
Definition USBDeviceAudioAPI.h:28