arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
USBAudio2DescriptorBuilder.h
1#include <cstdint>
2#include <cstring>
3#include <functional>
4
5#include "tusb.h"
6#include "USBAudioConfig.h"
7
8
9namespace audio_tools {
10
11// Audio 2.0 Descriptor Generator
13 public:
15 p_config = &cfg;
16 }
17
18 uint16_t calcMaxPacketSize() const {
19 uint16_t bytesPerFrame = (p_config->bits_per_sample / 8) * p_config->channels;
20 uint16_t samplesPerMs = (p_config->sample_rate + 999) / 1000;
21 return bytesPerFrame * samplesPerMs;
22 }
23
24 const uint8_t* buildDescriptor(uint8_t itf, uint8_t alt, uint16_t* outLen) {
25 static uint8_t desc[256];
26 uint8_t* p = desc;
27
28 if (alt == 0) {
29 p = addStandardInterfaceDesc(p, itf, alt, 0);
30 } else {
31 p = addStandardInterfaceDesc(p, itf, alt, 1);
32 p = addCsInterfaceHeader(p);
33 p = addInputTerminalDesc(p);
34 p = addFeatureUnitDesc(p);
35 p = addOutputTerminalDesc(p);
36 p = addFormatTypeDesc(p);
37 p = addIsoDataEndpointDesc(p);
38 p = addCsIsoEndpointDesc(p);
39 }
40
41 *outLen = static_cast<uint16_t>(p - desc);
42 return desc;
43 }
44
45 private:
46 uint8_t* addStandardInterfaceDesc(uint8_t* p, uint8_t itf, uint8_t alt,
47 uint8_t numEps) {
48 *p++ = 9; // bLength
49 *p++ = 0x04; // bDescriptorType = Interface
50 *p++ = itf; // bInterfaceNumber
51 *p++ = alt; // bAlternateSetting
52 *p++ = numEps; // bNumEndpoints
53 *p++ = 0x01; // bInterfaceClass (AUDIO)
54 *p++ = 0x02; // bInterfaceSubClass (Streaming)
55 *p++ = 0x20; // bInterfaceProtocol (2.0)
56 *p++ = 0; // iInterface
57 return p;
58 }
59
60 uint8_t* addCsInterfaceHeader(uint8_t* p) {
61 *p++ = 7; // bLength
62 *p++ = 0x24; // CS_INTERFACE
63 *p++ = 0x01; // HEADER subtype
64 *p++ = 0x00;
65 *p++ = 0x02; // bcdADC = 2.00
66 *p++ = 0x01; // bCategory = 1 (Speaker)
67 *p++ = 0x00; // wTotalLength (placeholder)
68 return p;
69 }
70
71 uint8_t* addInputTerminalDesc(uint8_t* p) {
72 *p++ = 17; // bLength
73 *p++ = 0x24; // CS_INTERFACE
74 *p++ = 0x02; // INPUT_TERMINAL subtype
75 *p++ = p_config->entity_id_input_terminal; // bTerminalID
76 *p++ = 0x01;
77 *p++ = 0x01; // wTerminalType = USB Streaming
78 *p++ = 0x00; // bAssocTerminal
79 *p++ = p_config->channels; // bNrChannels
80 *p++ = 0x03;
81 *p++ = 0x00;
82 *p++ = 0x00;
83 *p++ = 0x00; // wChannelConfig
84 *p++ = 0; // iChannelNames
85 *p++ = 0; // iTerminal
86 return p;
87 }
88
89 uint8_t* addFeatureUnitDesc(uint8_t* p) {
90 uint8_t length = 7 + (p_config->channels + 1) * 2;
91 *p++ = length; // bLength
92 *p++ = 0x24; // CS_INTERFACE
93 *p++ = 0x06; // FEATURE_UNIT subtype
94 *p++ = p_config->entity_id_feature_unit; // bUnitID
95 *p++ = p_config->entity_id_input_terminal; // bSourceID
96 *p++ = 0x01; // bControlSize
97 *p++ = 0x01; // bmaControls[0] (Master Mute)
98 for (uint8_t i = 1; i <= p_config->channels; ++i) {
99 *p++ = 0x03; // bmaControls[i] (Mute + Volume)
100 }
101 *p++ = 0x00; // iFeature
102 return p;
103 }
104
105 uint8_t* addOutputTerminalDesc(uint8_t* p) {
106 *p++ = 12; // bLength
107 *p++ = 0x24; // CS_INTERFACE
108 *p++ = 0x03; // OUTPUT_TERMINAL subtype
109 *p++ = p_config->entity_id_output_terminal; // bTerminalID
110 *p++ = 0x01;
111 *p++ = 0x03; // wTerminalType = Speaker
112 *p++ = 0x00; // bAssocTerminal
113 *p++ = p_config->entity_id_feature_unit; // bSourceID
114 *p++ = 0x00; // iTerminal
115 return p;
116 }
117
118 uint8_t* addFormatTypeDesc(uint8_t* p) {
119 *p++ = 14; // bLength
120 *p++ = 0x24; // CS_INTERFACE
121 *p++ = 0x02; // FORMAT_TYPE subtype
122 *p++ = 0x01; // FORMAT_TYPE_I
123 *p++ = p_config->channels; // bNrChannels
124 *p++ = p_config->bits_per_sample / 8; // bSubslotSize
125 *p++ = p_config->bits_per_sample; // bBitResolution
126 *p++ = 1; // bSamFreqType
127 *p++ = (uint8_t)(p_config->sample_rate & 0xFF);
128 *p++ = (uint8_t)((p_config->sample_rate >> 8) & 0xFF);
129 *p++ = (uint8_t)((p_config->sample_rate >> 16) & 0xFF);
130 return p;
131 }
132
133 uint8_t* addIsoDataEndpointDesc(uint8_t* p) {
134 uint16_t packetSize = calcMaxPacketSize();
135 *p++ = 7; // bLength
136 *p++ = 0x05; // ENDPOINT descriptor
137 *p++ = p_config->ep_in; // bEndpointAddress
138 *p++ = 0x05; // bmAttributes (Isochronous, Async)
139 *p++ = packetSize & 0xFF; // wMaxPacketSize LSB
140 *p++ = (packetSize >> 8) & 0xFF; // wMaxPacketSize MSB
141 *p++ = 0x01; // bInterval
142 return p;
143 }
144
145 uint8_t* addCsIsoEndpointDesc(uint8_t* p) {
146 *p++ = 8; // bLength
147 *p++ = 0x25; // CS_ENDPOINT
148 *p++ = 0x01; // EP_GENERAL subtype
149 *p++ = 0x00; // bmAttributes
150 *p++ = 0x00; // bmControls
151 *p++ = 0x00;
152 *p++ = 0x00; // wLockDelayUnits, wLockDelay
153 return p;
154 }
155
156 USBAudioConfig *p_config = nullptr;
157
158};
159
160} // namespace tinyusb
Definition USBAudio2DescriptorBuilder.h:12
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Definition USBAudioConfig.h:6