arduino-audio-tools
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 
56 enum class AudioProcessingStatus {
57  INACTIVE = 0,
58  ERROR = 500,
59  PLAYING = 1000,
60  ACTIVE = 2000
61 };
62 
64 class ByteBuffer {
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 
104 class USBDeviceAudio : public USBAudioCB {
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 
145  setupDebugPins();
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;
611  USBDeviceAudioAPI _api;
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