1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** USBX Component */
16 /** */
17 /** Audio Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_audio.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_audio_streaming_sampling_get PORTABLE C */
37 /* 6.1.12 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function obtains successive sampling characteristics for the */
45 /* audio streaming channel. */
46 /* */
47 /* Note only Audio 1.0 and RAW (PCM like) format is supported. */
48 /* */
49 /* INPUT */
50 /* */
51 /* audio Pointer to audio class */
52 /* audio_sampling Pointer to audio sampling */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* Completion Status */
57 /* */
58 /* CALLS */
59 /* */
60 /* _ux_host_stack_class_instance_verify Verify instance is valid */
61 /* _ux_utility_descriptor_parse Parse the descriptor */
62 /* _ux_host_mutex_on Get mutex */
63 /* _ux_host_mutex_off Put mutex */
64 /* */
65 /* CALLED BY */
66 /* */
67 /* Application */
68 /* Audio Class */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
75 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
76 /* resulting in version 6.1 */
77 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
78 /* refined macros names, */
79 /* resulting in version 6.1.10 */
80 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
81 /* fixed standalone compile, */
82 /* resulting in version 6.1.11 */
83 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
84 /* protect reentry with mutex, */
85 /* fixed error return code, */
86 /* resulting in version 6.1.12 */
87 /* */
88 /**************************************************************************/
_ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * audio_sampling)89 UINT _ux_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)
90 {
91
92 UCHAR * descriptor;
93 UX_INTERFACE_DESCRIPTOR interface_descriptor;
94 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR audio_interface_descriptor;
95 ULONG total_descriptor_length;
96 UINT descriptor_length;
97 UINT descriptor_type;
98 UINT descriptor_subtype;
99 UINT interface_found;
100 ULONG lower_frequency;
101 ULONG higher_frequency;
102 UINT specific_frequency_count;
103 UINT previous_match_found;
104
105 /* If trace is enabled, insert this event into the trace buffer. */
106 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_AUDIO_STREAMING_SAMPLING_GET, audio, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
107
108 /* Ensure the instance is valid. */
109 if (_ux_host_stack_class_instance_verify(_ux_system_host_class_audio_name, (VOID *) audio) != UX_SUCCESS)
110 {
111
112 /* Error trap. */
113 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_INSTANCE_UNKNOWN);
114
115 /* If trace is enabled, insert this event into the trace buffer. */
116 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_INSTANCE_UNKNOWN, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
117
118 return(UX_HOST_CLASS_INSTANCE_UNKNOWN);
119 }
120
121 /* Protect thread reentry to this instance. */
122 _ux_host_mutex_on(&audio -> ux_host_class_audio_mutex);
123
124 /* Reset the match flag. */
125 previous_match_found = UX_FALSE;
126
127 /* Get the descriptor to the entire configuration. */
128 descriptor = audio -> ux_host_class_audio_configuration_descriptor;
129 total_descriptor_length = audio -> ux_host_class_audio_configuration_descriptor_length;
130
131 /* Default is Interface descriptor not yet found. */
132 interface_found = UX_FALSE;
133
134 /* Scan the descriptor for the Audio Streaming interface. */
135 while (total_descriptor_length)
136 {
137
138 /* Gather the length, type and subtype of the descriptor. */
139 descriptor_length = *descriptor;
140 descriptor_type = *(descriptor + 1);
141 descriptor_subtype = *(descriptor + 2);
142
143 /* Make sure this descriptor has at least the minimum length. */
144 if (descriptor_length < 3)
145 {
146
147 /* Error trap. */
148 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
149
150 /* If trace is enabled, insert this event into the trace buffer. */
151 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
152
153 /* Unprotect thread reentry to this instance. */
154 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
155
156 return(UX_DESCRIPTOR_CORRUPTED);
157 }
158
159 /* Process relative to descriptor type. */
160 switch(descriptor_type)
161 {
162
163
164 case UX_INTERFACE_DESCRIPTOR_ITEM:
165
166 /* Parse the interface descriptor and make it machine independent */
167 _ux_utility_descriptor_parse(descriptor, _ux_system_interface_descriptor_structure,
168 UX_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &interface_descriptor);
169
170 /* Ensure we have the correct interface for Audio streaming. */
171 if ((interface_descriptor.bInterfaceClass == UX_HOST_CLASS_AUDIO_CLASS) &&
172 (interface_descriptor.bInterfaceSubClass == UX_HOST_CLASS_AUDIO_SUBCLASS_STREAMING))
173 {
174
175 /* Mark we have found it. */
176 interface_found = UX_TRUE;
177 }
178 else
179 {
180 interface_found = UX_FALSE;
181 }
182 break;
183
184
185 case UX_HOST_CLASS_AUDIO_CS_INTERFACE:
186
187 /* First make sure we have found the correct generic interface descriptor. */
188 if ((interface_found == UX_TRUE) && (descriptor_subtype == UX_HOST_CLASS_AUDIO_CS_FORMAT_TYPE))
189 {
190
191 /* Parse the FORMAT_TYPE descriptor and make it machine independent. */
192 _ux_utility_descriptor_parse(descriptor, _ux_system_class_audio_interface_descriptor_structure,
193 UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_ENTRIES, (UCHAR *) &audio_interface_descriptor);
194
195 /* This descriptor must refer to a PCM audio type. */
196 if (audio_interface_descriptor.bFormatType != UX_HOST_CLASS_AUDIO_FORMAT_TYPE_I)
197 break;
198
199 /* If this is the first time we ask for a streaming interface characteristics
200 we return the first we find. */
201 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == 0) &&
202 (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == 0))
203 {
204
205 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
206 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
207
208 if (audio_interface_descriptor.bSamFreqType == 0)
209 {
210
211 /* The declaration of frequency is contiguous, so get the minimum and maximum */
212 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
213 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
214 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
215 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
216
217 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high =
218 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
219 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
220 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
221 }
222 else
223 {
224
225 /* The declaration of the frequency is declared as an array of specific values.
226 We take the first one here. */
227 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low =
228 (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH ) |
229 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 )) << 8 |
230 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 )) << 16;
231
232 /* High and low frequencies are the same here. */
233 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low;
234
235 /* Unprotect thread reentry to this instance. */
236 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
237
238 /* We have found the first streaming characteristics. */
239 return(UX_SUCCESS);
240 }
241 }
242 else
243 {
244
245 /* This is not the second time we ask for the characteristics, we need
246 to find 1st where we left off and look at the next characteristics. */
247 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_channels == audio_interface_descriptor.bNrChannels) &&
248 (audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution == audio_interface_descriptor.bBitResolution))
249 {
250
251 if (audio_interface_descriptor.bSamFreqType == 0)
252 {
253
254 /* The declaration of frequency is contiguous, so get the minimum and maximum. */
255 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
256 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
257 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
258
259 higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
260 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
261 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
262
263 if ((audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency) &&
264 (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high == higher_frequency))
265 {
266
267 /* We have a match. */
268 previous_match_found = UX_TRUE;
269 break;
270 }
271 }
272 else
273 {
274
275 /* The declaration of the frequency is declared as an array of specific values. */
276 for (specific_frequency_count = 0; specific_frequency_count < audio_interface_descriptor.bSamFreqType; specific_frequency_count++)
277 {
278
279 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + (specific_frequency_count * 3)) |
280 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1 + (specific_frequency_count * 3))) << 8 |
281 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2 + (specific_frequency_count * 3))) << 16;
282
283 /* Compare the frequency. */
284 if (audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low == lower_frequency)
285 {
286
287 previous_match_found = UX_TRUE;
288 }
289 else
290 {
291
292 /* Now the frequency is different, if we had a match before
293 this becomes the next characteristics found. */
294 if (previous_match_found == UX_TRUE)
295 {
296
297 /* We return this characteristics. */
298 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
299 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
300 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
301 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = lower_frequency;
302
303 /* Unprotect thread reentry to this instance. */
304 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
305
306 /* Return successful completion. */
307 return(UX_SUCCESS);
308 }
309 }
310 }
311 }
312 }
313 else
314 {
315
316 /* We come here when the current characteristics does not match
317 the one given by the application. We need to check if we had found a match
318 before in which case, this is the one we need to return. */
319 if (previous_match_found == UX_TRUE)
320 {
321
322 /* We return this characteristics. */
323 audio_sampling -> ux_host_class_audio_sampling_characteristics_channels = audio_interface_descriptor.bNrChannels;
324 audio_sampling -> ux_host_class_audio_sampling_characteristics_resolution = audio_interface_descriptor.bBitResolution;
325
326 if (audio_interface_descriptor.bSamFreqType == 0)
327 {
328
329 /* The declaration of frequency is contiguous, so get the minimum and maximum. */
330 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
331 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
332 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
333
334 higher_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 3) |
335 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 4)) << 8 |
336 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 5)) << 16;
337
338 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
339 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = higher_frequency;
340
341 /* Unprotect thread reentry to this instance. */
342 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
343
344 /* Return successful completion. */
345 return(UX_SUCCESS);
346 }
347 else
348 {
349
350 lower_frequency = (ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH) |
351 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 1)) << 8 |
352 ((ULONG) *(descriptor + UX_HOST_CLASS_AUDIO_INTERFACE_DESCRIPTOR_LENGTH + 2)) << 16;
353
354 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_low = lower_frequency;
355 audio_sampling -> ux_host_class_audio_sampling_characteristics_frequency_high = lower_frequency;
356
357 /* Unprotect thread reentry to this instance. */
358 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
359
360 /* Return successful completion. */
361 return(UX_SUCCESS);
362 }
363 }
364 }
365 }
366 }
367 }
368
369 /* Verify the descriptor is still valid. */
370 if (descriptor_length > total_descriptor_length)
371 {
372
373 /* Error trap. */
374 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_DESCRIPTOR_CORRUPTED);
375
376 /* If trace is enabled, insert this event into the trace buffer. */
377 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_DESCRIPTOR_CORRUPTED, descriptor, 0, 0, UX_TRACE_ERRORS, 0, 0)
378
379 /* Unprotect thread reentry to this instance. */
380 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
381
382 return(UX_DESCRIPTOR_CORRUPTED);
383 }
384
385 /* Jump to the next descriptor if we have not reached the end. */
386 descriptor += descriptor_length;
387
388 /* And adjust the length left to parse in the descriptor. */
389 total_descriptor_length -= descriptor_length;
390 }
391
392 /* Unprotect thread reentry to this instance. */
393 _ux_host_mutex_off(&audio -> ux_host_class_audio_mutex);
394
395 /* Error trap. */
396 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_NO_ALTERNATE_SETTING);
397
398 /* If trace is enabled, insert this event into the trace buffer. */
399 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_NO_ALTERNATE_SETTING, audio, 0, 0, UX_TRACE_ERRORS, 0, 0)
400
401 /* We get here when either the report descriptor has a problem or we could
402 not find the right audio device. */
403 return(UX_NO_ALTERNATE_SETTING);
404 }
405
406
407 /**************************************************************************/
408 /* */
409 /* FUNCTION RELEASE */
410 /* */
411 /* _uxe_host_class_audio_streaming_sampling_get PORTABLE C */
412 /* 6.3.0 */
413 /* AUTHOR */
414 /* */
415 /* Chaoqiong Xiao, Microsoft Corporation */
416 /* */
417 /* DESCRIPTION */
418 /* */
419 /* This function checks errors in audio sampling characteristics get */
420 /* function call. */
421 /* */
422 /* INPUT */
423 /* */
424 /* audio Pointer to audio class */
425 /* audio_sampling Pointer to audio sampling */
426 /* */
427 /* OUTPUT */
428 /* */
429 /* Status */
430 /* */
431 /* CALLS */
432 /* */
433 /* _ux_host_class_audio_streaming_sampling_get */
434 /* Get sampling characteristics */
435 /* */
436 /* CALLED BY */
437 /* */
438 /* Application */
439 /* */
440 /* RELEASE HISTORY */
441 /* */
442 /* DATE NAME DESCRIPTION */
443 /* */
444 /* 10-31-2023 Chaoqiong Xiao Initial Version 6.3.0 */
445 /* */
446 /**************************************************************************/
_uxe_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO * audio,UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS * audio_sampling)447 UINT _uxe_host_class_audio_streaming_sampling_get(UX_HOST_CLASS_AUDIO *audio, UX_HOST_CLASS_AUDIO_SAMPLING_CHARACTERISTICS *audio_sampling)
448 {
449
450 /* Sanity checks. */
451 if ((audio == UX_NULL) || (audio_sampling == UX_NULL))
452 return(UX_INVALID_PARAMETER);
453
454 /* Invoke sampling characteristics get function. */
455 return(_ux_host_class_audio_streaming_sampling_get(audio, audio_sampling));
456 }
457