1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
|
/*
* SPDX-FileCopyrightText: Copyright (c) 2026 Zhenjiang Zhang
* SPDX-FileCopyrightText: Copyright (c) 2026 HiFiPhile (Zixun LI)
* SPDX-License-Identifier: MIT
*
* This file is part of the TinyUSB stack.
*/
#ifndef TUSB_AUDIO_HOST_H_
#define TUSB_AUDIO_HOST_H_
#include "audio.h"
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------+
// Class Driver Configuration
//--------------------------------------------------------------------+
// Audio Class protocol versions compiled into the host driver. Multiple
// versions can be enabled so UAC1 and UAC2 devices can be mounted together.
#define TUH_AUDIO_PROTOCOL_UAC1 TU_BIT(0)
#define TUH_AUDIO_PROTOCOL_UAC2 TU_BIT(1)
#ifndef CFG_TUH_AUDIO_PROTOCOLS
#define CFG_TUH_AUDIO_PROTOCOLS TUH_AUDIO_PROTOCOL_UAC1
#endif
#if !(CFG_TUH_AUDIO_PROTOCOLS & (TUH_AUDIO_PROTOCOL_UAC1 | TUH_AUDIO_PROTOCOL_UAC2))
#error CFG_TUH_AUDIO_PROTOCOLS must enable UAC1 and/or UAC2
#endif
#if CFG_TUH_AUDIO_PROTOCOLS & ~(TUH_AUDIO_PROTOCOL_UAC1 | TUH_AUDIO_PROTOCOL_UAC2)
#error CFG_TUH_AUDIO_PROTOCOLS contains an unsupported protocol bit
#endif
// Maximum number of Audio devices
#ifndef CFG_TUH_AUDIO_MAX
#define CFG_TUH_AUDIO_MAX 1
#endif
// Maximum number of discrete sampling frequencies per Audio Streaming interface
#ifndef CFG_TUH_AUDIO_MAX_SAM_FREQ
#define CFG_TUH_AUDIO_MAX_SAM_FREQ 5
#endif
// Maximum number of Audio Streaming interfaces per Audio device
#ifndef CFG_TUH_AUDIO_MAX_AS
#define CFG_TUH_AUDIO_MAX_AS 4
#endif
// Maximum size of one capture (IN) isochronous transfer the driver submits.
// Configurations needing a larger per-poll-interval packet are rejected.
// 256 covers 2-ch 48 kHz S16_LE (192 B) and common endpoint padding (208 B).
#ifndef CFG_TUH_AUDIO_EPIN_BUFSIZE
#define CFG_TUH_AUDIO_EPIN_BUFSIZE 256
#endif
// Maximum size of one playback (OUT) isochronous transfer the driver submits.
// Configurations needing a larger per-poll-interval packet are rejected.
#ifndef CFG_TUH_AUDIO_EPOUT_BUFSIZE
#define CFG_TUH_AUDIO_EPOUT_BUFSIZE 256
#endif
// Depth in bytes of the per-stream data FIFO. The FIFO decouples the
// application's read/write calls from the endpoint's isochronous polling cadence
// and absorbs rate differences. Capture overwrites the oldest frames when full.
// 1024 bytes hold 4 default (256 B) packets.
#ifndef CFG_TUH_AUDIO_STREAM_BUFSIZE
#define CFG_TUH_AUDIO_STREAM_BUFSIZE 1024
#endif
//--------------------------------------------------------------------+
// Types
//--------------------------------------------------------------------+
// Fixed transfer direction of a logical stream.
typedef enum {
TUH_AUDIO_STREAM_PLAYBACK = 0, // Host -> Device (OUT)
TUH_AUDIO_STREAM_CAPTURE = 1, // Device -> Host (IN)
TUH_AUDIO_STREAM_DIRECTION_COUNT
} tuh_audio_direction_t;
// Discrete Type-I PCM sample format. UAC1 requires bSamFreqType > 0; UAC2
// configurations are built from the directly connected Clock Source RANGE.
typedef enum {
TUH_AUDIO_FORMAT_S8 = 0, // signed 8-bit
TUH_AUDIO_FORMAT_S16_LE, // signed 16-bit little-endian
TUH_AUDIO_FORMAT_S24_3LE, // signed 24-bit packed in 3 bytes, LE
TUH_AUDIO_FORMAT_S24_LE, // signed 24-bit in 32-bit container, LE
TUH_AUDIO_FORMAT_S32_LE, // signed 32-bit little-endian
TUH_AUDIO_FORMAT_COUNT
} tuh_audio_format_t;
// One complete supported discrete configuration tuple.
// Each entry is a full (format, sample_rate, channels) combination,
// avoiding invalid mixes between independent format/rate/channel lists.
// dir is constant for all configs of a given (dev_idx, stream_idx) and
// equals the result of tuh_audio_stream_direction().
typedef struct {
uint32_t sample_rate;
tuh_audio_direction_t dir;
tuh_audio_format_t format;
uint8_t channels;
} tuh_audio_stream_config_t;
// Volume values are signed 1/256 dB. INT16_MIN represents silence.
#define TUH_AUDIO_VOLUME_SILENCE INT16_MIN
// One continuous volume range. This matches UAC1 MIN/MAX/RES and the common
// UAC2 RANGE response containing one subrange.
typedef struct {
int16_t min;
int16_t max;
uint16_t res;
} tuh_audio_volume_range_t;
//--------------------------------------------------------------------+
// Stream Enumeration
//--------------------------------------------------------------------+
// Number of logical audio streams exposed by one mounted device. The
// application iterates stream indices [0, tuh_audio_stream_count()) and
// inspects each with tuh_audio_stream_exists()/tuh_audio_stream_direction().
uint8_t tuh_audio_stream_count(uint8_t dev_idx);
// True if (dev_idx, stream_idx) identifies an existing stream.
bool tuh_audio_stream_exists(uint8_t dev_idx, uint8_t stream_idx);
// Fixed transfer direction of the stream.
tuh_audio_direction_t tuh_audio_stream_direction(uint8_t dev_idx, uint8_t stream_idx);
//--------------------------------------------------------------------+
// Configuration Enumeration
//--------------------------------------------------------------------+
// Number of supported discrete configurations of the stream.
uint8_t tuh_audio_config_count(uint8_t dev_idx, uint8_t stream_idx);
// Active configuration index of the stream, or TUSB_INDEX_INVALID_8 if none.
uint8_t tuh_audio_active_config(uint8_t dev_idx, uint8_t stream_idx);
// Retrieve one discrete configuration tuple into *config.
bool tuh_audio_config_get(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx, tuh_audio_stream_config_t *config);
//--------------------------------------------------------------------+
// Configuration (ALSA hw_params analogue)
//--------------------------------------------------------------------+
// Synchronously configure the stream with the discrete configuration identified by
// config_idx. The driver:
// 1. resolves the AS interface and alternate setting,
// 2. initializes the FIFO and packet scheduler,
// 3. opens / reconfigures only the selected endpoint.
bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx);
//--------------------------------------------------------------------+
// Stream Control / Frame-based Data
//--------------------------------------------------------------------+
// Start transferring data with the configuration selected by configure().
// UAC1 activates the alternate setting before setting an endpoint frequency;
// UAC2 sets a writable Clock Source before activating the alternate setting.
bool tuh_audio_start(uint8_t dev_idx, uint8_t stream_idx);
// Stop transferring and deactivate the Audio Streaming interface (alt 0).
bool tuh_audio_stop(uint8_t dev_idx, uint8_t stream_idx);
// Frame-based transfer. One frame = channels * bytes per sample.
// tuh_audio_write() is valid only for TUH_AUDIO_STREAM_PLAYBACK streams,
// tuh_audio_read() only for TUH_AUDIO_STREAM_CAPTURE streams.
// Returns the number of frames actually written/read (0 on any error,
// including wrong direction, unconfigured/stopped stream, or full/empty FIFO).
uint32_t tuh_audio_write(uint8_t dev_idx, uint8_t stream_idx, const void *buffer, uint32_t frame_count);
uint32_t tuh_audio_read(uint8_t dev_idx, uint8_t stream_idx, void *buffer, uint32_t frame_count);
// FIFO occupancy in frames available for a non-blocking write/read.
uint32_t tuh_audio_write_available(uint8_t dev_idx, uint8_t stream_idx);
uint32_t tuh_audio_read_available(uint8_t dev_idx, uint8_t stream_idx);
//--------------------------------------------------------------------+
// Helpers
//--------------------------------------------------------------------+
// Container size in bytes of one sample for a given format.
static inline uint8_t tuh_audio_format_bytes(tuh_audio_format_t format) {
switch (format) {
case TUH_AUDIO_FORMAT_S8:
return 1;
case TUH_AUDIO_FORMAT_S16_LE:
return 2;
case TUH_AUDIO_FORMAT_S24_3LE:
return 3;
case TUH_AUDIO_FORMAT_S24_LE:
case TUH_AUDIO_FORMAT_S32_LE:
return 4;
default:
return 0;
}
}
// Size in bytes of one frame (all channels) for a configuration.
static inline uint32_t tuh_audio_config_frame_size(const tuh_audio_stream_config_t *config) {
TU_ASSERT(config != NULL);
return (uint32_t)tuh_audio_format_bytes(config->format) * config->channels;
}
//--------------------------------------------------------------------+
// Device Info
//--------------------------------------------------------------------+
// Check if Audio device is mounted
bool tuh_audio_mounted(uint8_t idx);
// Get device address of Audio device
uint8_t tuh_audio_get_dev_addr(uint8_t idx);
// Get the Feature Unit ID associated with a stream (0 = none)
uint8_t tuh_audio_get_feature_unit_id(uint8_t idx, uint8_t stream_idx);
// True when the stream's Feature Unit supports master mute control.
bool tuh_audio_mute_supported(uint8_t idx, uint8_t stream_idx);
// Get the cached master volume range. Returns false when volume is unsupported.
bool tuh_audio_volume_range_get(uint8_t idx, uint8_t stream_idx, tuh_audio_volume_range_t *range);
//--------------------------------------------------------------------+
// Control Request API
//--------------------------------------------------------------------+
// Set a Feature Unit control associated with an Audio stream. UAC2 supports
// mute and volume through this low-level API; the other fixed-width selectors
// below are UAC1-only.
// Mute/bass/mid/treble/AGC/bass boost/loudness use one byte; volume/delay use two.
// Graphic EQ and unknown selectors are unsupported.
bool tuh_audio_feature_unit_set(uint8_t idx, uint8_t stream_idx, uint8_t control_selector, uint8_t channel,
uint16_t value, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Get a Feature Unit control associated with an Audio stream. UAC2 supports
// mute and volume through this low-level API; the other fixed-width selectors
// below are UAC1-only.
// The value is converted to host byte order before complete_cb is invoked.
// Graphic EQ and unknown selectors are unsupported.
// Only one Feature Unit operation may be in flight per device.
bool tuh_audio_feature_unit_get(uint8_t idx, uint8_t stream_idx, uint8_t control_selector, uint8_t channel,
uint16_t *value, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
// Master mute and volume controls. Capability and range information is cached
// before tuh_audio_mount_cb() is invoked. Volume SET accepts
// TUH_AUDIO_VOLUME_SILENCE or a value within the cached range; finite values
// are rounded to the nearest resolution step measured from the range minimum.
bool tuh_audio_mute_set(uint8_t idx, uint8_t stream_idx, bool mute, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
bool tuh_audio_mute_get(uint8_t idx, uint8_t stream_idx, bool *mute, tuh_xfer_cb_t complete_cb, uintptr_t user_data);
bool tuh_audio_volume_set(uint8_t idx, uint8_t stream_idx, int16_t volume, tuh_xfer_cb_t complete_cb,
uintptr_t user_data);
bool tuh_audio_volume_get(uint8_t idx, uint8_t stream_idx, int16_t *volume, tuh_xfer_cb_t complete_cb,
uintptr_t user_data);
//--------------------------------------------------------------------+
// Control Request Sync API
// Each Function will make a USB control transfer request to/from device the function will block until request is
// complete. The function will return the transfer request result
//--------------------------------------------------------------------+
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_feature_unit_set_sync(uint8_t idx, uint8_t stream_idx,
uint8_t control_selector,
uint8_t channel,
uint16_t value) {
TU_API_SYNC(tuh_audio_feature_unit_set, idx, stream_idx, control_selector, channel, value);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_feature_unit_get_sync(uint8_t idx, uint8_t stream_idx,
uint8_t control_selector,
uint8_t channel,
uint16_t *value) {
TU_API_SYNC(tuh_audio_feature_unit_get, idx, stream_idx, control_selector, channel, value);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_mute_set_sync(uint8_t idx, uint8_t stream_idx,
bool mute) {
TU_API_SYNC(tuh_audio_mute_set, idx, stream_idx, mute);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_mute_get_sync(uint8_t idx, uint8_t stream_idx,
bool *mute) {
TU_API_SYNC(tuh_audio_mute_get, idx, stream_idx, mute);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_volume_set_sync(uint8_t idx, uint8_t stream_idx,
int16_t volume) {
TU_API_SYNC(tuh_audio_volume_set, idx, stream_idx, volume);
}
TU_ATTR_ALWAYS_INLINE static inline tusb_xfer_result_t tuh_audio_volume_get_sync(uint8_t idx, uint8_t stream_idx,
int16_t *volume) {
TU_API_SYNC(tuh_audio_volume_get, idx, stream_idx, volume);
}
//--------------------------------------------------------------------+
// Callbacks (Weak is optional)
//--------------------------------------------------------------------+
// Invoked when device with Audio interface is mounted
void tuh_audio_mount_cb(uint8_t idx);
// Invoked when device with Audio interface is un-mounted
void tuh_audio_umount_cb(uint8_t idx);
// Invoked when an isochronous IN transfer completes successfully: the
// received data is already queued into the stream's capture FIFO.
void tuh_audio_capture_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes);
// Invoked when an isochronous OUT transfer completes successfully: the
// next playback packet is submitted from the stream FIFO, or as silence when
// a complete packet is not queued.
void tuh_audio_playback_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes);
// Invoked when asynchronous stream activation or an isochronous transfer
// fails. The stream is stopped (tuh_audio_start() must be called again to
// resume). xferred_bytes is zero for an activation failure.
void tuh_audio_err_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes);
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
bool audioh_init(void);
bool audioh_deinit(void);
uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface_t *desc_itf, uint16_t max_len);
bool audioh_set_config(uint8_t dev_addr, uint8_t itf_num);
bool audioh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void audioh_close(uint8_t daddr);
#ifdef __cplusplus
}
#endif
#endif /* TUSB_AUDIO_HOST_H_ */
|