summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/class/audio/audio_host.c38
-rw-r--r--test/unit-test/test/host/audio/test_audio_host.c30
2 files changed, 56 insertions, 12 deletions
diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c
index 2c18a22d8..2aad4040e 100644
--- a/src/class/audio/audio_host.c
+++ b/src/class/audio/audio_host.c
@@ -800,8 +800,11 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface
uint8_t usb_output_source_id = 0;
bool found_as_interface = false;
// A Feature Unit may precede the USB terminal that identifies its stream.
- uint8_t pending_fu_id = 0;
- uint8_t pending_fu_source_id = 0;
+ typedef struct {
+ uint8_t id;
+ uint8_t source_id;
+ } audioh_fu_info_t;
+ audioh_fu_info_t pending_fu[TUH_AUDIO_STREAM_DIRECTION_COUNT] = {0};
p_desc = tu_desc_next(p_desc);
while (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) != TUSB_DESC_INTERFACE) {
@@ -812,10 +815,13 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface
if (terminal->bLength >= sizeof(audio10_desc_input_terminal_t) &&
tu_le16toh(terminal->wTerminalType) == AUDIO_TERM_TYPE_USB_STREAMING && usb_input_terminal_id == 0) {
usb_input_terminal_id = terminal->bTerminalID;
- if (pending_fu_source_id == usb_input_terminal_id) {
- p_audio->out_stream.feature_unit_id = pending_fu_id;
- pending_fu_id = 0;
- pending_fu_source_id = 0;
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(pending_fu); i++) {
+ if (pending_fu[i].source_id == usb_input_terminal_id) {
+ p_audio->out_stream.feature_unit_id = pending_fu[i].id;
+ pending_fu[i].id = 0;
+ pending_fu[i].source_id = 0;
+ break;
+ }
}
}
break;
@@ -825,10 +831,13 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface
if (terminal->bLength >= sizeof(audio10_desc_output_terminal_t) &&
tu_le16toh(terminal->wTerminalType) == AUDIO_TERM_TYPE_USB_STREAMING && usb_output_source_id == 0) {
usb_output_source_id = terminal->bSourceID;
- if (pending_fu_id == usb_output_source_id) {
- p_audio->in_stream.feature_unit_id = pending_fu_id;
- pending_fu_id = 0;
- pending_fu_source_id = 0;
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(pending_fu); i++) {
+ if (pending_fu[i].id == usb_output_source_id) {
+ p_audio->in_stream.feature_unit_id = pending_fu[i].id;
+ pending_fu[i].id = 0;
+ pending_fu[i].source_id = 0;
+ break;
+ }
}
}
break;
@@ -847,8 +856,13 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface
mapped = true;
}
if (!mapped) {
- pending_fu_id = p_desc[3];
- pending_fu_source_id = p_desc[4];
+ for (uint8_t i = 0; i < TU_ARRAY_SIZE(pending_fu); i++) {
+ if (pending_fu[i].id == 0) {
+ pending_fu[i].id = p_desc[3];
+ pending_fu[i].source_id = p_desc[4];
+ break;
+ }
+ }
}
}
break;
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 72026e682..b11d5a766 100644
--- a/test/unit-test/test/host/audio/test_audio_host.c
+++ b/test/unit-test/test/host/audio/test_audio_host.c
@@ -324,6 +324,28 @@ static const uint8_t capture_fu_before_usb_output[] = {
TEST_UAC1_DATA_EP(0x81, TUSB_ISO_EP_ATT_ASYNCHRONOUS, 96, 1),
};
+static const uint8_t duplex_fus_before_usb_terminals[] = {
+ TEST_UAC1_AC_HEADER_2,
+ TEST_UAC1_FEATURE_UNIT(PLAYBACK_FU, PLAYBACK_INPUT_TERM),
+ TEST_UAC1_FEATURE_UNIT(CAPTURE_FU, CAPTURE_INPUT_TERM),
+ TEST_UAC1_INPUT_TERM(PLAYBACK_INPUT_TERM, AUDIO_TERM_TYPE_USB_STREAMING, 2),
+ TEST_UAC1_OUTPUT_TERM(CAPTURE_OUTPUT_TERM, AUDIO_TERM_TYPE_USB_STREAMING, CAPTURE_FU),
+ TEST_UAC1_OUTPUT_TERM(PLAYBACK_OUTPUT_TERM, AUDIO_TERM_TYPE_OUT_HEADPHONES, PLAYBACK_FU),
+ TEST_UAC1_INPUT_TERM(CAPTURE_INPUT_TERM, AUDIO_TERM_TYPE_IN_GENERIC_MIC, 1),
+ TEST_UAC1_AS_ALT0,
+ TEST_UAC1_AS_INTERFACE(1, 1),
+ TEST_UAC1_AS_GENERAL(PLAYBACK_INPUT_TERM),
+ TEST_UAC1_FORMAT(2, 2, 16, 48000),
+ TEST_UAC1_DATA_EP(0x01, TUSB_ISO_EP_ATT_ADAPTIVE, 192, 1),
+ TEST_UAC1_CS_DATA_EP,
+ TEST_UAC1_AS_INTERFACE_NUM(AUDIO_AS_IN_ITF, 0, 0),
+ TEST_UAC1_AS_INTERFACE_NUM(AUDIO_AS_IN_ITF, 1, 1),
+ TEST_UAC1_AS_GENERAL(CAPTURE_OUTPUT_TERM),
+ TEST_UAC1_FORMAT(1, 2, 16, 48000),
+ TEST_UAC1_DATA_EP(0x81, TUSB_ISO_EP_ATT_ASYNCHRONOUS, 96, 1),
+ TEST_UAC1_CS_DATA_EP,
+};
+
static const uint8_t playback_with_two_frequencies[] = {
TEST_UAC1_AC_HEADER,
TEST_UAC1_INPUT_TERM(PLAYBACK_INPUT_TERM, AUDIO_TERM_TYPE_USB_STREAMING, 2),
@@ -554,6 +576,14 @@ 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_maps_duplex_fus_declared_before_usb_terminals(void) {
+ open_descriptors(duplex_fus_before_usb_terminals, sizeof(duplex_fus_before_usb_terminals));
+
+ TEST_ASSERT_EQUAL_UINT8(2, tuh_audio_stream_count(0));
+ TEST_ASSERT_EQUAL_UINT8(PLAYBACK_FU, tuh_audio_get_feature_unit_id(0, 0));
+ TEST_ASSERT_EQUAL_UINT8(CAPTURE_FU, tuh_audio_get_feature_unit_id(0, 1));
+}
+
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));