diff options
| author | HiFiPHile <[email protected]> | 2026-08-25 09:29:07 +0200 |
|---|---|---|
| committer | HiFiPHile <[email protected]> | 2026-08-25 09:29:07 +0200 |
| commit | 87511ce87280e986545149e4ad017ccf2392671c (patch) | |
| tree | 6f0cc082e286f5f00795152389fb450d1f18e8ad | |
| parent | ea7d4ef12a4cd2b6fb6986a091888bc838b12574 (diff) | |
fix(audio): release instances without supported streams
Retain an audio function when at least one direction has a supported configuration, but release the tentative instance when neither direction does. Unsupported and MIDI-only functions no longer consume host slots or emit mount callbacks.
Signed-off-by: HiFiPHile <[email protected]>
| -rw-r--r-- | src/class/audio/audio_host.c | 8 | ||||
| -rw-r--r-- | test/unit-test/test/host/audio/test_audio_host.c | 41 |
2 files changed, 38 insertions, 11 deletions
diff --git a/src/class/audio/audio_host.c b/src/class/audio/audio_host.c index 2aad4040e..c29db658c 100644 --- a/src/class/audio/audio_host.c +++ b/src/class/audio/audio_host.c @@ -798,7 +798,6 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface uint8_t usb_input_terminal_id = 0; uint8_t usb_output_source_id = 0; - bool found_as_interface = false; // A Feature Unit may precede the USB terminal that identifies its stream. typedef struct { uint8_t id; @@ -887,15 +886,14 @@ uint16_t audioh_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface break; } - found_as_interface = true; TU_LOG_DRV(" Found AS Interface %u (alt = %u)\r\n", desc_interface->bInterfaceNumber, desc_interface->bAlternateSetting); p_desc = audioh_parse_as(p_audio, desc_interface, p_desc, desc_end); } - // This AC interface belongs to MIDI or another Audio subclass. Release the - // tentative instance and let the next class driver claim the interface. - if (!found_as_interface) { + // Release the tentative instance when no supported stream configuration was + // collected, including MIDI-only and unsupported Audio functions. + if (p_audio->in_stream.config_count == 0 && p_audio->out_stream.config_count == 0) { audioh_stream_reset(&p_audio->in_stream); audioh_stream_reset(&p_audio->out_stream); p_audio->daddr = 0; 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 b11d5a766..37b35dae8 100644 --- a/test/unit-test/test/host/audio/test_audio_host.c +++ b/test/unit-test/test/host/audio/test_audio_host.c @@ -346,6 +346,24 @@ static const uint8_t duplex_fus_before_usb_terminals[] = { TEST_UAC1_CS_DATA_EP, }; +static const uint8_t playback_with_unsupported_capture[] = { + TEST_UAC1_AC_HEADER_2, + 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_INPUT_TERM), + 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, 12, 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), @@ -667,16 +685,27 @@ void test_audio_host_parses_discrete_frequencies_with_interval_greater_than_one( TEST_ASSERT_EQUAL_UINT32(48000, config.sample_rate); } -void test_audio_host_rejects_sampling_frequency_range(void) { - open_descriptors(playback_with_frequency_range, sizeof(playback_with_frequency_range)); +void test_audio_host_keeps_supported_stream_when_other_as_format_is_unsupported(void) { + open_descriptors(playback_with_unsupported_capture, sizeof(playback_with_unsupported_capture)); - TEST_ASSERT_EQUAL_UINT8(0, tuh_audio_stream_count(0)); + TEST_ASSERT_EQUAL_UINT8(1, tuh_audio_stream_count(0)); + TEST_ASSERT_EQUAL(TUH_AUDIO_STREAM_PLAYBACK, tuh_audio_stream_direction(0, 0)); } -void test_audio_host_rejects_overflowed_frame_size_for_large_channel_count(void) { - open_descriptors(capture_with_large_channel_count, sizeof(capture_with_large_channel_count)); +void test_audio_host_rejects_sampling_frequency_range_and_releases_instance(void) { + TEST_ASSERT_EQUAL_UINT16(0, audioh_open(0, AUDIO_DEV_ADDR, (const tusb_desc_interface_t *)playback_with_frequency_range, + sizeof(playback_with_frequency_range))); + TEST_ASSERT_EQUAL_UINT8(0, tuh_audio_get_dev_addr(0)); - TEST_ASSERT_EQUAL_UINT8(0, tuh_audio_stream_count(0)); + open_descriptors(playback_with_explicit_feedback, sizeof(playback_with_explicit_feedback)); + TEST_ASSERT_EQUAL_UINT8(1, tuh_audio_stream_count(0)); +} + +void test_audio_host_rejects_overflowed_frame_size_for_large_channel_count(void) { + TEST_ASSERT_EQUAL_UINT16(0, audioh_open(0, AUDIO_DEV_ADDR, + (const tusb_desc_interface_t *)capture_with_large_channel_count, + sizeof(capture_with_large_channel_count))); + TEST_ASSERT_EQUAL_UINT8(0, tuh_audio_get_dev_addr(0)); } void test_audio_host_uses_cs_endpoint_declared_before_data_endpoint_on_start(void) { |
