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