diff options
| -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); |
