[SDK] One step further towards ReactOS source code tree restructure: the sdk folder...
[reactos.git] / reactos / sdk / lib / drivers / sound / libusbaudio / libusbaudio.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/libusbaudio/libusbaudio.c
5 * PURPOSE: USB AUDIO Parser
6 * PROGRAMMER: Johannes Anderwald
7 */
8 #include "priv.h"
9
10 GUID NodeTypeMicrophone = {STATIC_KSNODETYPE_MICROPHONE};
11 GUID NodeTypeDesktopMicrophone = {STATIC_KSNODETYPE_DESKTOP_MICROPHONE};
12 GUID NodeTypePersonalMicrophone = {STATIC_KSNODETYPE_PERSONAL_MICROPHONE};
13 GUID NodeTypeOmmniMicrophone = {STATIC_KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE};
14 GUID NodeTypeArrayMicrophone = {STATIC_KSNODETYPE_MICROPHONE_ARRAY};
15 GUID NodeTypeProcessingArrayMicrophone = {STATIC_KSNODETYPE_PROCESSING_MICROPHONE_ARRAY};
16 GUID NodeTypeSpeaker = {STATIC_KSNODETYPE_SPEAKER};
17 GUID NodeTypeHeadphonesSpeaker = {STATIC_KSNODETYPE_HEADPHONES};
18 GUID NodeTypeHMDA = {STATIC_KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO};
19 GUID NodeTypeDesktopSpeaker = {STATIC_KSNODETYPE_DESKTOP_SPEAKER};
20 GUID NodeTypeRoomSpeaker = {STATIC_KSNODETYPE_ROOM_SPEAKER};
21 GUID NodeTypeCommunicationSpeaker = {STATIC_KSNODETYPE_COMMUNICATION_SPEAKER};
22 GUID NodeTypeSubwoofer = {STATIC_KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER};
23 GUID NodeTypeCapture = {STATIC_PINNAME_CAPTURE};
24 GUID NodeTypePlayback = {STATIC_KSCATEGORY_AUDIO};
25
26
27 KSPIN_INTERFACE StandardPinInterface =
28 {
29 {STATIC_KSINTERFACESETID_Standard},
30 KSINTERFACE_STANDARD_STREAMING,
31 0
32 };
33
34 KSPIN_MEDIUM StandardPinMedium =
35 {
36 {STATIC_KSMEDIUMSETID_Standard},
37 KSMEDIUM_TYPE_ANYINSTANCE,
38 0
39 };
40
41 USBAUDIO_STATUS
42 UsbAudio_InitializeContext(
43 IN PUSBAUDIO_CONTEXT Context,
44 IN PUSBAUDIO_ALLOC Alloc,
45 IN PUSBAUDIO_FREE Free,
46 IN PUSBAUDIO_COPY Copy)
47 {
48
49 /* verify parameters */
50 if (!Context || !Alloc || !Free || !Copy)
51 {
52 /* invalid parameter */
53 return UA_STATUS_INVALID_PARAMETER;
54 }
55
56 /* initialize context */
57 Context->Size = sizeof(USBAUDIO_CONTEXT);
58 Context->Alloc = Alloc;
59 Context->Free = Free;
60 Context->Copy = Copy;
61
62 /* done */
63 return UA_STATUS_SUCCESS;
64 }
65
66 LPGUID
67 UsbAudio_GetPinCategoryFromTerminalDescriptor(
68 IN PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor)
69 {
70 if (TerminalDescriptor->wTerminalType == USB_AUDIO_MICROPHONE_TERMINAL_TYPE)
71 return &NodeTypeMicrophone;
72 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_MICROPHONE_TERMINAL_TYPE)
73 return &NodeTypeDesktopMicrophone;
74 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_PERSONAL_MICROPHONE_TERMINAL_TYPE)
75 return &NodeTypePersonalMicrophone;
76 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_OMMNI_MICROPHONE_TERMINAL_TYPE)
77 return &NodeTypeOmmniMicrophone;
78 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_MICROPHONE_TERMINAL_TYPE)
79 return &NodeTypeArrayMicrophone;
80 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_PROCESSING_MICROPHONE_TERMINAL_TYPE)
81 return &NodeTypeProcessingArrayMicrophone;
82
83 /* playback types */
84 if (TerminalDescriptor->wTerminalType == USB_AUDIO_SPEAKER_TERMINAL_TYPE)
85 return &NodeTypeSpeaker;
86 else if (TerminalDescriptor->wTerminalType == USB_HEADPHONES_SPEAKER_TERMINAL_TYPE)
87 return &NodeTypeHeadphonesSpeaker;
88 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_HMDA_TERMINAL_TYPE)
89 return &NodeTypeHMDA;
90 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_SPEAKER_TERMINAL_TYPE)
91 return &NodeTypeDesktopSpeaker;
92 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ROOM_SPEAKER_TERMINAL_TYPE)
93 return &NodeTypeRoomSpeaker;
94 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_COMMUNICATION_SPEAKER_TERMINAL_TYPE)
95 return &NodeTypeCommunicationSpeaker;
96 else if (TerminalDescriptor->wTerminalType == USB_AUDIO_SUBWOOFER_TERMINAL_TYPE)
97 return &NodeTypeSubwoofer;
98
99 if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
100 {
101 if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
102 return &NodeTypeCapture;
103 else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
104 return &NodeTypePlayback;
105
106 }
107 return NULL;
108 }
109
110 USBAUDIO_STATUS
111 UsbAudio_InitPinDescriptor(
112 IN PUCHAR ConfigurationDescriptor,
113 IN ULONG ConfigurationDescriptorLength,
114 IN PKSPIN_DESCRIPTOR_EX PinDescriptor,
115 IN ULONG TerminalCount,
116 IN PUSB_COMMON_DESCRIPTOR * Descriptors,
117 IN ULONG TerminalId)
118 {
119 PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor;
120
121 TerminalDescriptor = UsbAudio_GetTerminalDescriptorById(Descriptors, TerminalCount, TerminalId);
122 if (!TerminalDescriptor)
123 {
124 /* failed to find terminal descriptor */
125 return UA_STATUS_UNSUCCESSFUL;
126 }
127
128 /* init pin descriptor */
129 PinDescriptor->PinDescriptor.InterfacesCount = 1;
130 PinDescriptor->PinDescriptor.Interfaces = &StandardPinInterface;
131 PinDescriptor->PinDescriptor.MediumsCount = 1;
132 PinDescriptor->PinDescriptor.Mediums = &StandardPinMedium;
133 PinDescriptor->PinDescriptor.Category = UsbAudio_GetPinCategoryFromTerminalDescriptor(TerminalDescriptor);
134
135 if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
136 {
137 if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
138 {
139 PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK;
140 PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
141 }
142 else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
143 {
144 PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK;
145 PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
146 }
147
148 /* irp sinks / sources can be instantiated */
149 PinDescriptor->InstancesPossible = 1;
150
151 }
152 else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL)
153 {
154 PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE;
155 PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
156 }
157 else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL)
158 {
159 PinDescriptor->PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE;
160 PinDescriptor->PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT;
161 }
162
163 return UA_STATUS_SUCCESS;
164 }
165
166 USBAUDIO_STATUS
167 UsbAudio_ParseConfigurationDescriptor(
168 IN PUSBAUDIO_CONTEXT Context,
169 IN PUCHAR ConfigurationDescriptor,
170 IN ULONG ConfigurationDescriptorSize)
171 {
172 USBAUDIO_STATUS Status;
173 PKSFILTER_DESCRIPTOR FilterDescriptor;
174 PUSB_COMMON_DESCRIPTOR * Descriptors;
175 PUSB_COMMON_DESCRIPTOR * InterfaceDescriptors;
176 PULONG TerminalIds;
177 ULONG Index, AudioControlInterfaceIndex;
178 ULONG InterfaceCount, DescriptorCount, NewDescriptorCount;
179 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
180
181
182 if (!Context || !ConfigurationDescriptor || !ConfigurationDescriptorSize)
183 {
184 /* invalid parameter */
185 return UA_STATUS_INVALID_PARAMETER;
186 }
187
188 /* count usb interface descriptors */
189 Status = UsbAudio_CountInterfaceDescriptors(ConfigurationDescriptor, ConfigurationDescriptorSize, &InterfaceCount);
190 if (Status != UA_STATUS_SUCCESS || InterfaceCount == 0)
191 {
192 /* invalid parameter */
193 return UA_STATUS_INVALID_PARAMETER;
194 }
195
196 /* construct interface array */
197 Status = UsbAudio_CreateInterfaceDescriptorsArray(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceCount, &InterfaceDescriptors);
198 if (Status != UA_STATUS_SUCCESS)
199 {
200 /* invalid parameter */
201 return UA_STATUS_INVALID_PARAMETER;
202 }
203
204 /* get audio control interface index */
205 AudioControlInterfaceIndex = UsbAudio_GetAudioControlInterfaceIndex(InterfaceDescriptors, InterfaceCount);
206 if (AudioControlInterfaceIndex == MAXULONG)
207 {
208 /* invalid configuration descriptor */
209 Context->Free(InterfaceDescriptors);
210 return UA_STATUS_INVALID_PARAMETER;
211 }
212
213 /* count audio terminal descriptors */
214 Status = UsbAudio_CountAudioDescriptors(ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, AudioControlInterfaceIndex, &DescriptorCount);
215 if (Status != UA_STATUS_SUCCESS || DescriptorCount == 0)
216 {
217 /* invalid parameter */
218 Context->Free(InterfaceDescriptors);
219 return UA_STATUS_INVALID_PARAMETER;
220 }
221
222 /* construct terminal descriptor array */
223 Status = UsbAudio_CreateAudioDescriptorArray(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, InterfaceDescriptors, InterfaceCount, AudioControlInterfaceIndex, DescriptorCount, &Descriptors);
224 if (Status != UA_STATUS_SUCCESS)
225 {
226 /* no memory */
227 Context->Free(InterfaceDescriptors);
228 //DPRINT("[LIBUSBAUDIO] Failed to create descriptor array with %x\n", Status);
229 return Status;
230 }
231
232 /* construct filter */
233 FilterDescriptor = (PKSFILTER_DESCRIPTOR)Context->Alloc(sizeof(KSFILTER_DESCRIPTOR));
234 if (!FilterDescriptor)
235 {
236 /* no memory */
237 Context->Free(InterfaceDescriptors);
238 Context->Free(Descriptors);
239 return UA_STATUS_NO_MEMORY;
240 }
241
242
243 /* construct pin id array */
244 TerminalIds = (PULONG)Context->Alloc(sizeof(ULONG) * DescriptorCount);
245 if (!TerminalIds)
246 {
247 /* no memory */
248 Context->Free(InterfaceDescriptors);
249 Context->Free(FilterDescriptor);
250 Context->Free(Descriptors);
251 return UA_STATUS_NO_MEMORY;
252 }
253
254 /* now assign terminal ids */
255 Status = UsbAudio_AssignTerminalIds(Context, DescriptorCount, Descriptors, TerminalIds, &NewDescriptorCount);
256 if(Status != UA_STATUS_SUCCESS || NewDescriptorCount == 0)
257 {
258 /* failed to initialize */
259 Context->Free(InterfaceDescriptors);
260 Context->Free(FilterDescriptor);
261 Context->Free(Descriptors);
262 Context->Free(TerminalIds);
263 DPRINT1("[LIBUSBAUDIO] Failed to assign terminal ids with %x DescriptorCount %lx\n", Status, DescriptorCount);
264 return UA_STATUS_UNSUCCESSFUL;
265 }
266
267
268 /* init filter */
269 FilterDescriptor->Version = KSFILTER_DESCRIPTOR_VERSION;
270 FilterDescriptor->Flags = 0; /* FIXME */
271 FilterDescriptor->PinDescriptorsCount = NewDescriptorCount;
272 FilterDescriptor->PinDescriptorSize = sizeof(KSPIN_DESCRIPTOR_EX);
273 FilterDescriptor->PinDescriptors = Context->Alloc(sizeof(KSPIN_DESCRIPTOR_EX) * FilterDescriptor->PinDescriptorsCount);
274 if (!FilterDescriptor->PinDescriptors)
275 {
276 /* no memory */
277 Context->Free(InterfaceDescriptors);
278 Context->Free(FilterDescriptor);
279 Context->Free(Descriptors);
280 Context->Free(TerminalIds);
281 return UA_STATUS_NO_MEMORY;
282 }
283
284 /* now init pin properties */
285 for(Index = 0; Index < FilterDescriptor->PinDescriptorsCount; Index++)
286 {
287 /* now init every pin descriptor */
288 Status = UsbAudio_InitPinDescriptor(ConfigurationDescriptor, ConfigurationDescriptorSize, (PKSPIN_DESCRIPTOR_EX)&FilterDescriptor->PinDescriptors[Index], DescriptorCount, Descriptors, TerminalIds[Index]);
289 if (Status != UA_STATUS_SUCCESS)
290 break;
291 }
292
293 if (Status != UA_STATUS_SUCCESS)
294 {
295 /* failed to init pin descriptor */
296 Context->Free(InterfaceDescriptors);
297 Context->Free((PVOID)FilterDescriptor->PinDescriptors);
298 Context->Free(FilterDescriptor);
299 Context->Free(Descriptors);
300 Context->Free(TerminalIds);
301 DPRINT1("[LIBUSBAUDIO] Failed to init pin with %x\n", Status);
302 return Status;
303 }
304
305
306 /* now assign data ranges to the pins */
307 for(Index = 0; Index < InterfaceCount; Index++)
308 {
309 /* get descriptor */
310 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)InterfaceDescriptors[Index];
311
312 /* sanity check */
313 ASSERT(InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
314 DPRINT1("InterfaceNumber %d bInterfaceClass %x bInterfaceSubClass %x\n", InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bInterfaceClass, InterfaceDescriptor->bInterfaceSubClass);
315
316 if (InterfaceDescriptor->bInterfaceClass != 0x01 && InterfaceDescriptor->bInterfaceSubClass != 0x02)
317 continue;
318
319 /* assign data ranges */
320 Status = UsbAudio_AssignDataRanges(Context, ConfigurationDescriptor, ConfigurationDescriptorSize, FilterDescriptor, InterfaceDescriptors, InterfaceCount, Index, TerminalIds);
321 if (Status != UA_STATUS_SUCCESS)
322 break;
323 }
324
325 if (Status != UA_STATUS_SUCCESS)
326 {
327 /* failed to init pin descriptor */
328 Context->Free(InterfaceDescriptors);
329 Context->Free((PVOID)FilterDescriptor->PinDescriptors);
330 Context->Free(FilterDescriptor);
331 Context->Free(Descriptors);
332 Context->Free(TerminalIds);
333 return Status;
334 }
335
336
337
338 if (Status != UA_STATUS_SUCCESS)
339 {
340 /* failed to init pin descriptor */
341 Context->Free(InterfaceDescriptors);
342 Context->Free((PVOID)FilterDescriptor->PinDescriptors);
343 Context->Free(FilterDescriptor);
344 Context->Free(Descriptors);
345 Context->Free(TerminalIds);
346 return Status;
347 }
348
349 Context->Context = FilterDescriptor;
350 return Status;
351
352 }
353
354 USBAUDIO_STATUS
355 UsbAudio_GetFilter(
356 IN PUSBAUDIO_CONTEXT Context,
357 OUT PVOID * OutFilterDescriptor)
358 {
359 if (!OutFilterDescriptor)
360 return UA_STATUS_INVALID_PARAMETER;
361
362 *OutFilterDescriptor = Context->Context;
363 return UA_STATUS_SUCCESS;
364 }