summaryrefslogtreecommitdiff
path: root/examples/host/audio_host
diff options
context:
space:
mode:
Diffstat (limited to 'examples/host/audio_host')
-rw-r--r--examples/host/audio_host/README.md14
-rw-r--r--examples/host/audio_host/src/audio_app.c44
2 files changed, 37 insertions, 21 deletions
diff --git a/examples/host/audio_host/README.md b/examples/host/audio_host/README.md
index bef78c7d3..88c948ccd 100644
--- a/examples/host/audio_host/README.md
+++ b/examples/host/audio_host/README.md
@@ -6,6 +6,7 @@ This example demonstrates how to use TinyUSB's USB Audio Host driver (TUH_AUDIO)
- Enumerates and mounts USB Audio Class 1.0 devices
- Discovers the device's logical streams (capture/playback) and their supported configurations (discrete tuples only)
+- Reports the Feature Unit ID associated with each stream and sets the master volume when one is available
- Configures and starts an S16_LE capture stream (48 kHz preferred, 44.1 kHz fallback; stereo preferred, mono accepted)
- Echoes captured audio to an S16_LE playback stream at the same sample rate (same channel count preferred, mono/stereo conversion otherwise)
- Frame-based FIFO API: `tuh_audio_read()` / `tuh_audio_write()` queue frames; the driver schedules transfers at the endpoint's polling interval
@@ -64,9 +65,10 @@ make BOARD=<your_board> flash
2. Connect a USB Audio device (UAC 1.0) to the USB host port
3. Open a serial terminal to view output
4. The example will:
- - Print each stream's supported configurations when mounted
+ - Print each stream's Feature Unit ID and supported configurations when mounted
- Look for an S16_LE capture configuration at a preferred sample rate (48 kHz first, 44.1 kHz fallback; stereo preferred, mono accepted) and configure it
- Echo captured audio to an S16_LE playback configuration at the same sample rate (same channel count preferred, converted otherwise)
+ - Set the microphone and speaker master volume to `0x0600` when their streams have a Feature Unit
- Drain the capture FIFO in `audio_app_task_read()` and queue the frames into the playback FIFO; a sine test tone plays on the playback stream when no capture stream is echoing
- Cycle through the three phases (mic-only / spk-only / echo, 5 s each) with `tuh_audio_start()` / `tuh_audio_stop()`; a failed stream is restarted automatically 100 ms after the error callback
@@ -76,16 +78,18 @@ make BOARD=<your_board> flash
TinyUSB Host USB Audio Example
Connect a USB Audio Device (UAC 1.0) to test
Audio device mounted: idx=0 addr=1
- capture stream 1 configurations: 2
+ capture stream 1 Feature Unit ID: 5, configurations: 2
[0] format=1 rate=44100 channels=2
[1] format=1 rate=48000 channels=2
- playback stream 0 configurations: 2
+ playback stream 0 Feature Unit ID: 2, configurations: 2
[0] format=1 rate=44100 channels=2
[1] format=1 rate=48000 channels=2
Configuring 48 kHz S16_LE capture (2 channels)
- Microphone configured, starting capture
+ Microphone configured
+ Microphone Feature Unit 5 master volume set: 0x0600
Configuring 48 kHz S16_LE playback (2 channels)
- Speaker configured, starting playback
+ Speaker configured
+ Speaker Feature Unit 2 master volume set: 0x0600
```
## Configuration
diff --git a/examples/host/audio_host/src/audio_app.c b/examples/host/audio_host/src/audio_app.c
index 0110bdde8..3a782e146 100644
--- a/examples/host/audio_host/src/audio_app.c
+++ b/examples/host/audio_host/src/audio_app.c
@@ -31,6 +31,8 @@
#define AUDIO_MAX_FRAME_COUNT 48
#define AUDIO_MAX_CHANNELS 2
#define SAMPLE_RATES {48000, 44100}
+// UAC1 volume values are signed 1/256 dB; 0x0600 selects +6 dB.
+#define FEATURE_UNIT_VOLUME 0x0600
static uint8_t audio_idx = TUSB_INDEX_INVALID_8; // index of the selected audio device
static uint8_t cap_stream_idx = TUSB_INDEX_INVALID_8; // capture stream index
static uint8_t spk_stream_idx = TUSB_INDEX_INVALID_8; // playback stream index
@@ -347,9 +349,11 @@ void tuh_audio_err_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes) {
// Print all supported stream configurations
static void print_stream_configs(uint8_t idx, uint8_t stream_idx) {
- const tuh_audio_direction_t dir = tuh_audio_stream_direction(idx, stream_idx);
- const char *dir_name = (dir == TUH_AUDIO_STREAM_CAPTURE) ? "capture" : "playback";
- printf(" %s stream %u configurations: %u\r\n", dir_name, stream_idx, tuh_audio_config_count(idx, stream_idx));
+ const tuh_audio_direction_t dir = tuh_audio_stream_direction(idx, stream_idx);
+ const char *dir_name = (dir == TUH_AUDIO_STREAM_CAPTURE) ? "capture" : "playback";
+ const uint8_t feature_unit_id = tuh_audio_get_feature_unit_id(idx, stream_idx);
+ printf(" %s stream %u Feature Unit ID: %u, configurations: %u\r\n", dir_name, stream_idx, feature_unit_id,
+ tuh_audio_config_count(idx, stream_idx));
for (uint8_t i = 0; i < tuh_audio_config_count(idx, stream_idx); i++) {
tuh_audio_stream_config_t config;
if (tuh_audio_config_get(idx, stream_idx, i, &config)) {
@@ -359,23 +363,30 @@ static void print_stream_configs(uint8_t idx, uint8_t stream_idx) {
}
}
+static void set_stream_volume(uint8_t idx, uint8_t stream_idx, const char *stream_name) {
+ const uint8_t feature_unit_id = tuh_audio_get_feature_unit_id(idx, stream_idx);
+ if (feature_unit_id == 0) {
+ printf(" %s stream has no Feature Unit\r\n", stream_name);
+ return;
+ }
+
+ uint16_t volume = FEATURE_UNIT_VOLUME;
+ tusb_xfer_result_t result = tuh_audio_feature_unit_set_sync(idx, stream_idx, AUDIO10_FU_CTRL_VOLUME, 0, volume);
+ if (result == XFER_RESULT_SUCCESS) {
+ printf(" %s Feature Unit %u master volume set: 0x%04x\r\n", stream_name, feature_unit_id, (unsigned int)volume);
+ } else {
+ printf(" Setting %s Feature Unit %u volume failed: result=%u\r\n", stream_name, feature_unit_id, result);
+ }
+}
+
// Invoked when the configuration selected by tuh_audio_configure() completes
static void mic_configured(uint8_t idx, uint8_t stream_idx, tusb_xfer_result_t result, uintptr_t user_data) {
(void)user_data;
if (idx == audio_idx && stream_idx == cap_stream_idx && result == XFER_RESULT_SUCCESS) {
- printf(" Microphone configured, starting capture\r\n");
+ printf(" Microphone configured\r\n");
+ set_stream_volume(idx, stream_idx, "Microphone");
mic_ready = tuh_audio_start(idx, stream_idx);
-
- uint16_t volume = 0x0600;
- result = tuh_audio_feature_unit_set_sync(idx, stream_idx, AUDIO10_FU_CTRL_VOLUME, 0, volume);
- if (result == XFER_RESULT_SUCCESS) {
- printf(" Feature Unit volume set:volume 0x%04x\r\n", (unsigned int)volume);
- tuh_audio_feature_unit_get_sync(idx, stream_idx, AUDIO10_FU_CTRL_VOLUME, 0, &volume);
- printf(" Feature Unit volume get: 0x%04x\r\n", (unsigned int)volume);
- } else {
- printf(" Setting Feature Unit volume FAILED: result=%u\r\n", result);
- }
} else {
printf(" Microphone configuration failed: result=%u\r\n", result);
}
@@ -385,11 +396,12 @@ static void mic_configured(uint8_t idx, uint8_t stream_idx, tusb_xfer_result_t r
static void spk_configured(uint8_t idx, uint8_t stream_idx, tusb_xfer_result_t result, uintptr_t user_data) {
(void)user_data;
if (idx == audio_idx && stream_idx == spk_stream_idx && result == XFER_RESULT_SUCCESS) {
- printf(" Speaker configured, starting playback\r\n");
- spk_ready = tuh_audio_start(idx, stream_idx);
+ printf(" Speaker configured\r\n");
// playback-only device: set the frame cadence from the selected rate
audio_frame_count = spk_config.sample_rate / 1000;
spk_init_sine(); // fallback test tone while no capture stream is echoing
+ set_stream_volume(idx, stream_idx, "Speaker");
+ spk_ready = tuh_audio_start(idx, stream_idx);
// both streams running: start the periodic phase switching demo
if (mic_ready && spk_ready) {