[MMIXER]
[reactos.git] / reactos / lib / drivers / sound / mmixer / controls.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel Streaming
4 * FILE: lib/drivers/sound/mmixer/controls.c
5 * PURPOSE: Mixer Control Iteration Functions
6 * PROGRAMMER: Johannes Anderwald
7 */
8
9 #include "priv.h"
10
11 MIXER_STATUS
12 MMixerGetTargetPinsByNodeConnectionIndex(
13 IN PMIXER_CONTEXT MixerContext,
14 IN PKSMULTIPLE_ITEM NodeConnections,
15 IN PKSMULTIPLE_ITEM NodeTypes,
16 IN ULONG bUpDirection,
17 IN ULONG NodeConnectionIndex,
18 OUT PULONG Pins)
19 {
20 PKSTOPOLOGY_CONNECTION Connection;
21 ULONG PinId, NodeConnectionCount, Index;
22 PULONG NodeConnection;
23 MIXER_STATUS Status;
24
25
26 /* sanity check */
27 ASSERT(NodeConnectionIndex < NodeConnections->Count);
28
29 Connection = (PKSTOPOLOGY_CONNECTION)(NodeConnections + 1);
30
31 //DPRINT("FromNode %u FromNodePin %u -> ToNode %u ToNodePin %u\n", Connection[NodeConnectionIndex].FromNode, Connection[NodeConnectionIndex].FromNodePin, Connection[NodeConnectionIndex].ToNode, Connection[NodeConnectionIndex].ToNodePin );
32
33 if ((Connection[NodeConnectionIndex].ToNode == KSFILTER_NODE && bUpDirection == FALSE) ||
34 (Connection[NodeConnectionIndex].FromNode == KSFILTER_NODE && bUpDirection == TRUE))
35 {
36 /* iteration stops here */
37 if (bUpDirection)
38 PinId = Connection[NodeConnectionIndex].FromNodePin;
39 else
40 PinId = Connection[NodeConnectionIndex].ToNodePin;
41
42 //DPRINT("GetTargetPinsByNodeIndex FOUND Target Pin %u Parsed %u\n", PinId, Pins[PinId]);
43
44 /* mark pin index as a target pin */
45 Pins[PinId] = TRUE;
46 return MM_STATUS_SUCCESS;
47 }
48
49 // get all node indexes referenced by that node
50 if (bUpDirection)
51 {
52 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].FromNode, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
53 }
54 else
55 {
56 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Connection[NodeConnectionIndex].ToNode, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
57 }
58
59 if (Status == MM_STATUS_SUCCESS)
60 {
61 for(Index = 0; Index < NodeConnectionCount; Index++)
62 {
63 // iterate recursively into the nodes
64 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Pins);
65 ASSERT(Status == MM_STATUS_SUCCESS);
66 }
67 // free node connection indexes
68 MixerContext->Free(NodeConnection);
69 }
70
71 return Status;
72 }
73
74 MIXER_STATUS
75 MMixerGetControlsFromPinByConnectionIndex(
76 IN PMIXER_CONTEXT MixerContext,
77 IN PKSMULTIPLE_ITEM NodeConnections,
78 IN PKSMULTIPLE_ITEM NodeTypes,
79 IN ULONG bUpDirection,
80 IN ULONG NodeConnectionIndex,
81 OUT PULONG Nodes)
82 {
83 PKSTOPOLOGY_CONNECTION CurConnection;
84 LPGUID NodeType;
85 ULONG NodeIndex;
86 MIXER_STATUS Status;
87 ULONG NodeConnectionCount, Index;
88 PULONG NodeConnection;
89
90
91 /* get current connection */
92 CurConnection = MMixerGetConnectionByIndex(NodeConnections, NodeConnectionIndex);
93
94 if (bUpDirection)
95 NodeIndex = CurConnection->FromNode;
96 else
97 NodeIndex = CurConnection->ToNode;
98
99 /* get target node type of current connection */
100 NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
101
102 if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_SUM) || IsEqualGUIDAligned(NodeType, &KSNODETYPE_MUX))
103 {
104 if (bUpDirection)
105 {
106 /* add the sum / mux node to destination line */
107 Nodes[NodeIndex] = TRUE;
108 }
109
110 return MM_STATUS_SUCCESS;
111 }
112
113 /* now add the node */
114 Nodes[NodeIndex] = TRUE;
115
116
117 /* get all node indexes referenced by that node */
118 if (bUpDirection)
119 {
120 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, FALSE, &NodeConnectionCount, &NodeConnection);
121 }
122 else
123 {
124 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, NodeIndex, TRUE, TRUE, &NodeConnectionCount, &NodeConnection);
125 }
126
127 if (Status != MM_STATUS_SUCCESS)
128 {
129 for(Index = 0; Index < NodeConnectionCount; Index++)
130 {
131 /* iterate recursively into the nodes */
132 Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
133 ASSERT(Status == MM_STATUS_SUCCESS);
134 }
135 /* free node connection indexes */
136 MixerContext->Free(NodeConnection);
137 }
138
139 return Status;
140 }
141
142 MIXER_STATUS
143 MMixerAddMixerControl(
144 IN PMIXER_CONTEXT MixerContext,
145 IN LPMIXER_INFO MixerInfo,
146 IN HANDLE hDevice,
147 IN PKSMULTIPLE_ITEM NodeTypes,
148 IN ULONG NodeIndex,
149 IN LPMIXERLINE_EXT MixerLine,
150 OUT LPMIXERCONTROLW MixerControl)
151 {
152 LPGUID NodeType;
153 KSP_NODE Node;
154 ULONG BytesReturned;
155 MIXER_STATUS Status;
156 LPWSTR Name;
157
158 /* initialize mixer control */
159 MixerControl->cbStruct = sizeof(MIXERCONTROLW);
160 MixerControl->dwControlID = MixerInfo->ControlId;
161
162 /* get node type */
163 NodeType = MMixerGetNodeType(NodeTypes, NodeIndex);
164 /* store control type */
165 MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
166
167 MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; //FIXME
168 MixerControl->cMultipleItems = 0; //FIXME
169
170 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
171 {
172 MixerControl->Bounds.dwMinimum = 0;
173 MixerControl->Bounds.dwMaximum = 1;
174 }
175 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
176 {
177 MixerControl->Bounds.dwMinimum = 0;
178 MixerControl->Bounds.dwMaximum = 0xFFFF;
179 MixerControl->Metrics.cSteps = 0xC0; //FIXME
180 }
181
182 /* setup request to retrieve name */
183 Node.NodeId = NodeIndex;
184 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
185 Node.Property.Flags = KSPROPERTY_TYPE_GET;
186 Node.Property.Set = KSPROPSETID_Topology;
187 Node.Reserved = 0;
188
189 /* get node name size */
190 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
191
192 if (Status == MM_STATUS_MORE_ENTRIES)
193 {
194 ASSERT(BytesReturned != 0);
195 Name = (LPWSTR)MixerContext->Alloc(BytesReturned);
196 if (!Name)
197 {
198 /* not enough memory */
199 return MM_STATUS_NO_MEMORY;
200 }
201
202 /* get node name */
203 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
204 if (Status != MM_STATUS_SUCCESS)
205 {
206 MixerContext->Copy(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
207 MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
208
209 MixerContext->Copy(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
210 MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
211 }
212
213 /* free name buffer */
214 MixerContext->Free(Name);
215 }
216
217 MixerInfo->ControlId++;
218 #if 0
219 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
220 {
221 KSNODEPROPERTY Property;
222 ULONG PinId = 2;
223
224 /* setup the request */
225 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
226
227 Property.NodeId = NodeIndex;
228 Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
229 Property.Property.Flags = KSPROPERTY_TYPE_SET;
230 Property.Property.Set = KSPROPSETID_Audio;
231
232 /* get node volume level info */
233 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
234
235 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
236 //DbgBreakPoint();
237 }else
238 #endif
239 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
240 {
241 KSNODEPROPERTY_AUDIO_CHANNEL Property;
242 ULONG Length;
243 PKSPROPERTY_DESCRIPTION Desc;
244 PKSPROPERTY_MEMBERSHEADER Members;
245 PKSPROPERTY_STEPPING_LONG Range;
246
247 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
248 Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
249 ASSERT(Desc);
250
251 /* setup the request */
252 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
253
254 Property.NodeProperty.NodeId = NodeIndex;
255 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
256 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
257 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
258
259 /* get node volume level info */
260 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
261
262 if (Status == MM_STATUS_SUCCESS)
263 {
264 LPMIXERVOLUME_DATA VolumeData;
265 ULONG Steps, MaxRange, Index;
266 LONG Value;
267
268 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
269 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
270
271 DPRINT("NodeIndex %u Range Min %d Max %d Steps %x UMin %x UMax %x\n", NodeIndex, Range->Bounds.SignedMinimum, Range->Bounds.SignedMaximum, Range->SteppingDelta, Range->Bounds.UnsignedMinimum, Range->Bounds.UnsignedMaximum);
272
273 MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum;
274
275 if (MaxRange)
276 {
277 ASSERT(MaxRange);
278 VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA));
279 if (!VolumeData)
280 return MM_STATUS_NO_MEMORY;
281
282 Steps = MaxRange / Range->SteppingDelta + 1;
283
284 /* store mixer control info there */
285 VolumeData->Header.dwControlID = MixerControl->dwControlID;
286 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
287 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
288 VolumeData->SteppingDelta = Range->SteppingDelta;
289 VolumeData->ValuesCount = Steps;
290 VolumeData->InputSteppingDelta = 0x10000 / Steps;
291
292 VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps);
293 if (!VolumeData->Values)
294 {
295 MixerContext->Free(Desc);
296 MixerContext->Free(VolumeData);
297
298 return MM_STATUS_NO_MEMORY;
299 }
300
301 Value = Range->Bounds.SignedMinimum;
302 for(Index = 0; Index < Steps; Index++)
303 {
304 VolumeData->Values[Index] = Value;
305 Value += Range->SteppingDelta;
306 }
307 InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
308 }
309 }
310 MixerContext->Free(Desc);
311 }
312
313
314 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
315 return MM_STATUS_SUCCESS;
316 }
317
318 MIXER_STATUS
319 MMixerAddMixerSourceLine(
320 IN PMIXER_CONTEXT MixerContext,
321 IN OUT LPMIXER_INFO MixerInfo,
322 IN HANDLE hDevice,
323 IN PKSMULTIPLE_ITEM NodeConnections,
324 IN PKSMULTIPLE_ITEM NodeTypes,
325 IN ULONG PinId,
326 IN ULONG bBridgePin,
327 IN ULONG bTargetPin)
328 {
329 LPMIXERLINE_EXT SrcLine, DstLine;
330 MIXER_STATUS Status;
331 KSP_PIN Pin;
332 LPWSTR PinName;
333 GUID NodeType;
334 ULONG BytesReturned, ControlCount, Index;
335 PULONG Nodes;
336
337 if (!bTargetPin)
338 {
339 /* allocate src mixer line */
340 SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
341
342 if (!SrcLine)
343 return MM_STATUS_NO_MEMORY;
344
345 /* zero struct */
346 RtlZeroMemory(SrcLine, sizeof(MIXERLINE_EXT));
347
348 }
349 else
350 {
351 ASSERT(!IsListEmpty(&MixerInfo->LineList));
352 SrcLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
353 }
354
355 /* get destination line */
356 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DESTINATION_LINE);
357 ASSERT(DstLine);
358
359
360 if (!bTargetPin)
361 {
362 /* initialize mixer src line */
363 SrcLine->hDevice = hDevice;
364 SrcLine->PinId = PinId;
365 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
366
367 /* initialize mixer destination line */
368 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
369 SrcLine->Line.dwDestination = 0;
370 SrcLine->Line.dwSource = DstLine->Line.cConnections;
371 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * 0x10000);
372 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
373 SrcLine->Line.dwUser = 0;
374 SrcLine->Line.cChannels = DstLine->Line.cChannels;
375 SrcLine->Line.cConnections = 0;
376 SrcLine->Line.Target.dwType = 1;
377 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
378 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
379 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
380 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
381 InitializeListHead(&SrcLine->LineControlsExtraData);
382 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
383
384 }
385
386 /* allocate a node arrary */
387 Nodes = (PULONG)MixerContext->Alloc(sizeof(ULONG) * NodeTypes->Count);
388
389 if (!Nodes)
390 {
391 /* not enough memory */
392 if (!bTargetPin)
393 {
394 MixerContext->Free(SrcLine);
395 }
396 return MM_STATUS_NO_MEMORY;
397 }
398
399 Status = MMixerGetControlsFromPin(MixerContext, NodeConnections, NodeTypes, PinId, bTargetPin, Nodes);
400 if (Status != MM_STATUS_SUCCESS)
401 {
402 /* something went wrong */
403 if (!bTargetPin)
404 {
405 MixerContext->Free(SrcLine);
406 }
407 MixerContext->Free(Nodes);
408 return Status;
409 }
410
411 /* now count all nodes controlled by that pin */
412 ControlCount = 0;
413 for(Index = 0; Index < NodeTypes->Count; Index++)
414 {
415 if (Nodes[Index])
416 {
417 // found a node
418 ControlCount++;
419 }
420 }
421
422 /* now allocate the line controls */
423 if (ControlCount)
424 {
425 SrcLine->LineControls = (LPMIXERCONTROLW)MixerContext->Alloc(sizeof(MIXERCONTROLW) * ControlCount);
426
427 if (!SrcLine->LineControls)
428 {
429 /* no memory available */
430 if (!bTargetPin)
431 {
432 MixerContext->Free(SrcLine);
433 }
434 MixerContext->Free(Nodes);
435 return MM_STATUS_NO_MEMORY;
436 }
437
438 SrcLine->NodeIds = (PULONG)MixerContext->Alloc(sizeof(ULONG) * ControlCount);
439 if (!SrcLine->NodeIds)
440 {
441 /* no memory available */
442 MixerContext->Free(SrcLine->LineControls);
443 if (!bTargetPin)
444 {
445 MixerContext->Free(SrcLine);
446 }
447 MixerContext->Free(Nodes);
448 return MM_STATUS_NO_MEMORY;
449 }
450
451 /* zero line controls */
452 RtlZeroMemory(SrcLine->LineControls, sizeof(MIXERCONTROLW) * ControlCount);
453 RtlZeroMemory(SrcLine->NodeIds, sizeof(ULONG) * ControlCount);
454
455 ControlCount = 0;
456 for(Index = 0; Index < NodeTypes->Count; Index++)
457 {
458 if (Nodes[Index])
459 {
460 /* store the node index for retrieving / setting details */
461 SrcLine->NodeIds[ControlCount] = Index;
462
463 Status = MMixerAddMixerControl(MixerContext, MixerInfo, hDevice, NodeTypes, Index, SrcLine, &SrcLine->LineControls[ControlCount]);
464 if (Status == MM_STATUS_SUCCESS)
465 {
466 /* increment control count on success */
467 ControlCount++;
468 }
469 }
470 }
471 /* store control count */
472 SrcLine->Line.cControls = ControlCount;
473 }
474
475 /* release nodes array */
476 MixerContext->Free(Nodes);
477
478 /* get pin category */
479 Pin.PinId = PinId;
480 Pin.Reserved = 0;
481 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
482 Pin.Property.Set = KSPROPSETID_Pin;
483 Pin.Property.Id = KSPROPERTY_PIN_CATEGORY;
484
485 /* try get pin category */
486 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)&NodeType, sizeof(GUID), &BytesReturned);
487 if (Status != MM_STATUS_SUCCESS)
488 {
489 //FIXME
490 //map component type
491 }
492
493 /* retrieve pin name */
494 Pin.PinId = PinId;
495 Pin.Reserved = 0;
496 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
497 Pin.Property.Set = KSPROPSETID_Pin;
498 Pin.Property.Id = KSPROPERTY_PIN_NAME;
499
500 /* try get pin name size */
501 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
502
503 if (Status == MM_STATUS_MORE_ENTRIES)
504 {
505 PinName = (LPWSTR)MixerContext->Alloc(BytesReturned);
506 if (PinName)
507 {
508 /* try get pin name */
509 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (LPVOID)PinName, BytesReturned, &BytesReturned);
510
511 if (Status == MM_STATUS_SUCCESS)
512 {
513 MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
514 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
515
516 MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
517 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
518 }
519 MixerContext->Free(PinName);
520 }
521 }
522
523 /* insert src line */
524 if (!bTargetPin)
525 {
526 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
527 DstLine->Line.cConnections++;
528 }
529
530 return MM_STATUS_SUCCESS;
531 }
532
533 MIXER_STATUS
534 MMixerCreateDestinationLine(
535 IN PMIXER_CONTEXT MixerContext,
536 IN LPMIXER_INFO MixerInfo,
537 IN ULONG bInputMixer,
538 IN LPWSTR LineName)
539 {
540 LPMIXERLINE_EXT DestinationLine;
541
542 // allocate a mixer destination line
543 DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
544 if (!MixerInfo)
545 {
546 // no memory
547 return MM_STATUS_NO_MEMORY;
548 }
549
550 /* initialize mixer destination line */
551 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
552 DestinationLine->Line.dwSource = MAXULONG;
553 DestinationLine->Line.dwLineID = DESTINATION_LINE;
554 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
555 DestinationLine->Line.dwUser = 0;
556 DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
557 DestinationLine->Line.cChannels = 2; //FIXME
558
559 if (LineName)
560 {
561 wcscpy(DestinationLine->Line.szShortName, LineName);
562 wcscpy(DestinationLine->Line.szName, LineName);
563 }
564 else
565 {
566 /* FIXME no name was found for pin */
567 wcscpy(DestinationLine->Line.szShortName, L"Summe");
568 wcscpy(DestinationLine->Line.szName, L"Summe");
569 }
570
571 DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
572 DestinationLine->Line.Target.dwDeviceID = !bInputMixer;
573 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
574 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
575 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
576 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
577
578
579 // insert into mixer info
580 InsertHeadList(&MixerInfo->LineList, &DestinationLine->Entry);
581
582 // done
583 return MM_STATUS_SUCCESS;
584 }
585
586 MIXER_STATUS
587 MMixerGetControlsFromPin(
588 IN PMIXER_CONTEXT MixerContext,
589 IN PKSMULTIPLE_ITEM NodeConnections,
590 IN PKSMULTIPLE_ITEM NodeTypes,
591 IN ULONG PinId,
592 IN ULONG bUpDirection,
593 OUT PULONG Nodes)
594 {
595 ULONG NodeConnectionCount, Index;
596 MIXER_STATUS Status;
597 PULONG NodeConnection;
598
599 /* sanity check */
600 ASSERT(PinId != (ULONG)-1);
601
602 /* get all node indexes referenced by that pin */
603 if (bUpDirection)
604 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, FALSE, &NodeConnectionCount, &NodeConnection);
605 else
606 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, PinId, FALSE, TRUE, &NodeConnectionCount, &NodeConnection);
607
608 for(Index = 0; Index < NodeConnectionCount; Index++)
609 {
610 /* get all associated controls */
611 Status = MMixerGetControlsFromPinByConnectionIndex(MixerContext, NodeConnections, NodeTypes, bUpDirection, NodeConnection[Index], Nodes);
612 }
613
614 MixerContext->Free(NodeConnection);
615
616 return Status;
617 }
618
619
620
621
622 MIXER_STATUS
623 MMixerAddMixerSourceLines(
624 IN PMIXER_CONTEXT MixerContext,
625 IN OUT LPMIXER_INFO MixerInfo,
626 IN HANDLE hDevice,
627 IN PKSMULTIPLE_ITEM NodeConnections,
628 IN PKSMULTIPLE_ITEM NodeTypes,
629 IN ULONG PinsCount,
630 IN ULONG BridgePinIndex,
631 IN ULONG TargetPinIndex,
632 IN PULONG Pins)
633 {
634 ULONG Index;
635
636 for(Index = PinsCount; Index > 0; Index--)
637 {
638 DPRINT("MMixerAddMixerSourceLines Index %lu Pin %lu\n", Index-1, Pins[Index-1]);
639 if (Pins[Index-1])
640 {
641 MMixerAddMixerSourceLine(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, Index-1, (Index -1 == BridgePinIndex), (Index -1 == TargetPinIndex));
642 }
643 }
644 return MM_STATUS_SUCCESS;
645 }
646
647
648 MIXER_STATUS
649 MMixerHandlePhysicalConnection(
650 IN PMIXER_CONTEXT MixerContext,
651 IN OUT LPMIXER_INFO MixerInfo,
652 IN ULONG bInput,
653 IN PKSPIN_PHYSICALCONNECTION OutConnection)
654 {
655 PULONG PinsRef = NULL, PinConnectionIndex = NULL, PinsSrcRef;
656 ULONG PinsRefCount, Index, PinConnectionIndexCount;
657 MIXER_STATUS Status;
658 HANDLE hDevice = NULL;
659 PKSMULTIPLE_ITEM NodeTypes = NULL;
660 PKSMULTIPLE_ITEM NodeConnections = NULL;
661 PULONG MixerControls;
662 ULONG MixerControlsCount;
663
664
665 // open the connected filter
666 Status = MixerContext->Open(OutConnection->SymbolicLinkName, &hDevice);
667 if (Status != MM_STATUS_SUCCESS)
668 {
669 DPRINT("OpenDevice failed with %x\n", Status);
670 return Status;
671 }
672
673 // get connected filter pin count
674 PinsRefCount = MMixerGetFilterPinCount(MixerContext, hDevice);
675 ASSERT(PinsRefCount);
676
677 PinsRef = (PULONG)MixerContext->Alloc(sizeof(ULONG) * PinsRefCount);
678 if (!PinsRef)
679 {
680 // no memory
681 MixerContext->Close(hDevice);
682 return MM_STATUS_UNSUCCESSFUL;
683 }
684
685 // get topology node types
686 Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
687 if (Status != MM_STATUS_SUCCESS)
688 {
689 MixerContext->Close(hDevice);
690 MixerContext->Free(PinsRef);
691 return Status;
692 }
693
694 // get topology connections
695 Status = MMixerGetFilterTopologyProperty(MixerContext, hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
696 if (Status != MM_STATUS_SUCCESS)
697 {
698 MixerContext->Close(hDevice);
699 MixerContext->Free(PinsRef);
700 MixerContext->Free(NodeTypes);
701 return Status;
702 }
703 // gets connection index of the bridge pin which connects to a node
704 DPRINT("Pin %lu\n", OutConnection->Pin);
705
706 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, OutConnection->Pin, FALSE, !bInput, &PinConnectionIndexCount, &PinConnectionIndex);
707 if (Status != MM_STATUS_SUCCESS)
708 {
709 MixerContext->Close(hDevice);
710 MixerContext->Free(PinsRef);
711 MixerContext->Free(NodeTypes);
712 MixerContext->Free(NodeConnections);
713 return Status;
714 }
715
716 /* there should be no split in the bride pin */
717 ASSERT(PinConnectionIndexCount == 1);
718
719 /* find all target pins of this connection */
720 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, FALSE, PinConnectionIndex[0], PinsRef);
721 if (Status != MM_STATUS_SUCCESS)
722 {
723 MixerContext->Close(hDevice);
724 MixerContext->Free(PinsRef);
725 MixerContext->Free(NodeTypes);
726 MixerContext->Free(NodeConnections);
727 MixerContext->Free(PinConnectionIndex);
728 return Status;
729 }
730
731 for(Index = 0; Index < PinsRefCount; Index++)
732 {
733 DPRINT("PinsRefCount %lu Index %lu Value %lu\n", PinsRefCount, Index, PinsRef[Index]);
734 if (PinsRef[Index])
735 {
736 // found a target pin, now get all references
737 Status = MMixerGetNodeIndexes(MixerContext, NodeConnections, Index, FALSE, FALSE, &MixerControlsCount, &MixerControls);
738 if (Status != MM_STATUS_SUCCESS)
739 {
740 DPRINT("MMixerGetNodeIndexes failed with %u\n", Status);
741 break;
742 }
743
744 /* sanity check */
745 ASSERT(MixerControlsCount == 1);
746
747 PinsSrcRef = (PULONG)MixerContext->Alloc(PinsRefCount * sizeof(ULONG));
748 if (!PinsSrcRef)
749 {
750 /* no memory */
751 MixerContext->Close(hDevice);
752 MixerContext->Free(PinsRef);
753 MixerContext->Free(NodeTypes);
754 MixerContext->Free(NodeConnections);
755 MixerContext->Free(PinConnectionIndex);
756 MixerContext->Free(MixerControls);
757 return MM_STATUS_NO_MEMORY;
758 }
759
760 // now get all connected source pins
761 Status = MMixerGetTargetPinsByNodeConnectionIndex(MixerContext, NodeConnections, NodeTypes, TRUE, MixerControls[0], PinsSrcRef);
762 if (Status != MM_STATUS_SUCCESS)
763 {
764 // failed */
765 MixerContext->Close(hDevice);
766 MixerContext->Free(PinsRef);
767 MixerContext->Free(NodeTypes);
768 MixerContext->Free(NodeConnections);
769 MixerContext->Free(PinConnectionIndex);
770 MixerContext->Free(MixerControls);
771 MixerContext->Free(PinsSrcRef);
772 return Status;
773 }
774
775 /* add pins from target line */
776 if (!bInput)
777 {
778 // dont add bridge pin for input mixers
779 PinsSrcRef[Index] = TRUE;
780 PinsSrcRef[OutConnection->Pin] = TRUE;
781 }
782 PinsSrcRef[OutConnection->Pin] = TRUE;
783
784 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, hDevice, NodeConnections, NodeTypes, PinsRefCount, OutConnection->Pin, Index, PinsSrcRef);
785
786 MixerContext->Free(MixerControls);
787 MixerContext->Free(PinsSrcRef);
788 }
789 }
790
791 return Status;
792 }
793
794
795 MIXER_STATUS
796 MMixerInitializeFilter(
797 IN PMIXER_CONTEXT MixerContext,
798 IN PMIXER_LIST MixerList,
799 IN HANDLE hMixer,
800 IN LPWSTR DeviceName,
801 IN PKSMULTIPLE_ITEM NodeTypes,
802 IN PKSMULTIPLE_ITEM NodeConnections,
803 IN ULONG PinCount,
804 IN ULONG NodeIndex,
805 IN ULONG bInputMixer)
806 {
807 LPMIXER_INFO MixerInfo;
808 MIXER_STATUS Status;
809 PKSPIN_PHYSICALCONNECTION OutConnection;
810 ULONG Index;
811 ULONG * Pins;
812 ULONG bUsed;
813 ULONG BytesReturned;
814 KSP_PIN Pin;
815 LPWSTR Buffer = NULL;
816
817 // allocate a mixer info struct
818 MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
819 if (!MixerInfo)
820 {
821 // no memory
822 return MM_STATUS_NO_MEMORY;
823 }
824
825 // intialize mixer caps */
826 MixerInfo->MixCaps.wMid = MM_MICROSOFT; //FIXME
827 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; //FIXME
828 MixerInfo->MixCaps.vDriverVersion = 1; //FIXME
829 MixerInfo->MixCaps.fdwSupport = 0;
830 MixerInfo->MixCaps.cDestinations = 1;
831 MixerInfo->hMixer = hMixer;
832
833 // initialize line list
834 InitializeListHead(&MixerInfo->LineList);
835
836 /* FIXME find mixer name */
837
838 // now allocate an array which will receive the indices of the pin
839 // which has a ADC / DAC nodetype in its path
840 Pins = (PULONG)MixerContext->Alloc(PinCount * sizeof(ULONG));
841
842 if (!Pins)
843 {
844 // no memory
845 MMixerFreeMixerInfo(MixerContext, MixerInfo);
846 return MM_STATUS_NO_MEMORY;
847 }
848
849 // now get the target pins of the ADC / DAC node
850 Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, !bInputMixer, Pins, PinCount);
851
852 for(Index = 0; Index < PinCount; Index++)
853 {
854 if (Pins[Index])
855 {
856 /* retrieve pin name */
857 Pin.PinId = Index;
858 Pin.Reserved = 0;
859 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
860 Pin.Property.Set = KSPROPSETID_Pin;
861 Pin.Property.Id = KSPROPERTY_PIN_NAME;
862
863 /* try get pin name size */
864 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
865
866 if (Status == MM_STATUS_MORE_ENTRIES)
867 {
868 Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
869 if (Buffer)
870 {
871 /* try get pin name */
872 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
873 if (Status != MM_STATUS_SUCCESS)
874 {
875 MixerContext->Free((PVOID)Buffer);
876 Buffer = NULL;
877 }
878 else
879 {
880 // found name, done
881 break;
882 }
883 }
884 }
885 }
886 }
887
888 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInputMixer, Buffer);
889
890 if (Buffer)
891 {
892 // free name
893 MixerContext->Free(Buffer);
894 }
895
896 if (Status != MM_STATUS_SUCCESS)
897 {
898 // failed to create destination line
899 MixerContext->Free(MixerInfo);
900 MixerContext->Free(Pins);
901
902 return Status;
903 }
904
905
906
907 RtlZeroMemory(Pins, sizeof(ULONG) * PinCount);
908 // now get the target pins of the ADC / DAC node
909 Status = MMixerGetTargetPins(MixerContext, NodeTypes, NodeConnections, NodeIndex, bInputMixer, Pins, PinCount);
910
911 if (Status != MM_STATUS_SUCCESS)
912 {
913 // failed to locate target pins
914 MixerContext->Free(Pins);
915 MMixerFreeMixerInfo(MixerContext, MixerInfo);
916 DPRINT("MMixerGetTargetPins failed with %u\n", Status);
917 return Status;
918 }
919
920 // filter hasnt been used
921 bUsed = FALSE;
922
923 // now check all pins and generate new lines for destination lines
924 for(Index = 0; Index < PinCount; Index++)
925 {
926 DPRINT("Index %lu TargetPin %lu\n", Index, Pins[Index]);
927 // is the current index a target pin
928 if (Pins[Index])
929 {
930 // check if the pin has a physical connection
931 Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Index, &OutConnection);
932 if (Status == MM_STATUS_SUCCESS)
933 {
934 // the pin has a physical connection
935 Status = MMixerHandlePhysicalConnection(MixerContext, MixerInfo, bInputMixer, OutConnection);
936 DPRINT("MMixerHandlePhysicalConnection status %u\n", Status);
937 MixerContext->Free(OutConnection);
938 bUsed = TRUE;
939 }
940 else
941 {
942 // filter exposes the topology on the same filter
943 MMixerAddMixerSourceLine(MixerContext, MixerInfo, hMixer, NodeConnections, NodeTypes, Index, FALSE, FALSE);
944 bUsed = TRUE;
945 }
946 }
947 }
948 MixerContext->Free(Pins);
949
950 if (bUsed)
951 {
952 // store mixer info in list
953 if (!bInputMixer && MixerList->MixerListCount == 1)
954 {
955 //FIXME preferred device should be inserted at front
956 //windows always inserts output mixer in front
957 InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
958 }
959 else
960 {
961 InsertTailList(&MixerList->MixerList, &MixerInfo->Entry);
962 }
963 MixerList->MixerListCount++;
964 DPRINT("New MixerCount %lu\n", MixerList->MixerListCount);
965 }
966 else
967 {
968 // failed to create a mixer topology
969 MMixerFreeMixerInfo(MixerContext, MixerInfo);
970 }
971
972 // done
973 return Status;
974 }
975
976 MIXER_STATUS
977 MMixerSetupFilter(
978 IN PMIXER_CONTEXT MixerContext,
979 IN PMIXER_LIST MixerList,
980 IN HANDLE hMixer,
981 IN PULONG DeviceCount,
982 IN LPWSTR DeviceName)
983 {
984 PKSMULTIPLE_ITEM NodeTypes, NodeConnections;
985 MIXER_STATUS Status;
986 ULONG PinCount;
987 ULONG NodeIndex;
988
989 // get number of pins
990 PinCount = MMixerGetFilterPinCount(MixerContext, hMixer);
991 ASSERT(PinCount);
992 DPRINT("NumOfPins: %lu\n", PinCount);
993
994 // get filter node types
995 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
996 if (Status != MM_STATUS_SUCCESS)
997 {
998 // failed
999 return Status;
1000 }
1001
1002 // get filter node connections
1003 Status = MMixerGetFilterTopologyProperty(MixerContext, hMixer, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
1004 if (Status != MM_STATUS_SUCCESS)
1005 {
1006 // failed
1007 MixerContext->Free(NodeTypes);
1008 return Status;
1009 }
1010
1011 // check if the filter has an wave out node
1012 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_DAC);
1013 if (NodeIndex != MAXULONG)
1014 {
1015 // it has
1016 Status = MMixerInitializeFilter(MixerContext, MixerList, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, FALSE);
1017 DPRINT("MMixerInitializeFilter Status %u\n", Status);
1018 // check for success
1019 if (Status == MM_STATUS_SUCCESS)
1020 {
1021 // increment mixer count
1022 (*DeviceCount)++;
1023 }
1024
1025 }
1026
1027 // check if the filter has an wave in node
1028 NodeIndex = MMixerGetIndexOfGuid(NodeTypes, &KSNODETYPE_ADC);
1029 if (NodeIndex != MAXULONG)
1030 {
1031 // it has
1032 Status = MMixerInitializeFilter(MixerContext, MixerList, hMixer, DeviceName, NodeTypes, NodeConnections, PinCount, NodeIndex, TRUE);
1033 DPRINT("MMixerInitializeFilter Status %u\n", Status);
1034 // check for success
1035 if (Status == MM_STATUS_SUCCESS)
1036 {
1037 // increment mixer count
1038 (*DeviceCount)++;
1039 }
1040
1041 }
1042
1043 //free resources
1044 MixerContext->Free((PVOID)NodeTypes);
1045 MixerContext->Free((PVOID)NodeConnections);
1046
1047 // done
1048 return Status;
1049 }