summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/host/audio_host/README.md4
-rw-r--r--examples/host/audio_host/src/audio_app.c33
2 files changed, 24 insertions, 13 deletions
diff --git a/examples/host/audio_host/README.md b/examples/host/audio_host/README.md
index 706752a05..3d4307b42 100644
--- a/examples/host/audio_host/README.md
+++ b/examples/host/audio_host/README.md
@@ -73,7 +73,7 @@ make BOARD=<your_board> flash
- Echo captured audio to an S16_LE playback configuration at the same sample rate (same channel count preferred, converted otherwise)
- Read/unmute the microphone and speaker Feature Units and set supported master volumes near -6 dB
- Service both FIFOs from `audio_app_task()` at their half-full/half-drained watermarks; 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
+ - Cycle through the three phases (mic-only / spk-only / echo, 5 s each) with `tuh_audio_start()` / `tuh_audio_stop()`; their asynchronous results are printed from `tuh_audio_event_cb()`, and a failed stream is restarted automatically after 100 ms
## Serial Output Example
@@ -116,7 +116,7 @@ Edit `src/tusb_config.h` to modify:
## Notes
- `tuh_audio_descriptor_cb()` exposes the validated Audio Control descriptor block during enumeration. Applications that need raw entity controls must copy the required entity IDs or descriptor fields before the callback returns, then use `tuh_audio_control_xfer()` after the device mounts.
-- While a stream is running, the driver keeps one isochronous transfer in flight and re-submits on completion, so transfers follow the endpoint's `bInterval`. `tuh_audio_capture_cb()` / `tuh_audio_playback_cb()` only count completed transfers; `audio_app_task()` services the FIFOs independently from the main loop. `tuh_audio_err_cb()` reports failures, and the example restarts the failed stream automatically 100 ms later.
+- While a stream is running, the driver keeps one isochronous transfer in flight and re-submits on completion, so transfers follow the endpoint's `bInterval`. `tuh_audio_capture_cb()` / `tuh_audio_playback_cb()` only count completed transfers; `audio_app_task()` services the FIFOs independently from the main loop. `tuh_audio_event_cb()` reports asynchronous start/stop results and unrecoverable transfer failures. The example restarts a failed stream automatically 100 ms later.
- Capture and playback streams running concurrently in the same Audio Control instance must use the same sample rate.
- `tuh_audio_read()` / `tuh_audio_write()` are non-blocking FIFO operations: they return the number of whole frames actually read/queued. `tuh_audio_read_available()` reports captured frames ready to read; `tuh_audio_write_available()` reports free playback capacity. `tuh_audio_write()` only queues data; the playback transfer-completion chain sends it, or sends silence when the FIFO does not contain a complete polling interval without consuming the partial data.
- Isochronous transfers require the host to poll `tuh_task()` continuously; the capture FIFO absorbs short scheduling gaps and overwrites the oldest frames when full.
diff --git a/examples/host/audio_host/src/audio_app.c b/examples/host/audio_host/src/audio_app.c
index d3cc79c41..55efe3295 100644
--- a/examples/host/audio_host/src/audio_app.c
+++ b/examples/host/audio_host/src/audio_app.c
@@ -41,7 +41,7 @@ static tuh_audio_stream_config_t mic_config; // se
static tuh_audio_stream_config_t spk_config; // selected playback configuration
static uint32_t spk_cb_count = 0; // playback callbacks (for debug)
static uint32_t mic_cb_count = 0; // capture callbacks (for debug)
-static uint32_t err_cb_count = 0; // error callbacks (for debug)
+static uint32_t fail_event_count = 0; // transfer/start failures (for debug)
//--------------------------------------------------------------------+
@@ -238,11 +238,11 @@ void led_blinking_task(void) {
board_led_write(led_state);
led_state = 1 - led_state; // toggle
#if 1
- printf(" MIC CB=%lu SPK CB=%lu ERR CB=%lu\r\n", (unsigned long)mic_cb_count, (unsigned long)spk_cb_count,
- (unsigned long)err_cb_count);
+ printf(" MIC CB=%lu SPK CB=%lu FAIL EVENT=%lu\r\n", (unsigned long)mic_cb_count, (unsigned long)spk_cb_count,
+ (unsigned long)fail_event_count);
mic_cb_count = 0;
spk_cb_count = 0;
- err_cb_count = 0;
+ fail_event_count = 0;
#endif
}
@@ -325,18 +325,29 @@ static void audio_app_restart_stream(uintptr_t param) {
}
}
-// Invoked when stream activation or an isochronous transfer fails: the stream
-// was stopped by the driver, re-open it after a short delay so the device can
-// recover.
-void tuh_audio_err_cb(uint8_t idx, uint8_t stream_idx, uint16_t xferred_bytes) {
- (void)xferred_bytes;
- err_cb_count++;
+void tuh_audio_event_cb(uint8_t idx, uint8_t stream_idx, tuh_audio_event_t event, tusb_xfer_result_t result) {
+ const char *stream_name = (stream_idx == cap_stream_idx) ? "capture" : "playback";
+
+ if (event == TUH_AUDIO_EVENT_START_COMPLETE) {
+ printf(" %s start %s: result=%u\r\n", stream_name, result == XFER_RESULT_SUCCESS ? "complete" : "failed",
+ result);
+ if (result == XFER_RESULT_SUCCESS) {
+ return;
+ }
+ } else if (event == TUH_AUDIO_EVENT_STOP_COMPLETE) {
+ printf(" %s stop %s: result=%u\r\n", stream_name, result == XFER_RESULT_SUCCESS ? "complete" : "failed",
+ result);
+ return;
+ } else {
+ printf(" %s transfer failed: result=%u\r\n", stream_name, result);
+ }
+
+ fail_event_count++;
if (stream_idx == cap_stream_idx) {
mic_ready = false;
} else if (stream_idx == spk_stream_idx) {
spk_ready = false;
}
- printf(" AUDIO stream error: idx=%u stream=%u xferred_bytes=%u\r\n", idx, stream_idx, (unsigned)xferred_bytes);
app_defer_ms_async(100, (app_defer_func_t)audio_app_restart_stream, ((uintptr_t)idx << 8) | stream_idx);
}