Update log2lines to the latest version. Jan Roeloffzen, bug #4342.
[reactos.git] / reactos / lib / drivers / sound / mmixer / mixer.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/mmixer.c
5 * PURPOSE: Mixer Handling Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9
10
11 #include "priv.h"
12
13 MIXER_STATUS
14 MMixerVerifyContext(
15 IN PMIXER_CONTEXT MixerContext)
16 {
17 if (MixerContext->SizeOfStruct != sizeof(MIXER_CONTEXT))
18 return MM_STATUS_INVALID_PARAMETER;
19
20 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free)
21 return MM_STATUS_INVALID_PARAMETER;
22
23 if (!MixerContext->MixerContext)
24 return MM_STATUS_INVALID_PARAMETER;
25
26 return MM_STATUS_SUCCESS;
27 }
28
29 VOID
30 MMixerFreeMixerInfo(
31 IN PMIXER_CONTEXT MixerContext,
32 IN LPMIXER_INFO MixerInfo)
33 {
34 //UNIMPLEMENTED
35 // FIXME
36 // free all lines
37
38 MixerContext->Free((PVOID)MixerInfo);
39 }
40
41 ULONG
42 MMixerGetFilterPinCount(
43 IN PMIXER_CONTEXT MixerContext,
44 IN HANDLE hMixer)
45 {
46 KSPROPERTY Pin;
47 MIXER_STATUS Status;
48 ULONG NumPins, BytesReturned;
49
50 // setup property request
51 Pin.Flags = KSPROPERTY_TYPE_GET;
52 Pin.Set = KSPROPSETID_Pin;
53 Pin.Id = KSPROPERTY_PIN_CTYPES;
54
55 // query pin count
56 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSPROPERTY), (PVOID)&NumPins, sizeof(ULONG), (PULONG)&BytesReturned);
57
58 // check for success
59 if (Status != MM_STATUS_SUCCESS)
60 return 0;
61
62 return NumPins;
63 }
64
65 ULONG
66 MMixerGetIndexOfGuid(
67 PKSMULTIPLE_ITEM MultipleItem,
68 LPCGUID NodeType)
69 {
70 ULONG Index;
71 LPGUID Guid;
72
73 Guid = (LPGUID)(MultipleItem+1);
74
75 /* iterate through node type array */
76 for(Index = 0; Index < MultipleItem->Count; Index++)
77 {
78 if (IsEqualGUIDAligned(NodeType, Guid))
79 {
80 /* found matching guid */
81 return Index;
82 }
83 Guid++;
84 }
85 return MAXULONG;
86 }
87
88
89 MIXER_STATUS
90 MMixerGetFilterTopologyProperty(
91 IN PMIXER_CONTEXT MixerContext,
92 IN HANDLE hMixer,
93 IN ULONG PropertyId,
94 OUT PKSMULTIPLE_ITEM * OutMultipleItem)
95 {
96 KSPROPERTY Property;
97 PKSMULTIPLE_ITEM MultipleItem;
98 MIXER_STATUS Status;
99 ULONG BytesReturned;
100
101 // setup property request
102 Property.Id = PropertyId;
103 Property.Flags = KSPROPERTY_TYPE_GET;
104 Property.Set = KSPROPSETID_Topology;
105
106 // query for the size
107 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
108
109 if (Status != MM_STATUS_MORE_ENTRIES)
110 return Status;
111
112 // allocate an result buffer
113 MultipleItem = (PKSMULTIPLE_ITEM)MixerContext->Alloc(BytesReturned);
114
115 if (!MultipleItem)
116 {
117 // not enough memory
118 return MM_STATUS_NO_MEMORY;
119 }
120
121 // query again with allocated buffer
122 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)MultipleItem, BytesReturned, &BytesReturned);
123
124 if (Status != MM_STATUS_SUCCESS)
125 {
126 // failed
127 MixerContext->Free((PVOID)MultipleItem);
128 return Status;
129 }
130
131 // store result
132 *OutMultipleItem = MultipleItem;
133
134 // done
135 return Status;
136 }
137
138 MIXER_STATUS
139 MMixerCreateDestinationLine(
140 IN PMIXER_CONTEXT MixerContext,
141 IN LPMIXER_INFO MixerInfo,
142 IN ULONG bInputMixer)
143 {
144 LPMIXERLINE_EXT DestinationLine;
145
146 // allocate a mixer destination line
147 DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
148 if (!MixerInfo)
149 {
150 // no memory
151 return MM_STATUS_NO_MEMORY;
152 }
153
154 /* initialize mixer destination line */
155 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
156 DestinationLine->Line.dwSource = MAXULONG;
157 DestinationLine->Line.dwLineID = DESTINATION_LINE;
158 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
159 DestinationLine->Line.dwUser = 0;
160 DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
161 DestinationLine->Line.cChannels = 2; //FIXME
162 wcscpy(DestinationLine->Line.szShortName, L"Summe"); //FIXME
163 wcscpy(DestinationLine->Line.szName, L"Summe"); //FIXME
164 DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
165 DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
166 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
167 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
168 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
169 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
170
171
172 // insert into mixer info
173 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
174
175 // done
176 return MM_STATUS_SUCCESS;
177 }
178
179 MIXER_STATUS
180 MMixerInitializeFilter(
181 IN PMIXER_CONTEXT MixerContext,
182 IN HANDLE hMixer,
183 IN LPWSTR DeviceName,
184 IN PKSMULTIPLE_ITEM NodeTypes,
185 IN PKSMULTIPLE_ITEM NodeConnections,
186 IN ULONG PinCount,
187 IN ULONG NodeIndex,
188 IN ULONG bInputMixer)
189 {
190 LPMIXER_INFO MixerInfo;
191 MIXER_STATUS Status;
192 ULONG * Pins;
193
194 // allocate a mixer info struct
195 MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
196 if (!MixerInfo)
197 {
198 // no memory
199 return MM_STATUS_NO_MEMORY;
200 }
201
202 // intialize mixer caps */
203 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
204 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
205 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
206 MixerInfo->MixCaps.fdwSupport = 0;
207 MixerInfo->MixCaps.cDestinations = 1;
208 MixerInfo->hMixer = hMixer;
209
210 // initialize line list
211 InitializeListHead(&MixerInfo->LineList);
212
213 /* FIXME find mixer name */
214
215 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer);
216 if (Status != MM_STATUS_SUCCESS)
217 {
218 // failed to create destination line
219 MixerContext->Free(MixerInfo);
220 return Status;
221 }
222
223
224 // now allocate an array which will receive the indices of the pin
225 // which has a ADC / DAC nodetype in its path
226 Pins = (PULONG)MixerContext->Alloc(PinCount * sizeof(ULONG));
227
228 if (!Pins)
229 {
230 // no memory
231 MMixerFreeMixerInfo(MixerContext, MixerInfo);
232 return MM_STATUS_NO_MEMORY;
233 }
234
235
236 //UNIMPLEMENTED
237 // get target pins and find all nodes
238 return MM_STATUS_NOT_IMPLEMENTED;
239 }
240
241 MIXER_STATUS
242 MMixerSetupFilter(
243 IN PMIXER_CONTEXT MixerContext,
244 IN HANDLE hMixer,
245 IN PULONG DeviceCount,
246 IN LPWSTR DeviceName)
247 {
248 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
249 MIXER_STATUS Status;
250 ULONG PinCount;
251 ULONG NodeIndex;
252
253 // get number of pins
254 PinCount = MMixerGetFilterPinCount(MixerContext, hMixer);
255 ASSERT(PinCount);
256
257
258 // get filter node types
259 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
260 if (Status != MM_STATUS_SUCCESS)
261 {
262 // failed
263 return Status;
264 }
265
266 // get filter node connections
267 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
268 if (Status != MM_STATUS_SUCCESS)
269 {
270 // failed
271 MixerContext->Free(NodeTypes);
272 return Status;
273 }
274
275 // check if the filter has an wave out node
276 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
277 if (NodeIndex != MAXULONG)
278 {
279 // it has
280 Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE);
281
282 // check for success
283 if (Status == MM_STATUS_SUCCESS)
284 {
285 // increment mixer count
286 (*DeviceCount)++;
287 }
288
289 }
290
291 // check if the filter has an wave in node
292 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC);
293 if (NodeIndex != MAXULONG)
294 {
295 // it has
296 Status = MMixerInitializeFilter(MixerContext, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE);
297
298 // check for success
299 if (Status == MM_STATUS_SUCCESS)
300 {
301 // increment mixer count
302 (*DeviceCount)++;
303 }
304
305 }
306
307 //free resources
308 MixerContext->Free((PVOID)NodeTypes);
309 MixerContext->Free((PVOID)NodeConnections);
310
311 // done
312 return Status;
313 }
314
315
316 MIXER_STATUS
317 MMixerInitialize(
318 IN PMIXER_CONTEXT MixerContext,
319 IN PMIXER_ENUM EnumFunction,
320 IN PVOID EnumContext)
321 {
322 MIXER_STATUS Status;
323 HANDLE hMixer;
324 ULONG DeviceIndex, Count;
325 LPWSTR DeviceName;
326
327 if (!MixerContext || !EnumFunction || !EnumContext)
328 {
329 // invalid parameter
330 return MM_STATUS_INVALID_PARAMETER;
331 }
332
333 if (!MixerContext->Alloc || !MixerContext->Control || !MixerContext->Free)
334 {
335 // invalid parameter
336 return MM_STATUS_INVALID_PARAMETER;
337 }
338
339
340 // start enumerating all available devices
341 Count = 0;
342 DeviceIndex = 0;
343
344 do
345 {
346 // enumerate a device
347 Status = EnumFunction(EnumContext, DeviceIndex, &DeviceName, &hMixer);
348
349 if (Status != MM_STATUS_SUCCESS)
350 {
351 //check error code
352 if (Status != MM_STATUS_NO_MORE_DEVICES)
353 {
354 // enumeration has failed
355 return Status;
356 }
357 // last device
358 break;
359 }
360
361
362 // increment device index
363 DeviceIndex++;
364
365 Status = MMixerSetupFilter(MixerContext, hMixer, &Count, DeviceName);
366
367 if (Status != MM_STATUS_SUCCESS)
368 break;
369
370 }while(TRUE);
371
372 // done
373 return Status;
374 }
375
376