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