summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/host/audio_host/src/audio_app.c61
-rw-r--r--src/class/audio/audio_host.c164
-rw-r--r--src/class/audio/audio_host.h24
-rw-r--r--test/unit-test/test/host/audio/test_audio_host.c97
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);