21 AUDIO_FU_CTRL_UNDEF = 0x00,
22 AUDIO_FU_CTRL_MUTE = 0x01,
23 AUDIO_FU_CTRL_VOLUME = 0x02,
24 AUDIO_FU_CTRL_BASS = 0x03,
25 AUDIO_FU_CTRL_MID = 0x04,
26 AUDIO_FU_CTRL_TREBLE = 0x05,
27 AUDIO_FU_CTRL_GRAPHIC_EQUALIZER = 0x06,
28 AUDIO_FU_CTRL_AGC = 0x07,
29 AUDIO_FU_CTRL_DELAY = 0x08,
30 AUDIO_FU_CTRL_BASS_BOOST = 0x09,
31 AUDIO_FU_CTRL_LOUDNESS = 0x0A,
32 AUDIO_FU_CTRL_INPUT_GAIN = 0x0B,
33 AUDIO_FU_CTRL_GAIN_PAD = 0x0C,
34 AUDIO_FU_CTRL_INVERTER = 0x0D,
35 AUDIO_FU_CTRL_UNDERFLOW = 0x0E,
36 AUDIO_FU_CTRL_OVERVLOW = 0x0F,
37 AUDIO_FU_CTRL_LATENCY = 0x10,
40 enum audio_feedback_method_t {
41 AUDIO_FEEDBACK_METHOD_DISABLED,
42 AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED,
43 AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT,
44 AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2,
45 AUDIO_FEEDBACK_METHOD_FIFO_COUNT
49 std::function<void(AudioDevice&,
const uint8_t* data,
size_t len)>;
51 std::function<void(AudioDevice&, uint8_t* buffer,
size_t& len)>;
52 using VolumeGetCallback = std::function<int16_t(AudioDevice&)>;
53 using VolumeSetCallback = std::function<void(AudioDevice&, int16_t)>;
54 using MuteGetCallback = std::function<bool(AudioDevice&)>;
55 using MuteSetCallback = std::function<void(AudioDevice&,
bool)>;
57 static AudioDevice& instance() {
58 static AudioDevice inst;
62 void setOutput(Print& out) { volumeStream_.setOutput(out); }
64 void setInput(Stream& io) {
65 volumeStream_.setOutput(io);
66 volumeStream_.setStream(io);
69 bool begin(AudioInfo info) {
75 if (muteGetCallback_ ==
nullptr)
76 setMuteGetCallback([](AudioDevice<ItfNum, EPOut, EPIn>& dev) ->
bool {
77 return dev.current_mute;
80 if (muteSetCallback_ ==
nullptr)
81 setMuteSetCallback([](AudioDevice<ItfNum, EPOut, EPIn>& dev,
bool m) {
84 dev.volume_before_mute =
86 dev.current_volume = 0;
89 dev.volume_before_mute;
91 dev.volumeStream_.setVolume(dev.toFloatVolume(dev.current_volume));
94 if (volumeGetCallback_ ==
nullptr)
96 [](AudioDevice<ItfNum, EPOut, EPIn>& dev) -> int16_t {
97 return dev.current_volume;
100 if (volumeSetCallback_ ==
nullptr)
101 setVolumeSetCallback(
102 [](AudioDevice<ItfNum, EPOut, EPIn>& dev, int16_t v) {
103 dev.current_volume = v;
104 dev.volumeStream_.setVolume(dev.toFloatVolume(dev.current_volume));
107 if (rxCallback_ ==
nullptr) {
108 setRxCallback([](AudioDevice<ItfNum, EPOut, EPIn>& dev,
110 size_t len) { dev.volumeStream_.write(data, len); });
113 if (txCallback_ ==
nullptr) {
114 setTxCallback([](AudioDevice<ItfNum, EPOut, EPIn>& dev, uint8_t* data,
115 size_t len) { dev.volumeStream_.readBytes(data, len); });
118 return volumeStream_.begin();
121 void setRxCallback(RxCallback cb) { rxCallback_ = cb; }
122 void setTxCallback(TxCallback cb) { txCallback_ = cb; }
124 void setAudioInfo(AudioInfo info) {
125 descriptor_.setSampleRate(info.sample_rate);
126 descriptor_.setNumChannels(info.channels);
127 descriptor_.setBitsPerSample(info.bits_per_sample);
136 static bool tudAudioTxDoneCb(uint8_t itf, uint8_t ep) {
137 if (itf != ItfNum || ep != EPIn)
return false;
138 auto& inst = instance();
139 if (inst.txCallback_) {
140 uint16_t packetSize = inst.descriptor_.calcMaxPacketSize();
141 uint8_t buffer[packetSize];
142 size_t len = packetSize;
143 inst.txCallback_(buffer, len);
144 endpointWrite(itf, ep, buffer, len);
149 static bool tudAudioRxDoneCb(uint8_t itf, uint8_t ep) {
150 if (itf != ItfNum || ep != EPOut)
return false;
151 auto& inst = instance();
152 if (inst.rxCallback_) {
154 int32_t rlen = endpointRead(itf, ep, buffer,
sizeof(buffer));
155 if (rlen > 0) inst.rxCallback_(buffer, rlen);
160 static bool tudAudioSetReqCb(uint8_t rhport,
161 tusb_control_request_t
const* req,
163 return instance().handleAudioClassRequest(req, buffer,
true);
166 static bool tudAudioGetReqCb(uint8_t rhport,
167 tusb_control_request_t
const* req,
169 return instance().handleAudioClassRequest(req, buffer,
false);
172 static const uint8_t* tudAudioDescriptorCb(uint8_t itf, uint8_t alt,
174 return instance().descriptor_.buildDescriptor(itf, alt, len);
178 float volume()
const {
return toFloatVolume(current_volume); }
182 RxCallback rxCallback_ =
nullptr;
183 TxCallback txCallback_ =
nullptr;
184 VolumeGetCallback volumeGetCallback_ =
nullptr;
185 VolumeSetCallback volumeSetCallback_ =
nullptr;
186 MuteGetCallback muteGetCallback_ =
nullptr;
187 MuteSetCallback muteSetCallback_ =
nullptr;
188 bool current_mute =
false;
189 int16_t current_volume = 0;
190 int16_t volume_before_mute = 0;
191 VolumeStream volumeStream_;
193 struct audiod_function_t {
194 audiod_function_t() { memset(
this, 0,
sizeof(audiod_function_t)); }
195 uint8_t n_bytes_per_sample_tx;
196 uint8_t n_channels_tx;
197 uint8_t format_type_tx = AUDIO_FORMAT_TYPE_I;
200 uint8_t
const* p_desc =
231 uint16_t desc_length;
234 CFG_TUSB_MEM_ALIGN uint32_t
243 uint8_t compute_method;
250 uint32_t sample_freq;
261 uint32_t sample_rate_tx;
262 uint16_t packet_sz_tx[3];
263 uint8_t bclock_id_tx;
274 uint8_t* alt_setting;
284 CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
289 uint8_t* lin_buf_out;
293 static std::vector<CFG_TUD_MEM_SECTION audiod_function_t> _audiod_fct;
296 float toFloatVolume(int16_t intVol)
const {
297 return (32768.0f + intVol) / 65536.0f;
300 static inline uint16_t endpointWrite(uint8_t itf, uint8_t ep,
301 const void* buffer, uint16_t size) {
306 static inline int32_t endpointRead(uint8_t itf, uint8_t ep,
void* buffer,
312 void setVolumeGetCallback(VolumeGetCallback cb) { volumeGetCallback_ = cb; }
314 void setVolumeSetCallback(VolumeSetCallback cb) { volumeSetCallback_ = cb; }
316 void setMuteGetCallback(MuteGetCallback cb) { muteGetCallback_ = cb; }
318 void setMuteSetCallback(MuteSetCallback cb) { muteSetCallback_ = cb; }
320 bool handleAudioClassRequest(tusb_control_request_t
const* req,
321 uint8_t* buffer,
bool isSet) {
322 const uint8_t cs = (req->wValue >> 8) & 0xFF;
323 const uint8_t entityId = (req->wIndex >> 8) & 0xFF;
324 if (entityId != 2)
return false;
325 switch (req->bRequest) {
326 case AUDIO_CS_REQ_CUR:
327 if (cs == AUDIO_FU_CTRL_MUTE) {
329 bool mute = buffer[0];
330 if (muteSetCallback_) muteSetCallback_(*
this, mute);
332 buffer[0] = muteGetCallback_ ? muteGetCallback_(*
this) : 0;
335 }
else if (cs == AUDIO_FU_CTRL_VOLUME) {
337 int16_t vol = buffer[0] | (buffer[1] << 8);
338 if (volumeSetCallback_) volumeSetCallback_(*
this, vol);
340 int16_t vol = volumeGetCallback_ ? volumeGetCallback_(*
this) : 0;
341 buffer[0] = vol & 0xFF;
342 buffer[1] = (vol >> 8) & 0xFF;
355 static uint16_t tud_audio_n_available(uint8_t func_id) {
356 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
357 return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
360 static uint16_t tud_audio_n_read(uint8_t func_id,
void* buffer,
362 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
363 return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
366 static bool tud_audio_n_clear_ep_out_ff(uint8_t func_id) {
367 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
368 return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
371 static tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id) {
372 if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL)
373 return &_audiod_fct[func_id].ep_out_ff;
379 static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio,
380 uint16_t n_bytes_received) {
382 uint8_t
const* dummy2;
383 uint8_t idx_audio_fct = 0;
385 idx_audio_fct = audiod_get_audio_fct_idx(audio);
386 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio,
391 TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received,
392 idx_audio_fct, audio->ep_out,
393 audio->alt_setting[idxItf]));
396 TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out,
400 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out,
404 if (audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT) {
405 audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff));
410 TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received,
411 idx_audio_fct, audio->ep_out,
412 audio->alt_setting[idxItf]));
430 static uint16_t tud_audio_n_write(uint8_t func_id,
const void* data,
432 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
433 return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
436 static bool tud_audio_n_clear_ep_in_ff(
439 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
440 return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
443 static tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id) {
444 if (func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL)
445 return &_audiod_fct[func_id].ep_in_ff;
454 static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio) {
456 uint8_t
const* dummy2;
458 uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
459 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio,
464 if (audio->alt_setting[idxItf] == 0)
return false;
471 TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in,
472 audio->alt_setting[idxItf]));
478 n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx,
479 tu_fifo_count(&audio->ep_in_ff),
480 audio->ep_in_ff.depth, audio->ep_in_sz);
481 tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
483 usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
487 TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct,
489 audio->alt_setting[idxItf]));