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