diff options
| author | HiFiPHile <[email protected]> | 2026-08-25 09:27:37 +0200 |
|---|---|---|
| committer | HiFiPHile <[email protected]> | 2026-08-25 09:27:37 +0200 |
| commit | e590b45fcf51f9ddace73178074e4fe6d691e319 (patch) | |
| tree | 7a5e14c24e21ac46d7b7bfe8be82ae181a8ec1b5 /examples | |
| parent | 61e3544b249dd1e40d9cbb106361541091b3ee78 (diff) | |
feat(audio): demonstrate speaker volume control
Look up the playback Feature Unit in the host example and set its master volume after configuration. The output also reports when a stream has no controllable Feature Unit.
Signed-off-by: HiFiPHile <[email protected]>
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/host/audio_host/README.md | 14 | ||||
| -rw-r--r-- | examples/host/audio_host/src/audio_app.c | 44 |
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) { |
