[AUDIO-BRINGUP]
[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 const GUID KSNODETYPE_DESKTOP_MICROPHONE = {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
12 const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR = {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
13 const GUID KSNODETYPE_TELEPHONE = {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
14 const GUID KSNODETYPE_PHONE_LINE = {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
15 const GUID KSNODETYPE_DOWN_LINE_PHONE = {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
16 const GUID KSNODETYPE_DESKTOP_SPEAKER = {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID KSNODETYPE_ROOM_SPEAKER = {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
18 const GUID KSNODETYPE_COMMUNICATION_SPEAKER = {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID KSNODETYPE_HEADPHONES = {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
20 const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO = {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
21 const GUID KSNODETYPE_MICROPHONE = {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
22 const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
23 const GUID KSNODETYPE_SPDIF_INTERFACE = {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
24 const GUID KSNODETYPE_ANALOG_CONNECTOR = {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
25 const GUID KSNODETYPE_SPEAKER = {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
26 const GUID KSNODETYPE_CD_PLAYER = {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
27 const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
28 const GUID KSNODETYPE_LINE_CONNECTOR = {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
29 const GUID PINNAME_VIDEO_CAPTURE = {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
30
31 MIXER_STATUS
32 MMixerAddMixerControl(
33 IN PMIXER_CONTEXT MixerContext,
34 IN LPMIXER_INFO MixerInfo,
35 IN PTOPOLOGY Topology,
36 IN ULONG NodeIndex,
37 IN LPMIXERLINE_EXT MixerLine,
38 OUT LPMIXERCONTROLW MixerControl)
39 {
40 LPGUID NodeType;
41 KSP_NODE Node;
42 ULONG BytesReturned;
43 MIXER_STATUS Status;
44 LPWSTR Name;
45
46 /* initialize mixer control */
47 MixerControl->cbStruct = sizeof(MIXERCONTROLW);
48 MixerControl->dwControlID = MixerInfo->ControlId;
49
50 /* get node type */
51 NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex);
52 /* store control type */
53 MixerControl->dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
54
55 MixerControl->fdwControl = MIXERCONTROL_CONTROLF_UNIFORM; /* FIXME */
56 MixerControl->cMultipleItems = 0; /* FIXME */
57
58 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
59 {
60 MixerControl->Bounds.dwMinimum = 0;
61 MixerControl->Bounds.dwMaximum = 1;
62 }
63 else if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
64 {
65 MixerControl->Bounds.dwMinimum = 0;
66 MixerControl->Bounds.dwMaximum = 0xFFFF;
67 MixerControl->Metrics.cSteps = 0xC0; /* FIXME */
68 }
69
70 /* setup request to retrieve name */
71 Node.NodeId = NodeIndex;
72 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
73 Node.Property.Flags = KSPROPERTY_TYPE_GET;
74 Node.Property.Set = KSPROPSETID_Topology;
75 Node.Reserved = 0;
76
77 /* get node name size */
78 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
79
80 if (Status == MM_STATUS_MORE_ENTRIES)
81 {
82 ASSERT(BytesReturned != 0);
83 Name = (LPWSTR)MixerContext->Alloc(BytesReturned);
84 if (!Name)
85 {
86 /* not enough memory */
87 return MM_STATUS_NO_MEMORY;
88 }
89
90 /* get node name */
91 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
92
93 if (Status == MM_STATUS_SUCCESS)
94 {
95 MixerContext->Copy(MixerControl->szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
96 MixerControl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
97
98 MixerContext->Copy(MixerControl->szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
99 MixerControl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
100 }
101
102 /* free name buffer */
103 MixerContext->Free(Name);
104 }
105
106 MixerInfo->ControlId++;
107 #if 0
108 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
109 {
110 KSNODEPROPERTY Property;
111 ULONG PinId = 2;
112
113 /* setup the request */
114 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY));
115
116 Property.NodeId = NodeIndex;
117 Property.Property.Id = KSPROPERTY_AUDIO_MUX_SOURCE;
118 Property.Property.Flags = KSPROPERTY_TYPE_SET;
119 Property.Property.Set = KSPROPSETID_Audio;
120
121 /* get node volume level info */
122 Status = MixerContext->Control(hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY), (PVOID)&PinId, sizeof(ULONG), &BytesReturned);
123
124 DPRINT1("Status %x NodeIndex %u PinId %u\n", Status, NodeIndex, PinId);
125 //DbgBreakPoint();
126 }else
127 #endif
128 if (MixerControl->dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
129 {
130 KSNODEPROPERTY_AUDIO_CHANNEL Property;
131 ULONG Length;
132 PKSPROPERTY_DESCRIPTION Desc;
133 PKSPROPERTY_MEMBERSHEADER Members;
134 PKSPROPERTY_STEPPING_LONG Range;
135
136 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
137 Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
138 ASSERT(Desc);
139
140 /* setup the request */
141 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
142
143 Property.NodeProperty.NodeId = NodeIndex;
144 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
145 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT;
146 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
147
148 /* get node volume level info */
149 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
150
151 if (Status == MM_STATUS_SUCCESS)
152 {
153 LPMIXERVOLUME_DATA VolumeData;
154 ULONG Steps, MaxRange, Index;
155 LONG Value;
156
157 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
158 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
159
160 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);
161
162 MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum;
163
164 if (MaxRange)
165 {
166 ASSERT(MaxRange);
167 VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA));
168 if (!VolumeData)
169 return MM_STATUS_NO_MEMORY;
170
171 Steps = MaxRange / Range->SteppingDelta + 1;
172
173 /* store mixer control info there */
174 VolumeData->Header.dwControlID = MixerControl->dwControlID;
175 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
176 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
177 VolumeData->SteppingDelta = Range->SteppingDelta;
178 VolumeData->ValuesCount = Steps;
179 VolumeData->InputSteppingDelta = 0x10000 / Steps;
180
181 VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps);
182 if (!VolumeData->Values)
183 {
184 MixerContext->Free(Desc);
185 MixerContext->Free(VolumeData);
186 return MM_STATUS_NO_MEMORY;
187 }
188
189 Value = Range->Bounds.SignedMinimum;
190 for(Index = 0; Index < Steps; Index++)
191 {
192 VolumeData->Values[Index] = Value;
193 Value += Range->SteppingDelta;
194 }
195 InsertTailList(&MixerLine->LineControlsExtraData, &VolumeData->Header.Entry);
196 }
197 }
198 MixerContext->Free(Desc);
199 }
200
201 DPRINT("Status %x Name %S\n", Status, MixerControl->szName);
202 return MM_STATUS_SUCCESS;
203 }
204
205 MIXER_STATUS
206 MMixerCreateDestinationLine(
207 IN PMIXER_CONTEXT MixerContext,
208 IN LPMIXER_INFO MixerInfo,
209 IN ULONG bInputMixer,
210 IN LPWSTR LineName)
211 {
212 LPMIXERLINE_EXT DestinationLine;
213
214 /* allocate a mixer destination line */
215 DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
216 if (!MixerInfo)
217 {
218 /* no memory */
219 return MM_STATUS_NO_MEMORY;
220 }
221
222 /* initialize mixer destination line */
223 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
224 DestinationLine->Line.dwSource = MAXULONG;
225 DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
226 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
227 DestinationLine->Line.dwUser = 0;
228 DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
229 DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
230 DestinationLine->Line.cChannels = 2; /* FIXME */
231
232 if (LineName)
233 {
234 MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
235 DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
236
237 MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
238 DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
239
240 }
241
242 DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
243 DestinationLine->Line.Target.dwDeviceID = 0; //FIXME
244 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
245 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
246 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
247
248 ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
249 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
250
251 /* initialize extra line */
252 InitializeListHead(&DestinationLine->LineControlsExtraData);
253
254 /* insert into mixer info */
255 InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
256
257 /* increment destination count */
258 MixerInfo->MixCaps.cDestinations++;
259
260 /* done */
261 return MM_STATUS_SUCCESS;
262 }
263
264 MIXER_STATUS
265 MMixerGetPinName(
266 IN PMIXER_CONTEXT MixerContext,
267 IN LPMIXER_INFO MixerInfo,
268 IN ULONG PinId,
269 IN OUT LPWSTR * OutBuffer)
270 {
271 KSP_PIN Pin;
272 ULONG BytesReturned;
273 LPWSTR Buffer;
274 MIXER_STATUS Status;
275
276 /* prepare pin */
277 Pin.PinId = PinId;
278 Pin.Reserved = 0;
279 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
280 Pin.Property.Set = KSPROPSETID_Pin;
281 Pin.Property.Id = KSPROPERTY_PIN_NAME;
282
283 /* try get pin name size */
284 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
285
286 /* check if buffer overflowed */
287 if (Status == MM_STATUS_MORE_ENTRIES)
288 {
289 /* allocate buffer */
290 Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
291 if (!Buffer)
292 {
293 /* out of memory */
294 return MM_STATUS_NO_MEMORY;
295 }
296
297 /* try get pin name */
298 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
299 if (Status != MM_STATUS_SUCCESS)
300 {
301 /* failed to get pin name */
302 MixerContext->Free((PVOID)Buffer);
303 return Status;
304 }
305
306 /* successfully obtained pin name */
307 *OutBuffer = Buffer;
308 return MM_STATUS_SUCCESS;
309 }
310
311 /* failed to get pin name */
312 return Status;
313 }
314
315 MIXER_STATUS
316 MMixerBuildMixerDestinationLine(
317 IN PMIXER_CONTEXT MixerContext,
318 IN OUT LPMIXER_INFO MixerInfo,
319 IN ULONG PinId,
320 IN ULONG bInput)
321 {
322 LPWSTR PinName;
323 MIXER_STATUS Status;
324
325 /* try get pin name */
326 Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
327 if (Status == MM_STATUS_SUCCESS)
328 {
329 /* create mixer destination line */
330
331 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName);
332
333 /* free pin name */
334 MixerContext->Free(PinName);
335 }
336 else
337 {
338 /* create mixer destination line unlocalized */
339 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name");
340 }
341
342 return Status;
343 }
344
345 MIXER_STATUS
346 MMixerBuildTopology(
347 IN PMIXER_CONTEXT MixerContext,
348 IN LPMIXER_DATA MixerData,
349 OUT PTOPOLOGY * OutTopology)
350 {
351 ULONG PinsCount;
352 PKSMULTIPLE_ITEM NodeTypes = NULL;
353 PKSMULTIPLE_ITEM NodeConnections = NULL;
354 MIXER_STATUS Status;
355
356 if (MixerData->Topology)
357 {
358 /* re-use existing topology */
359 *OutTopology = MixerData->Topology;
360
361 return MM_STATUS_SUCCESS;
362 }
363
364 /* get connected filter pin count */
365 PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
366
367 if (!PinsCount)
368 {
369 /* referenced filter does not have any pins */
370 return MM_STATUS_UNSUCCESSFUL;
371 }
372
373 /* get topology node types */
374 Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
375 if (Status != MM_STATUS_SUCCESS)
376 {
377 /* failed to get topology node types */
378 return Status;
379 }
380
381 /* get topology connections */
382 Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
383 if (Status != MM_STATUS_SUCCESS)
384 {
385 /* failed to get topology connections */
386 MixerContext->Free(NodeTypes);
387 return Status;
388 }
389
390 /* create a topology */
391 Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology);
392
393 /* free node types & connections */
394 MixerContext->Free(NodeConnections);
395 MixerContext->Free(NodeTypes);
396
397 if (Status == MM_STATUS_SUCCESS)
398 {
399 /* store topology object */
400 MixerData->Topology = *OutTopology;
401 }
402
403 /* done */
404 return Status;
405 }
406
407 MIXER_STATUS
408 MMixerCountMixerControls(
409 IN PMIXER_CONTEXT MixerContext,
410 IN PTOPOLOGY Topology,
411 IN ULONG PinId,
412 IN ULONG bInputMixer,
413 IN ULONG bUpStream,
414 OUT PULONG OutNodesCount,
415 OUT PULONG OutNodes,
416 OUT PULONG OutLineTerminator)
417 {
418 PULONG Nodes;
419 ULONG NodesCount, NodeIndex, Count, bTerminator;
420 MIXER_STATUS Status;
421
422 /* allocate an array to store all nodes which are upstream of this pin */
423 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
424
425 if (Status != MM_STATUS_SUCCESS)
426 {
427 /* out of memory */
428 return STATUS_NO_MEMORY;
429 }
430
431 /* mark result array as zero */
432 *OutNodesCount = 0;
433
434 /* get next nodes */
435 MMixerGetNextNodesFromPinIndex(MixerContext, Topology, PinId, bUpStream, &NodesCount, Nodes);
436
437 /* assume no topology split before getting line terminator */
438 ASSERT(NodesCount == 1);
439
440 /* get first node */
441 NodeIndex = Nodes[0];
442 Count = 0;
443
444 do
445 {
446 /* check if the node is a terminator */
447 MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator);
448
449 if (bTerminator)
450 {
451 /* found terminator */
452 if (bInputMixer)
453 {
454 /* add mux source for source destination line */
455 OutNodes[Count] = NodeIndex;
456 Count++;
457 }
458 break;
459 }
460
461 /* store node id */
462 OutNodes[Count] = NodeIndex;
463
464 /* increment node count */
465 Count++;
466
467 /* get next nodes upstream */
468 MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &NodesCount, Nodes);
469
470 /* assume there is a node connected */
471 ASSERT(NodesCount != 0);
472 ASSERT(NodesCount == 1);
473
474 /* use first index */
475 NodeIndex = Nodes[0];
476
477 }while(TRUE);
478
479 /* free node index */
480 MixerContext->Free(Nodes);
481
482 /* store nodes count */
483 *OutNodesCount = Count;
484
485 /* store line terminator */
486 *OutLineTerminator = NodeIndex;
487
488 /* done */
489 return MM_STATUS_SUCCESS;
490 }
491
492 MIXER_STATUS
493 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
494 IN PMIXER_CONTEXT MixerContext,
495 IN LPMIXER_INFO MixerInfo,
496 IN PTOPOLOGY Topology,
497 IN OUT LPMIXERLINE_EXT DstLine,
498 IN ULONG NodesCount,
499 IN PULONG Nodes)
500 {
501 ULONG Index, Count, bReserved;
502 MIXER_STATUS Status;
503
504 /* store nodes array */
505 DstLine->NodeIds = Nodes;
506
507 /* allocate MIXERCONTROLSW array */
508 DstLine->LineControls = MixerContext->Alloc(NodesCount * sizeof(MIXERCONTROLW));
509
510 if (!DstLine->LineControls)
511 {
512 /* out of memory */
513 return MM_STATUS_NO_MEMORY;
514 }
515
516 /* initialize control count */
517 Count = 0;
518
519 for(Index = 0; Index < NodesCount; Index++)
520 {
521 /* check if the node has already been reserved to a line */
522 MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
523 #if 0 /* MS lies */
524 if (bReserved)
525 {
526 /* node is already used, skip it */
527 continue;
528 }
529 #endif
530 /* set node status as used */
531 MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
532
533 /* now add the mixer control */
534 Status = MMixerAddMixerControl(MixerContext, MixerInfo, Topology, Nodes[Index], DstLine, &DstLine->LineControls[Count]);
535
536 if (Status == MM_STATUS_SUCCESS)
537 {
538 /* increment control count */
539 Count++;
540 }
541 }
542
543 /* store control count */
544 DstLine->Line.cControls = Count;
545
546 /* done */
547 return MM_STATUS_SUCCESS;
548 }
549
550 MIXER_STATUS
551 MMixerGetComponentAndTargetType(
552 IN PMIXER_CONTEXT MixerContext,
553 IN OUT LPMIXER_INFO MixerInfo,
554 IN ULONG PinId,
555 OUT PULONG ComponentType,
556 OUT PULONG TargetType)
557 {
558 KSPIN_DATAFLOW DataFlow;
559 KSPIN_COMMUNICATION Communication;
560 MIXER_STATUS Status;
561 KSP_PIN Request;
562 ULONG BytesReturned;
563 GUID Guid;
564 BOOLEAN BridgePin = FALSE;
565 PKSPIN_PHYSICALCONNECTION Connection;
566
567 /* first dataflow type */
568 Status = MMixerGetPinDataFlowAndCommunication(MixerContext, MixerInfo->hMixer, PinId, &DataFlow, &Communication);
569
570 if (Status != MM_STATUS_SUCCESS)
571 {
572 /* failed to get dataflow */
573 return Status;
574 }
575
576 /* now get pin category guid */
577 Request.PinId = PinId;
578 Request.Reserved = 0;
579 Request.Property.Flags = KSPROPERTY_TYPE_GET;
580 Request.Property.Set = KSPROPSETID_Pin;
581 Request.Property.Id = KSPROPERTY_PIN_CATEGORY;
582
583
584 /* get pin category */
585 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_PIN), &Guid, sizeof(GUID), &BytesReturned);
586 if (Status != MM_STATUS_SUCCESS)
587 {
588 /* failed to get dataflow */
589 return Status;
590 }
591
592 /* check if it has a physical connection */
593 Status = MMixerGetPhysicalConnection(MixerContext, MixerInfo->hMixer, PinId, &Connection);
594 if (Status == MM_STATUS_SUCCESS)
595 {
596 /* pin is a brige pin */
597 BridgePin = TRUE;
598
599 /* free physical connection */
600 MixerContext->Free(Connection);
601 }
602
603 if (DataFlow == KSPIN_DATAFLOW_IN)
604 {
605 if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_MICROPHONE) ||
606 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_MICROPHONE))
607 {
608 /* type microphone */
609 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
610 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
611 }
612 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR) ||
613 IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
614 IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER))
615 {
616 /* type waveout */
617 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
618 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
619 }
620 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_CD_PLAYER))
621 {
622 /* type cd player */
623 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
624 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
625 }
626 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SYNTHESIZER))
627 {
628 /* type synthesizer */
629 *TargetType = MIXERLINE_TARGETTYPE_MIDIOUT;
630 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
631 }
632 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LINE_CONNECTOR))
633 {
634 /* type line */
635 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
636 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
637 }
638 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
639 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
640 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
641 {
642 /* type telephone */
643 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
644 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
645 }
646 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
647 {
648 /* type analog */
649 if (BridgePin)
650 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
651 else
652 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
653
654 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_ANALOG;
655 }
656 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
657 {
658 /* type analog */
659 if (BridgePin)
660 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
661 else
662 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
663
664 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
665 }
666 else
667 {
668 /* unknown type */
669 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
670 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
671 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
672 }
673 }
674 else
675 {
676 if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER) ||
677 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_SPEAKER) ||
678 IsEqualGUIDAligned(&Guid, &KSNODETYPE_ROOM_SPEAKER) ||
679 IsEqualGUIDAligned(&Guid, &KSNODETYPE_COMMUNICATION_SPEAKER))
680 {
681 /* type waveout */
682 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
683 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
684 }
685 else if (IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
686 IsEqualGUIDAligned(&Guid, &PINNAME_CAPTURE))
687 {
688 /* type wavein */
689 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
690 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
691 }
692 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEADPHONES) ||
693 IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO))
694 {
695 /* type head phones */
696 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
697 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
698 }
699 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
700 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
701 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
702 {
703 /* type waveout */
704 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
705 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_TELEPHONE;
706 }
707 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
708 {
709 /* type analog */
710 if (BridgePin)
711 {
712 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
713 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
714 }
715 else
716 {
717 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
718 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
719 }
720 }
721 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
722 {
723 /* type spdif */
724 if (BridgePin)
725 {
726 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
727 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
728 }
729 else
730 {
731 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
732 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
733 }
734 }
735 else
736 {
737 /* unknown type */
738 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
739 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
740 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
741 }
742 }
743
744 /* done */
745 return MM_STATUS_SUCCESS;
746 }
747
748 MIXER_STATUS
749 MMixerBuildMixerSourceLine(
750 IN PMIXER_CONTEXT MixerContext,
751 IN OUT LPMIXER_INFO MixerInfo,
752 IN PTOPOLOGY Topology,
753 IN ULONG PinId,
754 IN ULONG NodesCount,
755 IN PULONG Nodes,
756 IN ULONG DestinationLineID,
757 OUT LPMIXERLINE_EXT * OutSrcLine)
758 {
759 LPMIXERLINE_EXT SrcLine, DstLine;
760 LPWSTR PinName;
761 MIXER_STATUS Status;
762 ULONG ComponentType, TargetType;
763
764 /* get component and target type */
765 Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, PinId, &ComponentType, &TargetType);
766 if (Status != MM_STATUS_SUCCESS)
767 {
768 /* failed to get component status */
769 TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
770 ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
771 }
772
773 /* construct source line */
774 SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
775
776 if (!SrcLine)
777 {
778 /* no memory */
779 return MM_STATUS_NO_MEMORY;
780 }
781
782 /* get destination line */
783 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
784 ASSERT(DstLine);
785
786 /* initialize mixer src line */
787 SrcLine->hDevice = MixerInfo->hMixer;
788 SrcLine->PinId = PinId;
789 SrcLine->NodeIds = Nodes;
790
791 /* initialize mixer line */
792 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
793 SrcLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations-1;
794 SrcLine->Line.dwSource = DstLine->Line.cConnections;
795 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * SOURCE_LINE)+ (MixerInfo->MixCaps.cDestinations-1);
796 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
797 SrcLine->Line.dwComponentType = ComponentType;
798 SrcLine->Line.dwUser = 0;
799 SrcLine->Line.cChannels = DstLine->Line.cChannels;
800 SrcLine->Line.cConnections = 0;
801 SrcLine->Line.Target.dwType = TargetType;
802 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
803 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
804 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
805 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
806 InitializeListHead(&SrcLine->LineControlsExtraData);
807
808 /* copy name */
809 ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
810 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
811
812 /* get pin name */
813 Status = MMixerGetPinName(MixerContext, MixerInfo, PinId, &PinName);
814
815 if (Status == MM_STATUS_SUCCESS)
816 {
817 /* store pin name as line name */
818 MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
819 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
820
821 MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
822 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
823
824 /* free pin name buffer */
825 MixerContext->Free(PinName);
826 }
827
828 /* add the controls to mixer line */
829 Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, SrcLine, NodesCount, Nodes);
830 if (Status != MM_STATUS_SUCCESS)
831 {
832 /* failed */
833 return Status;
834 }
835
836 /* store result */
837 *OutSrcLine = SrcLine;
838
839 return MM_STATUS_SUCCESS;
840 }
841
842 MIXER_STATUS
843 MMixerAddMixerSourceLines(
844 IN PMIXER_CONTEXT MixerContext,
845 IN OUT LPMIXER_INFO MixerInfo,
846 IN PTOPOLOGY Topology,
847 IN ULONG DestinationLineID,
848 IN ULONG LineTerminator)
849 {
850 PULONG AllNodes, AllPins, AllPinNodes;
851 ULONG AllNodesCount, AllPinsCount, AllPinNodesCount;
852 ULONG Index, SubIndex, PinId, CurNode, bConnected;
853 MIXER_STATUS Status;
854 LPMIXERLINE_EXT DstLine, SrcLine;
855
856 /* get destination line */
857 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
858 ASSERT(DstLine);
859
860 /* allocate an array to store all nodes which are upstream of the line terminator */
861 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes);
862
863 /* check for success */
864 if (Status != MM_STATUS_SUCCESS)
865 {
866 /* out of memory */
867 return MM_STATUS_NO_MEMORY;
868 }
869
870 /* allocate an array to store all nodes which are downstream of a particular pin */
871 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes);
872
873 /* allocate an array to store all pins which are upstream of this pin */
874 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &AllPins);
875
876 /* check for success */
877 if (Status != MM_STATUS_SUCCESS)
878 {
879 /* out of memory */
880 MixerContext->Free(AllNodes);
881 return MM_STATUS_NO_MEMORY;
882 }
883
884 /* get all nodes which indirectly / directly connect to this node */
885 AllNodesCount = 0;
886 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllNodesCount, AllNodes);
887
888 /* get all pins which indirectly / directly connect to this node */
889 AllPinsCount = 0;
890 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins);
891
892 DPRINT1("LineTerminator %lu\n", LineTerminator);
893 DPRINT1("PinCount %lu\n", AllPinsCount);
894 DPRINT1("AllNodesCount %lu\n", AllNodesCount);
895
896 /* now construct the source lines which are attached to the destination line */
897 Index = AllPinsCount;
898
899 do
900 {
901 /* get current pin id */
902 PinId = AllPins[Index - 1];
903
904 /* reset nodes count */
905 AllPinNodesCount = 0;
906
907 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
908 for(SubIndex = 0; SubIndex < AllNodesCount; SubIndex++)
909 {
910 /* get current node index */
911 CurNode = AllNodes[SubIndex];
912
913 if (CurNode != MAXULONG && CurNode != LineTerminator)
914 {
915 /* check if that node is connected in some way to the current pin */
916 Status = MMixerIsNodeConnectedToPin(MixerContext, Topology, CurNode, PinId, TRUE, &bConnected);
917
918 if (Status != MM_STATUS_SUCCESS)
919 break;
920
921 if (bConnected)
922 {
923 /* it is connected */
924 AllPinNodes[AllPinNodesCount] = CurNode;
925 AllPinNodesCount++;
926
927 /* clear current index */
928 AllNodes[SubIndex] = MAXULONG;
929 }
930 }
931 }
932
933 /* decrement pin index */
934 Index--;
935
936 if (AllPinNodesCount)
937 {
938 #ifdef MMIXER_DEBUG
939 ULONG TempIndex;
940 #endif
941 /* now build the mixer source line */
942 Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, Topology, PinId, AllPinNodesCount, AllPinNodes, DestinationLineID, &SrcLine);
943
944 if (Status == MM_STATUS_SUCCESS)
945 {
946 /* insert into line list */
947 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
948
949 /* increment destination line count */
950 DstLine->Line.cConnections++;
951 #ifdef MMIXER_DEBUG
952 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId, AllPinNodesCount, DestinationLineID);
953 for(TempIndex = 0; TempIndex < AllPinNodesCount; TempIndex++)
954 DPRINT1("NodeIndex %lu\n", AllPinNodes[TempIndex]);
955 #endif
956 }
957 }
958 else
959 {
960 #ifdef MMIXER_DEBUG
961 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID, PinId);
962 #endif
963 }
964
965 }while(Index != 0);
966
967 return MM_STATUS_SUCCESS;
968 }
969
970
971 MIXER_STATUS
972 MMixerAddMixerControlsToDestinationLine(
973 IN PMIXER_CONTEXT MixerContext,
974 IN OUT LPMIXER_INFO MixerInfo,
975 IN PTOPOLOGY Topology,
976 IN ULONG PinId,
977 IN ULONG bInput,
978 IN ULONG DestinationLineId,
979 OUT PULONG OutLineTerminator)
980 {
981 PULONG Nodes;
982 ULONG NodesCount, LineTerminator;
983 MIXER_STATUS Status;
984 LPMIXERLINE_EXT DstLine;
985
986 /* allocate nodes index array */
987 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
988
989 /* check for success */
990 if (Status != MM_STATUS_SUCCESS)
991 {
992 /* out of memory */
993 return MM_STATUS_NO_MEMORY;
994 }
995
996 /* get all destination line controls */
997 Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
998
999 /* check for success */
1000 if (Status != MM_STATUS_SUCCESS)
1001 {
1002 /* failed to count controls */
1003 MixerContext->Free(Nodes);
1004 return Status;
1005 }
1006
1007 /* get destination mixer line */
1008 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
1009
1010 /* sanity check */
1011 ASSERT(DstLine);
1012
1013 if (NodesCount > 0)
1014 {
1015 /* add all nodes as mixer controls to the destination line */
1016 Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, Topology, DstLine, NodesCount, Nodes);
1017 if (Status != MM_STATUS_SUCCESS)
1018 {
1019 /* failed to add controls */
1020 MixerContext->Free(Nodes);
1021 return Status;
1022 }
1023 }
1024
1025 /* store result */
1026 *OutLineTerminator = LineTerminator;
1027
1028 /* return result */
1029 return Status;
1030 }
1031
1032 VOID
1033 MMixerApplyOutputFilterHack(
1034 IN PMIXER_CONTEXT MixerContext,
1035 IN LPMIXER_DATA MixerData,
1036 IN OUT PULONG PinsCount,
1037 IN OUT PULONG Pins)
1038 {
1039 ULONG Count = 0, Index;
1040 MIXER_STATUS Status;
1041 PKSPIN_PHYSICALCONNECTION Connection;
1042
1043 for(Index = 0; Index < *PinsCount; Index++)
1044 {
1045 /* check if it has a physical connection */
1046 Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[Index], &Connection);
1047
1048 if (Status == MM_STATUS_SUCCESS)
1049 {
1050 /* remove pin */
1051 MixerContext->Copy(&Pins[Index], &Pins[Index + 1], (*PinsCount - (Index + 1)) * sizeof(ULONG));
1052
1053 /* free physical connection */
1054 MixerContext->Free(Connection);
1055
1056 /* decrement index */
1057 Index--;
1058
1059 /* decrement pin count */
1060 (*PinsCount)--;
1061 }
1062 else
1063 {
1064 /* simple pin */
1065 Count++;
1066 }
1067 }
1068
1069 /* store result */
1070 *PinsCount = Count;
1071 }
1072
1073 MIXER_STATUS
1074 MMixerHandlePhysicalConnection(
1075 IN PMIXER_CONTEXT MixerContext,
1076 IN PMIXER_LIST MixerList,
1077 IN LPMIXER_DATA MixerData,
1078 IN OUT LPMIXER_INFO MixerInfo,
1079 IN ULONG bInput,
1080 IN PKSPIN_PHYSICALCONNECTION OutConnection)
1081 {
1082 MIXER_STATUS Status;
1083 ULONG PinsCount, LineTerminator, DestinationLineID;
1084 PULONG Pins;
1085 PTOPOLOGY Topology;
1086
1087 /* first try to open the connected filter */
1088 OutConnection->SymbolicLinkName[1] = L'\\';
1089 MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
1090
1091 /* check if the linked connection is found */
1092 if (!MixerData)
1093 {
1094 /* filter references invalid physical connection */
1095 return MM_STATUS_UNSUCCESSFUL;
1096 }
1097
1098 DPRINT1("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
1099
1100 if (MixerInfo->hMixer != NULL)
1101 {
1102 /* dont replace mixer destination handles */
1103 DPRINT1("MixerInfo hDevice %p MixerData hDevice %p\n", MixerInfo->hMixer, MixerData->hDevice);
1104 ASSERT(MixerInfo->hMixer == MixerData->hDevice);
1105 }
1106
1107 /* store connected mixer handle */
1108 MixerInfo->hMixer = MixerData->hDevice;
1109
1110 if (MixerData->Topology == NULL)
1111 {
1112 /* construct new topology */
1113 Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
1114 if (Status != MM_STATUS_SUCCESS)
1115 {
1116 /* failed to create topology */
1117 return Status;
1118 }
1119
1120 /* store topology */
1121 MixerData->Topology = Topology;
1122 }
1123 else
1124 {
1125 /* re-use existing topology */
1126 Topology = MixerData->Topology;
1127 }
1128
1129 /* allocate pin index array which will hold all referenced pins */
1130 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1131 ASSERT(Status == MM_STATUS_SUCCESS);
1132
1133 if (!bInput)
1134 {
1135 /* the mixer is an output mixer
1136 * find end pin of the node path
1137 */
1138 PinsCount = 0;
1139 Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins);
1140
1141 /* check for success */
1142 if (Status != MM_STATUS_SUCCESS)
1143 {
1144 /* failed to get end pin */
1145 MixerContext->Free(Pins);
1146 //MMixerFreeTopology(Topology);
1147
1148 /* return error code */
1149 return Status;
1150 }
1151 /* HACK:
1152 * some topologies do not have strict boundaries
1153 * WorkArround: remove all pin ids which have a physical connection
1154 * because bridge pins may belong to different render paths
1155 */
1156 MMixerApplyOutputFilterHack(MixerContext, MixerData, &PinsCount, Pins);
1157
1158 /* sanity checks */
1159 ASSERT(PinsCount != 0);
1160 ASSERT(PinsCount == 1);
1161
1162 /* create destination line */
1163 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInput);
1164
1165 /* calculate destination line id */
1166 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
1167
1168 if (Status != MM_STATUS_SUCCESS)
1169 {
1170 /* failed to build destination line */
1171 MixerContext->Free(Pins);
1172
1173 /* return error code */
1174 return Status;
1175 }
1176
1177 /* add mixer controls to destination line */
1178 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, Pins[0], bInput, DestinationLineID, &LineTerminator);
1179
1180 if (Status == MM_STATUS_SUCCESS)
1181 {
1182 /* now add the rest of the source lines */
1183 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, DestinationLineID, LineTerminator);
1184 }
1185 }
1186 else
1187 {
1188 /* calculate destination line id */
1189 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
1190
1191 /* add mixer controls */
1192 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
1193
1194 if (Status == MM_STATUS_SUCCESS)
1195 {
1196 /* now add the rest of the source lines */
1197 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, Topology, DestinationLineID, LineTerminator);
1198 }
1199 }
1200
1201 return Status;
1202 }
1203
1204 MIXER_STATUS
1205 MMixerInitializeFilter(
1206 IN PMIXER_CONTEXT MixerContext,
1207 IN PMIXER_LIST MixerList,
1208 IN LPMIXER_DATA MixerData,
1209 IN LPMIXER_INFO MixerInfo,
1210 IN PTOPOLOGY Topology,
1211 IN ULONG NodeIndex,
1212 IN ULONG bInputMixer,
1213 IN OUT LPMIXER_INFO * OutMixerInfo)
1214 {
1215
1216 MIXER_STATUS Status;
1217 PKSPIN_PHYSICALCONNECTION OutConnection;
1218 ULONG * Pins;
1219 ULONG PinsFound;
1220 ULONG NewMixerInfo = FALSE;
1221
1222 if (MixerInfo == NULL)
1223 {
1224 /* allocate a mixer info struct */
1225 MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
1226 if (!MixerInfo)
1227 {
1228 /* no memory */
1229 return MM_STATUS_NO_MEMORY;
1230 }
1231
1232 /* new mixer info */
1233 NewMixerInfo = TRUE;
1234
1235 /* intialize mixer caps */
1236 MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
1237 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
1238 MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
1239 MixerInfo->MixCaps.fdwSupport = 0;
1240 MixerInfo->MixCaps.cDestinations = 0;
1241
1242 /* get mixer name */
1243 MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
1244
1245 /* initialize line list */
1246 InitializeListHead(&MixerInfo->LineList);
1247 InitializeListHead(&MixerInfo->EventList);
1248 }
1249
1250 /* store mixer info */
1251 *OutMixerInfo = MixerInfo;
1252
1253 /* now allocate an array which will receive the indices of the pin
1254 * which has a ADC / DAC nodetype in its path
1255 */
1256 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1257 ASSERT(Status == MM_STATUS_SUCCESS);
1258
1259 PinsFound = 0;
1260
1261 /* now get all sink / source pins, which are attached to the ADC / DAC node
1262 * For sink pins (wave out) search up stream
1263 * For source pins (wave in) search down stream
1264 * The search direction is always the opposite of the current mixer type
1265 */
1266 PinsFound = 0;
1267 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
1268
1269 /* if there is no pin found, we have a broken topology */
1270 ASSERT(PinsFound != 0);
1271
1272 /* now create a wave info struct */
1273 Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
1274 if (Status != MM_STATUS_SUCCESS)
1275 {
1276 /* failed to create wave info struct */
1277 MixerContext->Free(MixerInfo);
1278 MixerContext->Free(Pins);
1279 return Status;
1280 }
1281
1282 if (bInputMixer)
1283 {
1284 /* pre create the mixer destination line for input mixers */
1285 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, Pins[0], bInputMixer);
1286
1287 if (Status != MM_STATUS_SUCCESS)
1288 {
1289 /* failed to create mixer destination line */
1290 return Status;
1291 }
1292 }
1293
1294
1295 /* now get the bridge pin which is at the end of node path
1296 * For sink pins (wave out) search down stream
1297 * For source pins (wave in) search up stream
1298 */
1299 MixerContext->Free(Pins);
1300 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1301 ASSERT(Status == MM_STATUS_SUCCESS);
1302
1303 PinsFound = 0;
1304 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins);
1305
1306 /* if there is no pin found, we have a broken topology */
1307 ASSERT(PinsFound != 0);
1308
1309 /* there should be exactly one bridge pin */
1310 ASSERT(PinsFound == 1);
1311
1312 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer);
1313
1314 /* does the pin have a physical connection */
1315 Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection);
1316
1317 if (Status == MM_STATUS_SUCCESS)
1318 {
1319 /* topology on the topoloy filter */
1320 Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
1321
1322 /* free physical connection data */
1323 MixerContext->Free(OutConnection);
1324 }
1325 else
1326 {
1327 /* FIXME
1328 * handle drivers which expose their topology on the same filter
1329 */
1330 ASSERT(0);
1331 MixerInfo->hMixer = MixerData->hDevice;
1332 }
1333
1334 /* free pins */
1335 MixerContext->Free(Pins);
1336
1337 if (NewMixerInfo)
1338 {
1339 /* insert mixer */
1340 InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
1341 /* increment mixer count */
1342 MixerList->MixerListCount++;
1343 }
1344
1345 /* done */
1346 return Status;
1347 }
1348
1349 MIXER_STATUS
1350 MMixerSetupFilter(
1351 IN PMIXER_CONTEXT MixerContext,
1352 IN PMIXER_LIST MixerList,
1353 IN LPMIXER_DATA MixerData,
1354 IN PULONG DeviceCount)
1355 {
1356 MIXER_STATUS Status;
1357 PTOPOLOGY Topology;
1358 ULONG NodeIndex;
1359 LPMIXER_INFO MixerInfo = NULL;
1360
1361 /* check if topology has already been built */
1362 if (MixerData->Topology == NULL)
1363 {
1364 /* build topology */
1365 Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
1366
1367 if (Status != MM_STATUS_SUCCESS)
1368 {
1369 /* failed to build topology */
1370 return Status;
1371 }
1372
1373 /* store topology */
1374 MixerData->Topology = Topology;
1375 }
1376 else
1377 {
1378 /* re-use topology */
1379 Topology = MixerData->Topology;
1380 }
1381
1382 /* check if the filter has an wave out node */
1383 NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_DAC);
1384 if (NodeIndex != MAXULONG)
1385 {
1386 /* it has */
1387 Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NULL, Topology, NodeIndex, FALSE, &MixerInfo);
1388
1389 /* check for success */
1390 if (Status == MM_STATUS_SUCCESS)
1391 {
1392 /* increment mixer count */
1393 (*DeviceCount)++;
1394 }
1395 else
1396 {
1397 /* reset mixer info in case of error */
1398 MixerInfo = NULL;
1399 }
1400 }
1401
1402 /* check if the filter has an wave in node */
1403 NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_ADC);
1404 if (NodeIndex != MAXULONG)
1405 {
1406 /* it has */
1407 Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, MixerInfo, Topology, NodeIndex, TRUE, &MixerInfo);
1408
1409 /* check for success */
1410 if (Status == MM_STATUS_SUCCESS)
1411 {
1412 /* increment mixer count */
1413 (*DeviceCount)++;
1414 }
1415
1416 }
1417
1418 /* TODO: handle alternative mixer types + apply hacks for Wave source line */
1419
1420 /* activate midi devices */
1421 MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1422
1423 /* done */
1424 return Status;
1425 }
1426
1427
1428 MIXER_STATUS
1429 MMixerAddEvent(
1430 IN PMIXER_CONTEXT MixerContext,
1431 IN OUT LPMIXER_INFO MixerInfo,
1432 IN PVOID MixerEventContext,
1433 IN PMIXER_EVENT MixerEventRoutine)
1434 {
1435 //KSE_NODE Property;
1436 PEVENT_NOTIFICATION_ENTRY EventData;
1437 //ULONG BytesReturned;
1438 //MIXER_STATUS Status;
1439
1440 EventData = (PEVENT_NOTIFICATION_ENTRY)MixerContext->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY));
1441 if (!EventData)
1442 {
1443 /* not enough memory */
1444 return MM_STATUS_NO_MEMORY;
1445 }
1446
1447 #if 0
1448 /* setup request */
1449 Property.Event.Set = KSEVENTSETID_AudioControlChange;
1450 Property.Event.Flags = KSEVENT_TYPE_TOPOLOGY|KSEVENT_TYPE_ENABLE;
1451 Property.Event.Id = KSEVENT_CONTROL_CHANGE;
1452
1453 Property.NodeId = NodeId;
1454 Property.Reserved = 0;
1455
1456 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSP_NODE), (PVOID)EventData, sizeof(KSEVENTDATA), &BytesReturned);
1457 if (Status != MM_STATUS_SUCCESS)
1458 {
1459 /* failed to add event */
1460 MixerContext->FreeEventData(EventData);
1461 return Status;
1462 }
1463 #endif
1464
1465 /* initialize notification entry */
1466 EventData->MixerEventContext = MixerEventContext;
1467 EventData->MixerEventRoutine;
1468
1469 /* store event */
1470 InsertTailList(&MixerInfo->EventList, &EventData->Entry);
1471 return MM_STATUS_SUCCESS;
1472 }
1473