diff options
| author | HiFiPHile <[email protected]> | 2026-08-25 09:28:12 +0200 |
|---|---|---|
| committer | HiFiPHile <[email protected]> | 2026-08-25 09:28:12 +0200 |
| commit | aab34b8d0dafb360213fc40bd3ce33813fdf5cad (patch) | |
| tree | c02672a1a2f7bd4721ce62344251268b8dc5b99e | |
| parent | ddf4bad89017dab131eddf2fa27d835218e7f72e (diff) | |
refactor(audio): separate stream configuration and start
Make configuration a synchronous local operation that selects and opens the endpoint. Start now activates the alternate setting and sets the sampling frequency afterward, including every restart, so devices cannot reset the selected rate with SET_INTERFACE.
Signed-off-by: HiFiPHile <[email protected]>
| -rw-r--r-- | examples/host/audio_host/src/audio_app.c | 61 | ||||
| -rw-r--r-- | src/class/audio/audio_host.c | 164 | ||||
| -rw-r--r-- | src/class/audio/audio_host.h | 24 | ||||
| -rw-r--r-- | test/unit-test/test/host/audio/test_audio_host.c | 97 |
4 files changed, 151 insertions, 195 deletions
diff --git a/examples/host/audio_host/src/audio_app.c b/examples/host/audio_host/src/audio_app.c index 3a782e146..553e8f20e 100644 --- a/examples/host/audio_host/src/audio_app.c +++ b/examples/host/audio_host/src/audio_app.c @@ -379,38 +379,6 @@ static void set_stream_volume(uint8_t idx, uint8_t stream_idx, const char *strea } } -// 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\r\n"); - set_stream_volume(idx, stream_idx, "Microphone"); - mic_ready = tuh_audio_start(idx, stream_idx); - } else { - printf(" Microphone configuration failed: result=%u\r\n", result); - } -} - -// Invoked when the playback configuration selected by tuh_audio_configure() completes -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\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) { - app_audio_phase_enter(APP_PHASE_MIC_ONLY); - } - } else { - printf(" Speaker configuration failed: result=%u\r\n", result); - } -} // Invoked when device with Audio interface is un-mounted void tuh_audio_umount_cb(uint8_t idx) { printf("Audio device unmounted: idx=%u\r\n", idx); @@ -460,14 +428,19 @@ static void tuh_audio_mount_async(uintptr_t param) { // Check for a matching sample rate S16_LE configuration with the desired channel count if (tuh_audio_config_get(idx, stream_idx, i, &config) && config.format == TUH_AUDIO_FORMAT_S16_LE && config.sample_rate == sample_rate && config.channels == ch) { + printf(" Configuring %u S16_LE capture (%u channels)\r\n", (unsigned)sample_rate, config.channels); + if (!tuh_audio_configure(idx, stream_idx, i)) { + printf(" Microphone configuration failed\r\n"); + continue; + } audio_idx = idx; cap_stream_idx = stream_idx; mic_config = config; // one ms of audio at the selected rate, rounded down to whole frames audio_frame_count = sample_rate / 1000; - printf(" Configuring %u S16_LE capture (%u channels)\r\n", (unsigned)sample_rate, config.channels); - // Configure the selected capture stream and start it through the callback. - (void)tuh_audio_configure(idx, stream_idx, i, mic_configured, 0); + printf(" Microphone configured\r\n"); + set_stream_volume(idx, stream_idx, "Microphone"); + mic_ready = tuh_audio_start(idx, stream_idx); capture_found = true; break; } @@ -514,8 +487,22 @@ static void tuh_audio_mount_async(uintptr_t param) { return; } printf(" Configuring %u S16_LE playback (%u channels)\r\n", (unsigned)spk_config.sample_rate, spk_config.channels); - // Configure the selected playback stream and start it through the callback. - (void)tuh_audio_configure(idx, spk_stream_idx, playback_config_idx, spk_configured, 0); + if (!tuh_audio_configure(idx, spk_stream_idx, playback_config_idx)) { + printf(" Speaker configuration failed\r\n"); + return; + } + audio_idx = 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, spk_stream_idx, "Speaker"); + spk_ready = tuh_audio_start(idx, spk_stream_idx); + + // both streams running: start the periodic phase switching demo + if (mic_ready && spk_ready) { + app_audio_phase_enter(APP_PHASE_MIC_ONLY); + } } // Invoked when device with Audio interface is mounted diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c index b682d2d8a..9115ce4ca 100644 --- a/src/class/audio/audio_host.c +++ b/src/class/audio/audio_host.c @@ -38,8 +38,8 @@ * supported configurations during enumeration. * * The driver owns: - * 1. Endpoint selection and opening (only the alternate setting selected by - * tuh_audio_configure() is ever activated). + * 1. Endpoint selection and opening; only the alternate setting selected by + * tuh_audio_configure() is activated by tuh_audio_start(). * 2. Endpoint sampling-frequency control (SET_CUR, 3 bytes little-endian). */ @@ -100,8 +100,7 @@ TU_ATTR_WEAK void tuh_audio_err_cb(uint8_t idx, uint8_t stream_idx, uint16_t xfe // Stream state machine enum { - STREAM_STATE_IDLE = 0, // not configured, no configuration in progress - STREAM_STATE_CONFIG, // tuh_audio_configure() sequence in progress + STREAM_STATE_IDLE = 0, // not configured STREAM_STATE_READY // configured, ready to start/stop }; @@ -149,10 +148,6 @@ typedef struct { uint32_t frames_rem; uint32_t rem_acc; - // Configure state machine - tuh_audio_configure_cb_t complete_cb; - uintptr_t user_data; - // FIFO + endpoint transfer helper (see tu_edpt_stream, used by the MIDI // host driver): the FIFO decouples the application's frame-based read/write // from the endpoint's isochronous transfer cadence. ep_buf is bound at init from @@ -286,7 +281,6 @@ static void audioh_stream_reset(tuh_audio_stream_t *s) { s->frames_per_interval = 0; s->frames_rem = 0; s->rem_acc = 0; - s->complete_cb = NULL; tu_edpt_stream_close(&s->edpt); tu_edpt_stream_clear(&s->edpt); } @@ -374,47 +368,15 @@ static bool audioh_stream_close_ep(tuh_audio_stream_t *s) { return true; } -static void audioh_stream_fail(tuh_audio_stream_t *s, tusb_xfer_result_t result) { +static void audioh_stream_fail(tuh_audio_stream_t *s) { (void)audioh_stream_close_ep(s); s->state = STREAM_STATE_IDLE; s->active_config = TUSB_INDEX_INVALID_8; s->running = false; - - tuh_audio_configure_cb_t cb = s->complete_cb; - uintptr_t user_data = s->user_data; - s->complete_cb = NULL; - if (cb != NULL) { - cb(s->idx, s->stream_idx, result, user_data); - } -} - -static void audioh_stream_ready(tuh_audio_stream_t *s) { - s->state = STREAM_STATE_READY; - - tuh_audio_configure_cb_t cb = s->complete_cb; - uintptr_t user_data = s->user_data; - s->complete_cb = NULL; - if (cb != NULL) { - cb(s->idx, s->stream_idx, XFER_RESULT_SUCCESS, user_data); - } -} - -static void audioh_stream_set_freq_complete(tuh_xfer_t *xfer) { - tuh_audio_stream_t *s = (tuh_audio_stream_t *)xfer->user_data; - if (s->daddr != xfer->daddr || s->state != STREAM_STATE_CONFIG) { - return; // device is gone or configuration was aborted - } - - if (xfer->result != XFER_RESULT_SUCCESS) { - TU_LOG_DRV(" AUDIO set sampling frequency failed: result=%u\r\n", xfer->result); - audioh_stream_fail(s, xfer->result); - return; - } - audioh_stream_ready(s); } -// Set the endpoint sampling frequency (3 bytes little-endian) when supported -static void audioh_stream_set_freq(tuh_audio_stream_t *s) { +// Set the endpoint sampling frequency (3 bytes little-endian) +static bool audioh_stream_set_freq(tuh_audio_stream_t *s, tuh_xfer_cb_t complete_cb) { const audioh_stream_map_t *map = &s->map[s->active_config]; const tuh_audio_stream_config_t *cfg = &s->config[s->active_config]; uint8_t *ctrl = _audioh_epbuf[s->idx].sam_freq; @@ -434,15 +396,13 @@ static void audioh_stream_set_freq(tuh_audio_stream_t *s) { .ep_addr = 0, .setup = &request, .buffer = ctrl, - .complete_cb = audioh_stream_set_freq_complete, + .complete_cb = complete_cb, .user_data = (uintptr_t)s}; - if (!tuh_control_xfer(&xfer)) { - audioh_stream_fail(s, XFER_RESULT_FAILED); - } + return tuh_control_xfer(&xfer); } // Reconstruct the endpoint descriptor of the selected configuration and open it -static void audioh_stream_open_ep(tuh_audio_stream_t *s) { +static bool audioh_stream_open_ep(tuh_audio_stream_t *s) { const audioh_stream_map_t *map = &s->map[s->active_config]; const tusb_desc_endpoint_t desc_ep = {.bLength = sizeof(tusb_desc_endpoint_t), @@ -456,35 +416,16 @@ static void audioh_stream_open_ep(tuh_audio_stream_t *s) { if (!tuh_edpt_open(s->daddr, &desc_ep)) { TU_LOG_DRV(" AUDIO open endpoint failed: addr=%u ep=%02x\r\n", s->daddr, map->ep_addr); - audioh_stream_fail(s, XFER_RESULT_FAILED); - return; + audioh_stream_fail(s); + return false; } // Bind the transfer helper to the endpoint and start with an empty FIFO const uint16_t xfer_len = (s->dir == TUSB_DIR_IN) ? CFG_TUH_AUDIO_EPIN_BUFSIZE : CFG_TUH_AUDIO_EPOUT_BUFSIZE; tu_edpt_stream_open(&s->edpt, s->daddr, &desc_ep, xfer_len); tu_edpt_stream_clear(&s->edpt); - - if (map->sam_freq_ctrl) { - audioh_stream_set_freq(s); - } else { - audioh_stream_ready(s); - } -} - -static void audioh_stream_set_interface_complete(tuh_xfer_t *xfer) { - tuh_audio_stream_t *s = (tuh_audio_stream_t *)xfer->user_data; - if (s->daddr != xfer->daddr || s->state != STREAM_STATE_CONFIG) { - return; // device is gone or configuration was aborted - } - - if (xfer->result != XFER_RESULT_SUCCESS) { - TU_LOG_DRV(" AUDIO SET_INTERFACE failed: itf=%u alt=%u result=%u\r\n", s->map[s->active_config].itf_num, - s->map[s->active_config].alt_setting, xfer->result); - audioh_stream_fail(s, xfer->result); - return; - } - audioh_stream_open_ep(s); + s->state = STREAM_STATE_READY; + return true; } //--------------------------------------------------------------------+ @@ -534,12 +475,8 @@ void audioh_close(uint8_t daddr) { tuh_audio_umount_cb(idx); } - // Abort a configuration in progress so the application callback still fires for (uint8_t s = 0; s < 2; s++) { tuh_audio_stream_t *stream = (s == 0) ? &p_audio->in_stream : &p_audio->out_stream; - if (stream->state == STREAM_STATE_CONFIG && stream->complete_cb != NULL) { - audioh_stream_fail(stream, XFER_RESULT_ABORTED); - } audioh_stream_reset(stream); } @@ -1013,7 +950,7 @@ bool audioh_set_config(uint8_t dev_addr, uint8_t itf_num) { if (idx == TUSB_INDEX_INVALID_8) { // Audio Streaming interface (or another driver's interface): nothing to do at mount. - // Alternate settings are activated by tuh_audio_configure(). + // Alternate settings are activated by tuh_audio_start(). usbh_driver_set_config_complete(dev_addr, itf_num); return true; } @@ -1106,19 +1043,17 @@ bool tuh_audio_config_get(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_id return true; } -bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx, tuh_audio_configure_cb_t complete_cb, - uintptr_t user_data) { +bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx) { TU_VERIFY(dev_idx < CFG_TUH_AUDIO_MAX, false); audioh_interface_t *p_audio = &_audioh_itf[dev_idx]; TU_VERIFY(p_audio->mounted, false); tuh_audio_stream_t *s = audioh_get_stream_by_idx(p_audio, stream_idx); - TU_VERIFY(s && complete_cb, false); + TU_VERIFY(s, false); TU_VERIFY(config_idx < s->config_count, false); const tuh_audio_stream_config_t *cfg = &s->config[config_idx]; - // Reconfiguration is allowed from a stopped stream; only one configuration - // may be in progress - TU_VERIFY(s->state != STREAM_STATE_CONFIG && !s->running, false); + // Reconfiguration is allowed from a stopped stream. + TU_VERIFY(!s->running, false); if (s->state == STREAM_STATE_READY) { // Wait for any in-flight transfer to complete and be discarded TU_VERIFY(!usbh_edpt_busy(s->daddr, s->edpt.ep_addr), false); @@ -1153,33 +1088,64 @@ bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx s->frames_per_interval = (uint16_t)(frames_numerator / 1000000u); s->frames_rem = (uint32_t)(frames_numerator % 1000000u); s->rem_acc = 0; - s->complete_cb = complete_cb; - s->user_data = user_data; - s->state = STREAM_STATE_CONFIG; + s->state = STREAM_STATE_IDLE; if (s->dir == TUSB_DIR_IN) { // A byte FIFO can overwrite only complete audio frames when its depth is // an exact multiple of the configured frame size. const uint16_t fifo_depth = CFG_TUH_AUDIO_STREAM_BUFSIZE - (CFG_TUH_AUDIO_STREAM_BUFSIZE % s->frame_bytes); - TU_VERIFY(tu_fifo_config(&s->edpt.ff, s->ff_buf, fifo_depth, true), false); + if (!tu_fifo_config(&s->edpt.ff, s->ff_buf, fifo_depth, true)) { + audioh_stream_fail(s); + return false; + } } TU_LOG_DRV(" AUDIO configure %s stream %u: itf %u alt %u ep %02x\r\n", (s->dir == TUSB_DIR_IN) ? "capture" : "playback", s->stream_idx, map->itf_num, map->alt_setting, map->ep_addr); - if (!tuh_interface_set(s->daddr, map->itf_num, map->alt_setting, audioh_stream_set_interface_complete, - (uintptr_t)s)) { - audioh_stream_fail(s, XFER_RESULT_FAILED); - return false; + return audioh_stream_open_ep(s); +} + +// Invoked when the SET_INTERFACE activating the stream's interface completes: +// the interface is active, set its sampling frequency before submitting +// transfers +static void audioh_stream_start_xfer(tuh_audio_stream_t *s) { + if (s->dir == TUSB_DIR_IN) { + audioh_stream_capture_xfer(s); // feed the capture endpoint + } else { + audioh_stream_playback_xfer(s); // start the continuous playback transfer chain + } +} + +static void audioh_stream_start_set_freq_complete(tuh_xfer_t *xfer) { + tuh_audio_stream_t *s = (tuh_audio_stream_t *)xfer->user_data; + if (s->daddr != xfer->daddr || s->state != STREAM_STATE_READY || !s->running) { + return; // device is gone or the stream was stopped meanwhile + } + if (xfer->result != XFER_RESULT_SUCCESS) { + TU_LOG_DRV(" AUDIO set sampling frequency failed: result=%u\r\n", xfer->result); + s->running = false; + return; + } + audioh_stream_start_xfer(s); +} + +static bool audioh_stream_start_active(tuh_audio_stream_t *s) { + const audioh_stream_map_t *map = &s->map[s->active_config]; + if (map->sam_freq_ctrl) { + if (!audioh_stream_set_freq(s, audioh_stream_start_set_freq_complete)) { + s->running = false; + return false; + } + } else { + audioh_stream_start_xfer(s); } return true; } -// Invoked when the SET_INTERFACE activating the stream's interface completes: -// the interface is active, start submitting transfers static void audioh_stream_start_complete(tuh_xfer_t *xfer) { tuh_audio_stream_t *s = (tuh_audio_stream_t *)xfer->user_data; - if (s->daddr != xfer->daddr || !s->running) { + if (s->daddr != xfer->daddr || s->state != STREAM_STATE_READY || !s->running) { return; // device is gone or the stream was stopped meanwhile } if (xfer->result != XFER_RESULT_SUCCESS) { @@ -1187,11 +1153,7 @@ static void audioh_stream_start_complete(tuh_xfer_t *xfer) { s->running = false; return; } - if (s->dir == TUSB_DIR_IN) { - audioh_stream_capture_xfer(s); // feed the capture endpoint - } else { - audioh_stream_playback_xfer(s); // start the continuous playback transfer chain - } + (void)audioh_stream_start_active(s); } bool tuh_audio_start(uint8_t dev_idx, uint8_t stream_idx) { @@ -1205,9 +1167,9 @@ bool tuh_audio_start(uint8_t dev_idx, uint8_t stream_idx) { // Wait for any in-flight transfer to complete and be discarded TU_VERIFY(!usbh_edpt_busy(s->daddr, s->map[s->active_config].ep_addr), false); + s->running = true; // Activate the interface's alternate setting asynchronously: transfers - // begin once SET_INTERFACE completes (audioh_stream_start_complete) - s->running = true; + // begin once SET_INTERFACE and sampling-frequency control complete. const audioh_stream_map_t *map = &s->map[s->active_config]; if (!tuh_interface_set(s->daddr, map->itf_num, map->alt_setting, audioh_stream_start_complete, (uintptr_t)s)) { s->running = false; diff --git a/src/class/audio/audio_host.h b/src/class/audio/audio_host.h index 9fcbe2577..b1e2a9169 100644 --- a/src/class/audio/audio_host.h +++ b/src/class/audio/audio_host.h @@ -85,10 +85,6 @@ typedef struct { uint8_t channels; } tuh_audio_stream_config_t; -// Asynchronous completion callback of tuh_audio_configure(). -typedef void (*tuh_audio_configure_cb_t)(uint8_t dev_idx, uint8_t stream_idx, tusb_xfer_result_t result, - uintptr_t user_data); - //--------------------------------------------------------------------+ // Stream Enumeration //--------------------------------------------------------------------+ @@ -118,26 +114,24 @@ uint8_t tuh_audio_active_config(uint8_t dev_idx, uint8_t stream_idx); 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, asynchronous) +// Configuration (ALSA hw_params analogue) //--------------------------------------------------------------------+ -// Configure the stream with the discrete configuration identified by -// config_idx. The driver asynchronously: +// Synchronously configure the stream with the discrete configuration identified by +// config_idx. The driver: // 1. resolves the AS interface and alternate setting, -// 2. issues SET_INTERFACE (checking submission and transfer result), -// 3. opens / reconfigures only the selected endpoint, -// 4. sets the endpoint sampling frequency when supported, -// 5. initializes the FIFO and packet scheduler. -// complete_cb is invoked with the final XFER_RESULT_* status. -bool tuh_audio_configure(uint8_t dev_idx, uint8_t stream_idx, uint8_t config_idx, tuh_audio_configure_cb_t complete_cb, - uintptr_t user_data); +// 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/stop transferring data on a configured stream. +// Start transferring data by activating the alternate setting selected by +// configure, then set the endpoint sampling frequency when supported. 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. diff --git a/test/unit-test/test/host/audio/test_audio_host.c b/test/unit-test/test/host/audio/test_audio_host.c index b87f94bc9..ec1816084 100644 --- a/test/unit-test/test/host/audio/test_audio_host.c +++ b/test/unit-test/test/host/audio/test_audio_host.c @@ -26,6 +26,7 @@ enum { static bool interface_set_result; static tuh_xfer_t interface_xfer; static uint8_t interface_alt; +static uint8_t interface_set_count; static bool control_xfer_result; static tuh_xfer_t control_xfer; @@ -93,6 +94,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt, tuh_xfer interface_xfer.ep_addr = 0; interface_xfer.complete_cb = complete_cb; interface_xfer.user_data = user_data; + interface_set_count++; return interface_set_result; } @@ -343,20 +345,9 @@ static const uint8_t playback_44100_max_packets_only[] = { TEST_UAC1_CS_DATA_EP_ATTR(AUDIO10_CS_AS_ISO_DATA_EP_ATT_MAX_PACKETS_ONLY), }; -static uint8_t configure_cb_count; -static tusb_xfer_result_t configure_cb_result; - static uint8_t fu_cb_count; static uintptr_t fu_cb_user_data; -static void configure_complete(uint8_t dev_idx, uint8_t stream_idx, tusb_xfer_result_t result, uintptr_t user_data) { - (void)dev_idx; - (void)stream_idx; - (void)user_data; - configure_cb_count++; - configure_cb_result = result; -} - static void feature_unit_complete(tuh_xfer_t *xfer) { fu_cb_count++; fu_cb_user_data = xfer->user_data; @@ -381,7 +372,8 @@ static void complete_control_xfer(tusb_xfer_result_t result) { void setUp(void) { interface_set_result = true; memset(&interface_xfer, 0, sizeof(interface_xfer)); - interface_alt = 0; + interface_alt = 0; + interface_set_count = 0; control_xfer_result = true; memset(&control_xfer, 0, sizeof(control_xfer)); @@ -404,10 +396,8 @@ void setUp(void) { memset(edpt_xfer_buffer, 0, sizeof(edpt_xfer_buffer)); edpt_xfer_count = 0; - configure_cb_count = 0; - configure_cb_result = XFER_RESULT_INVALID; - fu_cb_count = 0; - fu_cb_user_data = 0; + fu_cb_count = 0; + fu_cb_user_data = 0; TEST_ASSERT_TRUE(audioh_init()); } @@ -456,11 +446,10 @@ void test_audio_host_maps_capture_fu_declared_before_usb_output_terminal(void) { TEST_ASSERT_EQUAL(TUH_AUDIO_STREAM_CAPTURE, tuh_audio_stream_direction(0, 0)); TEST_ASSERT_EQUAL_UINT8(CAPTURE_FU, tuh_audio_get_feature_unit_id(0, 0)); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); - complete_interface_set(XFER_RESULT_SUCCESS); - complete_control_xfer(XFER_RESULT_SUCCESS); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); complete_interface_set(XFER_RESULT_SUCCESS); + complete_control_xfer(XFER_RESULT_SUCCESS); TEST_ASSERT_EQUAL_UINT8(1, edpt_xfer_count); // Keep polling without application reads. Once full, the capture FIFO must @@ -480,6 +469,40 @@ void test_audio_host_maps_capture_fu_declared_before_usb_output_terminal(void) { TEST_ASSERT_EACH_EQUAL_UINT8(11, captured + fifo_depth - 96, 96); } +void test_audio_host_sets_sampling_frequency_after_each_stream_activation(void) { + mount_descriptors(capture_fu_before_usb_output, sizeof(capture_fu_before_usb_output)); + + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); + TEST_ASSERT_EQUAL_UINT8(0, control_xfer_count); + TEST_ASSERT_EQUAL_UINT8(0, interface_set_count); + + TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); + TEST_ASSERT_EQUAL_UINT8(1, interface_set_count); + complete_interface_set(XFER_RESULT_SUCCESS); + TEST_ASSERT_EQUAL_UINT8(1, control_xfer_count); + TEST_ASSERT_EQUAL_UINT8(0, edpt_xfer_count); + TEST_ASSERT_EQUAL_HEX8_ARRAY(((uint8_t[]){U24_TO_U8S_LE(32000)}), control_buffer, 3); + complete_control_xfer(XFER_RESULT_SUCCESS); + TEST_ASSERT_EQUAL_UINT8(1, edpt_xfer_count); + + TEST_ASSERT_TRUE(tuh_audio_stop(0, 0)); + TEST_ASSERT_EQUAL_UINT8(0, interface_alt); + TEST_ASSERT_EQUAL_UINT8(2, interface_set_count); + complete_interface_set(XFER_RESULT_SUCCESS); + edpt_busy = false; + TEST_ASSERT_TRUE(audioh_xfer_cb(AUDIO_DEV_ADDR, 0x81, XFER_RESULT_SUCCESS, 96)); + + TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); + TEST_ASSERT_EQUAL_UINT8(1, interface_alt); + TEST_ASSERT_EQUAL_UINT8(3, interface_set_count); + complete_interface_set(XFER_RESULT_SUCCESS); + TEST_ASSERT_EQUAL_UINT8(2, control_xfer_count); + TEST_ASSERT_EQUAL_UINT8(1, edpt_xfer_count); + TEST_ASSERT_EQUAL_HEX8_ARRAY(((uint8_t[]){U24_TO_U8S_LE(32000)}), control_buffer, 3); + complete_control_xfer(XFER_RESULT_SUCCESS); + TEST_ASSERT_EQUAL_UINT8(2, edpt_xfer_count); +} + void test_audio_host_parses_discrete_frequencies_with_interval_greater_than_one(void) { tuh_audio_stream_config_t config; open_descriptors(playback_with_two_frequencies, sizeof(playback_with_two_frequencies)); @@ -503,50 +526,42 @@ void test_audio_host_rejects_overflowed_frame_size_for_large_channel_count(void) TEST_ASSERT_EQUAL_UINT8(0, tuh_audio_stream_count(0)); } -void test_audio_host_associates_cs_endpoint_declared_before_data_endpoint(void) { +void test_audio_host_uses_cs_endpoint_declared_before_data_endpoint_on_start(void) { mount_descriptors(playback_with_cs_ep_before_data_ep, sizeof(playback_with_cs_ep_before_data_ep)); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); - complete_interface_set(XFER_RESULT_SUCCESS); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); + TEST_ASSERT_EQUAL_UINT8(0, control_xfer_count); + TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); + TEST_ASSERT_EQUAL_UINT8(1, interface_set_count); + complete_interface_set(XFER_RESULT_SUCCESS); TEST_ASSERT_EQUAL_UINT8(1, control_xfer_count); TEST_ASSERT_EQUAL_UINT16(3, tu_le16toh(control_request.wLength)); TEST_ASSERT_EQUAL_UINT16(0x01, tu_le16toh(control_request.wIndex)); complete_control_xfer(XFER_RESULT_SUCCESS); - TEST_ASSERT_EQUAL_UINT8(1, configure_cb_count); - TEST_ASSERT_EQUAL(XFER_RESULT_SUCCESS, configure_cb_result); } void test_audio_host_closes_old_endpoint_and_cleans_up_failed_reconfiguration(void) { mount_descriptors(playback_with_two_alternates, sizeof(playback_with_two_alternates)); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); - complete_interface_set(XFER_RESULT_SUCCESS); - complete_control_xfer(XFER_RESULT_SUCCESS); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); TEST_ASSERT_EQUAL_UINT8(1, edpt_open_count); TEST_ASSERT_EQUAL_HEX8(0x01, opened_ep[0].bEndpointAddress); TEST_ASSERT_EQUAL_UINT16(192, tu_edpt_packet_size(&opened_ep[0])); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 1, configure_complete, 0)); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 1)); TEST_ASSERT_EQUAL_UINT8(1, edpt_close_count); TEST_ASSERT_EQUAL_HEX8(0x01, closed_ep[0]); - complete_interface_set(XFER_RESULT_SUCCESS); - complete_control_xfer(XFER_RESULT_SUCCESS); TEST_ASSERT_EQUAL_UINT8(2, edpt_open_count); TEST_ASSERT_EQUAL_HEX8(0x02, opened_ep[1].bEndpointAddress); TEST_ASSERT_EQUAL_UINT16(384, tu_edpt_packet_size(&opened_ep[1])); - control_xfer_result = false; - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); + edpt_open_result = false; + TEST_ASSERT_FALSE(tuh_audio_configure(0, 0, 0)); TEST_ASSERT_EQUAL_UINT8(2, edpt_close_count); TEST_ASSERT_EQUAL_HEX8(0x02, closed_ep[1]); - complete_interface_set(XFER_RESULT_SUCCESS); TEST_ASSERT_EQUAL_UINT8(3, edpt_open_count); - TEST_ASSERT_EQUAL_UINT8(3, edpt_close_count); - TEST_ASSERT_EQUAL_HEX8(0x01, closed_ep[2]); - TEST_ASSERT_EQUAL_UINT8(3, configure_cb_count); - TEST_ASSERT_EQUAL(XFER_RESULT_FAILED, configure_cb_result); TEST_ASSERT_EQUAL_UINT8(TUSB_INDEX_INVALID_8, tuh_audio_active_config(0, 0)); } @@ -590,13 +605,12 @@ void test_audio_host_schedules_44100_hz_fractional_packets_with_max_packets_only uint8_t samples[441 * 4] = {0}; mount_descriptors(playback_44100_max_packets_only, sizeof(playback_44100_max_packets_only)); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); - complete_interface_set(XFER_RESULT_SUCCESS); - TEST_ASSERT_EQUAL_UINT8(1, configure_cb_count); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); TEST_ASSERT_EQUAL_UINT8(0, control_xfer_count); TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); TEST_ASSERT_EQUAL_UINT8(1, interface_alt); + TEST_ASSERT_EQUAL_UINT8(1, interface_set_count); TEST_ASSERT_EQUAL_UINT32(256, tuh_audio_write(0, 0, samples, 256)); TEST_ASSERT_EQUAL_UINT8(0, edpt_xfer_count); complete_interface_set(XFER_RESULT_SUCCESS); @@ -624,8 +638,7 @@ void test_audio_host_sends_silence_when_playback_fifo_has_too_few_frames(void) { memset(more_samples, 0x55, sizeof(more_samples)); mount_descriptors(playback_44100_max_packets_only, sizeof(playback_44100_max_packets_only)); - TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0, configure_complete, 0)); - complete_interface_set(XFER_RESULT_SUCCESS); + TEST_ASSERT_TRUE(tuh_audio_configure(0, 0, 0)); TEST_ASSERT_TRUE(tuh_audio_start(0, 0)); complete_interface_set(XFER_RESULT_SUCCESS); |
