Skip to content

Commit 6a67bac

Browse files
committed
Integrate OS guessing quirk into uac2_speaker_fb example.
1 parent 4a48544 commit 6a67bac

File tree

5 files changed

+253
-3
lines changed

5 files changed

+253
-3
lines changed

examples/device/uac2_speaker_fb/src/main.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
#include "usb_descriptors.h"
3232
#include "common_types.h"
3333

34+
#ifdef CFG_QUIRK_OS_GUESSING
35+
#include "quirk_os_guessing.h"
36+
#endif
37+
3438
//--------------------------------------------------------------------+
3539
// MACRO CONSTANT TYPEDEF PROTOTYPES
3640
//--------------------------------------------------------------------+
@@ -385,6 +389,18 @@ bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, u
385389
return true;
386390
}
387391
#endif
392+
393+
#if CFG_QUIRK_OS_GUESSING
394+
bool tud_audio_feedback_format_correction_cb(uint8_t func_id)
395+
{
396+
(void)func_id;
397+
if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) {
398+
return true;
399+
} else {
400+
return false;
401+
}
402+
}
403+
#endif
388404
//--------------------------------------------------------------------+
389405
// AUDIO Task
390406
//--------------------------------------------------------------------+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2024 HiFiPhile
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
*/
25+
26+
#include "quirk_os_guessing.h"
27+
28+
static tusb_desc_type_t desc_req_buf[2];
29+
static int desc_req_idx = 0;
30+
31+
// Place at the start of tud_descriptor_device_cb()
32+
void quirk_os_guessing_desc_device_cb() {
33+
desc_req_idx = 0;
34+
}
35+
36+
// Place at the start of tud_descriptor_configuration_cb()
37+
void quirk_os_guessing_desc_configuration_cb() {
38+
// Skip redundant request
39+
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_CONFIGURATION)) {
40+
desc_req_buf[desc_req_idx++] = TUSB_DESC_CONFIGURATION;
41+
}
42+
}
43+
44+
// Place at the start of tud_descriptor_bos_cb()
45+
void quirk_os_guessing_desc_bos_cb() {
46+
// Skip redundant request
47+
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_BOS)) {
48+
desc_req_buf[desc_req_idx++] = TUSB_DESC_BOS;
49+
}
50+
}
51+
52+
// Place at the start of tud_descriptor_string_cb()
53+
void quirk_os_guessing_desc_string_cb() {
54+
// Skip redundant request
55+
if (desc_req_idx == 0 || (desc_req_idx == 1 && desc_req_buf[0] != TUSB_DESC_STRING)) {
56+
desc_req_buf[desc_req_idx++] = TUSB_DESC_STRING;
57+
}
58+
}
59+
60+
// Each OS request descriptors differently:
61+
// Windows 10 - 11
62+
// Device Desc
63+
// Config Desc
64+
// BOS Desc
65+
// String Desc
66+
// Linux 3.16 - 6.8
67+
// Device Desc
68+
// BOS Desc
69+
// Config Desc
70+
// String Desc
71+
// OS X Ventura - Sonoma
72+
// Device Desc
73+
// String Desc
74+
// Config Desc || BOS Desc
75+
// BOS Desc || Config Desc
76+
quirk_os_guessing_t quirk_os_guessing_get(void) {
77+
if (desc_req_idx < 2) {
78+
return QUIRK_OS_GUESSING_UNKNOWN;
79+
}
80+
81+
if (desc_req_buf[0] == TUSB_DESC_BOS && desc_req_buf[1] == TUSB_DESC_CONFIGURATION) {
82+
return QUIRK_OS_GUESSING_LINUX;
83+
} else if (desc_req_buf[0] == TUSB_DESC_CONFIGURATION && desc_req_buf[1] == TUSB_DESC_BOS) {
84+
return QUIRK_OS_GUESSING_WINDOWS;
85+
} else if (desc_req_buf[0] == TUSB_DESC_STRING && (desc_req_buf[1] == TUSB_DESC_BOS || desc_req_buf[1] == TUSB_DESC_CONFIGURATION)) {
86+
return QUIRK_OS_GUESSING_OSX;
87+
}
88+
89+
return QUIRK_OS_GUESSING_UNKNOWN;
90+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2024 HiFiPhile
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
*/
25+
26+
#ifndef _QUIRK_OS_GUESSING_H_
27+
#define _QUIRK_OS_GUESSING_H_
28+
29+
#ifdef __cplusplus
30+
extern "C" {
31+
#endif
32+
33+
#include "tusb.h"
34+
35+
//================================== !!! WARNING !!! ====================================
36+
// This quirk operate out of USB specification in order to workaround specific issues.
37+
// It may not work on your platform.
38+
//=======================================================================================
39+
//
40+
// Prerequisites:
41+
// - Set USB version to at least 2.01 in Device Descriptor
42+
// - Has a valid BOS Descriptor, refer to webusb_serial example
43+
//
44+
// Attention:
45+
// Windows detection result comes out after Configuration Descriptor request,
46+
// meaning it will be too late to do descriptor adjustment. It's advised to make
47+
// Windows as default configuration and adjust to other OS accordingly.
48+
49+
typedef enum {
50+
QUIRK_OS_GUESSING_UNKNOWN,
51+
QUIRK_OS_GUESSING_LINUX,
52+
QUIRK_OS_GUESSING_OSX,
53+
QUIRK_OS_GUESSING_WINDOWS,
54+
} quirk_os_guessing_t;
55+
56+
// Get Host OS type
57+
quirk_os_guessing_t quirk_os_guessing_get(void);
58+
59+
// Place at the start of tud_descriptor_device_cb()
60+
void quirk_os_guessing_desc_device_cb(void);
61+
62+
// Place at the start of tud_descriptor_configuration_cb()
63+
void quirk_os_guessing_desc_configuration_cb(void);
64+
65+
// Place at the start of tud_descriptor_bos_cb()
66+
void quirk_os_guessing_desc_bos_cb(void);
67+
68+
// Place at the start of tud_descriptor_string_cb()
69+
void quirk_os_guessing_desc_string_cb(void);
70+
71+
#ifdef __cplusplus
72+
}
73+
#endif
74+
75+
#endif /* _QUIRK_OS_GUESSING_H_ */

examples/device/uac2_speaker_fb/src/tusb_config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ extern "C" {
8787
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
8888
#endif
8989

90+
/* (Needed for Full-Speed only)
91+
* Enable host OS guessing to workaround UAC2 compatibility issues between Windows and OS X
92+
* The default configuration only support Windows and Linux, enable this option for OS X
93+
* support. Otherwise if you don't need Windows support you can make OS X's configuration as
94+
* default.
95+
*/
96+
#define CFG_QUIRK_OS_GUESSING 1
97+
9098
//--------------------------------------------------------------------
9199
// DEVICE CONFIGURATION
92100
//--------------------------------------------------------------------

examples/device/uac2_speaker_fb/src/usb_descriptors.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#include "usb_descriptors.h"
2929
#include "common_types.h"
3030

31+
#ifdef CFG_QUIRK_OS_GUESSING
32+
#include "quirk_os_guessing.h"
33+
#endif
34+
3135
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
3236
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
3337
*
@@ -45,7 +49,7 @@ tusb_desc_device_t const desc_device =
4549
{
4650
.bLength = sizeof(tusb_desc_device_t),
4751
.bDescriptorType = TUSB_DESC_DEVICE,
48-
.bcdUSB = 0x0200,
52+
.bcdUSB = 0x0201,
4953

5054
// Use Interface Association Descriptor (IAD) for Audio
5155
// As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
@@ -69,6 +73,9 @@ tusb_desc_device_t const desc_device =
6973
// Application return pointer to descriptor
7074
uint8_t const * tud_descriptor_device_cb(void)
7175
{
76+
#if CFG_QUIRK_OS_GUESSING
77+
quirk_os_guessing_desc_device_cb();
78+
#endif
7279
return (uint8_t const *)&desc_device;
7380
}
7481

@@ -144,7 +151,7 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
144151
#define EPNUM_DEBUG 0x02
145152
#endif
146153

147-
uint8_t const desc_configuration[] =
154+
uint8_t const desc_configuration_default[] =
148155
{
149156
// Config number, interface count, string index, total length, attribute, power in mA
150157
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
@@ -158,13 +165,63 @@ uint8_t const desc_configuration[] =
158165
#endif
159166
};
160167

168+
#if CFG_QUIRK_OS_GUESSING
169+
// OS X needs 3 bytes feedback endpoint on FS
170+
uint8_t const desc_configuration_osx_fs[] =
171+
{
172+
// Config number, interface count, string index, total length, attribute, power in mA
173+
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
174+
175+
// Interface number, string index, byte per sample, bit per sample, EP Out, EP size, EP feedback, feedback EP size,
176+
TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(0, 4, CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_RESOLUTION_RX, EPNUM_AUDIO_OUT, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX, EPNUM_AUDIO_FB | 0x80, 3),
177+
178+
#if CFG_AUDIO_DEBUG
179+
// Interface number, string index, protocol, report descriptor len, EP In address, size & polling interval
180+
TUD_HID_DESCRIPTOR(ITF_NUM_DEBUG, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_DEBUG | 0x80, CFG_TUD_HID_EP_BUFSIZE, 7)
181+
#endif
182+
};
183+
#endif
184+
161185
// Invoked when received GET CONFIGURATION DESCRIPTOR
162186
// Application return pointer to descriptor
163187
// Descriptor contents must exist long enough for transfer to complete
164188
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
165189
{
166190
(void)index; // for multiple configurations
167-
return desc_configuration;
191+
192+
#if CFG_QUIRK_OS_GUESSING
193+
quirk_os_guessing_desc_configuration_cb();
194+
if(tud_speed_get() == TUSB_SPEED_FULL && quirk_os_guessing_get() == QUIRK_OS_GUESSING_OSX) {
195+
return desc_configuration_osx_fs;
196+
}
197+
#endif
198+
return desc_configuration_default;
199+
}
200+
201+
//--------------------------------------------------------------------+
202+
// BOS Descriptor, required for OS guessing quirk
203+
//--------------------------------------------------------------------+
204+
205+
#define TUD_BOS_USB20_EXT_DESC_LEN 7
206+
207+
#define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_USB20_EXT_DESC_LEN)
208+
209+
// BOS Descriptor is required for webUSB
210+
uint8_t const desc_bos[] =
211+
{
212+
// total length, number of device caps
213+
TUD_BOS_DESCRIPTOR(BOS_TOTAL_LEN, 1),
214+
215+
// USB 2.0 Extension Descriptor
216+
0x07, TUSB_DESC_DEVICE_CAPABILITY, DEVICE_CAPABILITY_USB20_EXTENSION, 0x00, 0x00, 0x00,0x00
217+
};
218+
219+
uint8_t const * tud_descriptor_bos_cb(void)
220+
{
221+
#if CFG_QUIRK_OS_GUESSING
222+
quirk_os_guessing_desc_bos_cb();
223+
#endif
224+
return desc_bos;
168225
}
169226

170227
//--------------------------------------------------------------------+
@@ -197,6 +254,10 @@ uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
197254
(void) langid;
198255
size_t chr_count;
199256

257+
#if CFG_QUIRK_OS_GUESSING
258+
quirk_os_guessing_desc_string_cb();
259+
#endif
260+
200261
switch ( index ) {
201262
case STRID_LANGID:
202263
memcpy(&_desc_str[1], string_desc_arr[0], 2);

0 commit comments

Comments
 (0)