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 "precomp.h"
10
11 // #define NDEBUG
12 #include <debug.h>
13
14 const GUID KSNODETYPE_DESKTOP_MICROPHONE = {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
15 const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR = {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
16 const GUID KSNODETYPE_TELEPHONE = {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
17 const GUID KSNODETYPE_PHONE_LINE = {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
18 const GUID KSNODETYPE_DOWN_LINE_PHONE = {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
19 const GUID KSNODETYPE_DESKTOP_SPEAKER = {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
20 const GUID KSNODETYPE_ROOM_SPEAKER = {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
21 const GUID KSNODETYPE_COMMUNICATION_SPEAKER = {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
22 const GUID KSNODETYPE_HEADPHONES = {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
23 const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO = {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
24 const GUID KSNODETYPE_MICROPHONE = {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
25 const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
26 const GUID KSNODETYPE_SPDIF_INTERFACE = {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
27 const GUID KSNODETYPE_ANALOG_CONNECTOR = {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
28 const GUID KSNODETYPE_SPEAKER = {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
29 const GUID KSNODETYPE_CD_PLAYER = {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
30 const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
31 const GUID KSNODETYPE_LINE_CONNECTOR = {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
32 const GUID PINNAME_VIDEO_CAPTURE = {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
33
34 MIXER_STATUS
MMixerAddMixerControl(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN PTOPOLOGY Topology,IN ULONG NodeIndex,IN LPMIXERLINE_EXT MixerLine,IN ULONG MaxChannels)35 MMixerAddMixerControl(
36 IN PMIXER_CONTEXT MixerContext,
37 IN LPMIXER_INFO MixerInfo,
38 IN HANDLE hMixer,
39 IN PTOPOLOGY Topology,
40 IN ULONG NodeIndex,
41 IN LPMIXERLINE_EXT MixerLine,
42 IN ULONG MaxChannels)
43 {
44 LPGUID NodeType;
45 KSP_NODE Node;
46 ULONG BytesReturned;
47 MIXER_STATUS Status;
48 LPWSTR Name;
49 LPMIXERCONTROL_EXT MixerControl;
50
51 /* allocate mixer control */
52 MixerControl = MixerContext->Alloc(sizeof(MIXERCONTROL_EXT));
53 if (!MixerControl)
54 {
55 /* no memory */
56 return MM_STATUS_NO_MEMORY;
57 }
58
59 /* initialize mixer control */
60 MixerControl->hDevice = hMixer;
61 MixerControl->NodeID = NodeIndex;
62 MixerControl->ExtraData = NULL;
63
64 MixerControl->Control.cbStruct = sizeof(MIXERCONTROLW);
65 MixerControl->Control.dwControlID = MixerInfo->ControlId;
66
67 /* get node type */
68 NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex);
69 /* store control type */
70 MixerControl->Control.dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
71
72 MixerControl->Control.fdwControl = (MaxChannels > 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM);
73 MixerControl->Control.cMultipleItems = 0;
74
75 /* setup request to retrieve name */
76 Node.NodeId = NodeIndex;
77 Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
78 Node.Property.Flags = KSPROPERTY_TYPE_GET;
79 Node.Property.Set = KSPROPSETID_Topology;
80 Node.Reserved = 0;
81
82 /* get node name size */
83 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
84
85 if (Status == MM_STATUS_MORE_ENTRIES)
86 {
87 ASSERT(BytesReturned != 0);
88 Name = (LPWSTR)MixerContext->Alloc(BytesReturned);
89 if (!Name)
90 {
91 /* not enough memory */
92 return MM_STATUS_NO_MEMORY;
93 }
94
95 /* get node name */
96 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
97
98 if (Status == MM_STATUS_SUCCESS)
99 {
100 MixerContext->Copy(MixerControl->Control.szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
101 MixerControl->Control.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
102
103 MixerContext->Copy(MixerControl->Control.szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
104 MixerControl->Control.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
105 }
106
107 /* free name buffer */
108 MixerContext->Free(Name);
109 }
110
111 /* increment control count */
112 MixerInfo->ControlId++;
113
114 /* insert control */
115 InsertTailList(&MixerLine->ControlsList, &MixerControl->Entry);
116
117 if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
118 {
119 ULONG NodesCount;
120 PULONG Nodes;
121
122 /* allocate topology nodes array */
123 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
124
125 if (Status != MM_STATUS_SUCCESS)
126 {
127 /* out of memory */
128 return STATUS_NO_MEMORY;
129 }
130
131 /* get connected node count */
132 MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, TRUE, &NodesCount, Nodes);
133
134 /* TODO */
135 MixerContext->Free(Nodes);
136
137 /* setup mux bounds */
138 MixerControl->Control.Bounds.dwMinimum = 0;
139 MixerControl->Control.Bounds.dwMaximum = NodesCount - 1;
140 MixerControl->Control.Metrics.dwReserved[0] = NodesCount;
141 MixerControl->Control.cMultipleItems = NodesCount;
142 MixerControl->Control.fdwControl |= MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
143 }
144 else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
145 {
146 MixerControl->Control.Bounds.dwMinimum = 0;
147 MixerControl->Control.Bounds.dwMaximum = 1;
148 }
149 else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF)
150 {
151 /* only needs to set bounds */
152 MixerControl->Control.Bounds.dwMinimum = 0;
153 MixerControl->Control.Bounds.dwMaximum = 1;
154 }
155 else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
156 {
157 KSNODEPROPERTY_AUDIO_CHANNEL Property;
158 ULONG Length;
159 PKSPROPERTY_DESCRIPTION Desc;
160 PKSPROPERTY_MEMBERSHEADER Members;
161 PKSPROPERTY_STEPPING_LONG Range;
162
163 MixerControl->Control.Bounds.dwMinimum = 0;
164 MixerControl->Control.Bounds.dwMaximum = 0xFFFF;
165 MixerControl->Control.Metrics.cSteps = 0xC0; /* FIXME */
166
167 Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
168 Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
169 ASSERT(Desc);
170
171 /* setup the request */
172 RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
173
174 Property.NodeProperty.NodeId = NodeIndex;
175 Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
176 Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
177 Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
178
179 /* get node volume level info */
180 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
181
182 if (Status == MM_STATUS_SUCCESS)
183 {
184 LPMIXERVOLUME_DATA VolumeData;
185 ULONG Steps, MaxRange, Index;
186 LONG Value;
187
188 Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
189 Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
190
191 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);
192
193 MaxRange = Range->Bounds.UnsignedMaximum - Range->Bounds.UnsignedMinimum;
194
195 if (MaxRange)
196 {
197 ASSERT(MaxRange);
198 VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA));
199 if (!VolumeData)
200 return MM_STATUS_NO_MEMORY;
201
202 Steps = MaxRange / Range->SteppingDelta + 1;
203
204 /* store mixer control info there */
205 VolumeData->Header.dwControlID = MixerControl->Control.dwControlID;
206 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
207 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
208 VolumeData->SteppingDelta = Range->SteppingDelta;
209 VolumeData->ValuesCount = Steps;
210 VolumeData->InputSteppingDelta = 0x10000 / Steps;
211
212 VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps);
213 if (!VolumeData->Values)
214 {
215 MixerContext->Free(Desc);
216 MixerContext->Free(VolumeData);
217 return MM_STATUS_NO_MEMORY;
218 }
219
220 Value = Range->Bounds.SignedMinimum;
221 for(Index = 0; Index < Steps; Index++)
222 {
223 VolumeData->Values[Index] = Value;
224 Value += Range->SteppingDelta;
225 }
226 MixerControl->ExtraData = VolumeData;
227 }
228 }
229 MixerContext->Free(Desc);
230 }
231
232 DPRINT("Status %x Name %S\n", Status, MixerControl->Control.szName);
233 return MM_STATUS_SUCCESS;
234 }
235
236 MIXER_STATUS
MMixerCreateDestinationLine(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN ULONG bInputMixer,IN LPWSTR LineName)237 MMixerCreateDestinationLine(
238 IN PMIXER_CONTEXT MixerContext,
239 IN LPMIXER_INFO MixerInfo,
240 IN ULONG bInputMixer,
241 IN LPWSTR LineName)
242 {
243 LPMIXERLINE_EXT DestinationLine;
244
245 /* allocate a mixer destination line */
246 DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
247 if (!MixerInfo)
248 {
249 /* no memory */
250 return MM_STATUS_NO_MEMORY;
251 }
252
253 /* initialize mixer destination line */
254 DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
255 DestinationLine->Line.cChannels = 2; /* FIXME */
256 DestinationLine->Line.cConnections = 0;
257 DestinationLine->Line.cControls = 0;
258 DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
259 DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
260 DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
261 DestinationLine->Line.dwSource = MAXULONG;
262 DestinationLine->Line.dwUser = 0;
263 DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
264
265 if (LineName)
266 {
267 MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
268 DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
269
270 MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
271 DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
272
273 }
274
275 DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
276 DestinationLine->Line.Target.dwDeviceID = 0; //FIXME
277 DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
278 DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
279 DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
280
281 ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
282 wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
283
284 /* initialize extra line */
285 InitializeListHead(&DestinationLine->ControlsList);
286
287 /* insert into mixer info */
288 InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
289
290 /* increment destination count */
291 MixerInfo->MixCaps.cDestinations++;
292
293 /* done */
294 return MM_STATUS_SUCCESS;
295 }
296
297 MIXER_STATUS
MMixerGetPinName(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG PinId,IN OUT LPWSTR * OutBuffer)298 MMixerGetPinName(
299 IN PMIXER_CONTEXT MixerContext,
300 IN LPMIXER_INFO MixerInfo,
301 IN HANDLE hMixer,
302 IN ULONG PinId,
303 IN OUT LPWSTR * OutBuffer)
304 {
305 KSP_PIN Pin;
306 ULONG BytesReturned;
307 LPWSTR Buffer;
308 MIXER_STATUS Status;
309
310 /* prepare pin */
311 Pin.PinId = PinId;
312 Pin.Reserved = 0;
313 Pin.Property.Flags = KSPROPERTY_TYPE_GET;
314 Pin.Property.Set = KSPROPSETID_Pin;
315 Pin.Property.Id = KSPROPERTY_PIN_NAME;
316
317 /* try get pin name size */
318 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
319
320 /* check if buffer overflowed */
321 if (Status == MM_STATUS_MORE_ENTRIES)
322 {
323 /* allocate buffer */
324 Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
325 if (!Buffer)
326 {
327 /* out of memory */
328 return MM_STATUS_NO_MEMORY;
329 }
330
331 /* try get pin name */
332 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
333 if (Status != MM_STATUS_SUCCESS)
334 {
335 /* failed to get pin name */
336 MixerContext->Free((PVOID)Buffer);
337 return Status;
338 }
339
340 /* successfully obtained pin name */
341 *OutBuffer = Buffer;
342 return MM_STATUS_SUCCESS;
343 }
344
345 /* failed to get pin name */
346 return Status;
347 }
348
349 MIXER_STATUS
MMixerBuildMixerDestinationLine(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG PinId,IN ULONG bInput)350 MMixerBuildMixerDestinationLine(
351 IN PMIXER_CONTEXT MixerContext,
352 IN OUT LPMIXER_INFO MixerInfo,
353 IN HANDLE hMixer,
354 IN ULONG PinId,
355 IN ULONG bInput)
356 {
357 LPWSTR PinName;
358 MIXER_STATUS Status;
359
360 /* try get pin name */
361 Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
362 if (Status == MM_STATUS_SUCCESS)
363 {
364 /* create mixer destination line */
365
366 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName);
367
368 /* free pin name */
369 MixerContext->Free(PinName);
370 }
371 else
372 {
373 /* create mixer destination line unlocalized */
374 Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name");
375 }
376
377 return Status;
378 }
379
380 MIXER_STATUS
MMixerBuildTopology(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_DATA MixerData,OUT PTOPOLOGY * OutTopology)381 MMixerBuildTopology(
382 IN PMIXER_CONTEXT MixerContext,
383 IN LPMIXER_DATA MixerData,
384 OUT PTOPOLOGY * OutTopology)
385 {
386 ULONG PinsCount;
387 PKSMULTIPLE_ITEM NodeTypes = NULL;
388 PKSMULTIPLE_ITEM NodeConnections = NULL;
389 MIXER_STATUS Status;
390
391 if (MixerData->Topology)
392 {
393 /* re-use existing topology */
394 *OutTopology = MixerData->Topology;
395
396 return MM_STATUS_SUCCESS;
397 }
398
399 /* get connected filter pin count */
400 PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
401
402 if (!PinsCount)
403 {
404 /* referenced filter does not have any pins */
405 return MM_STATUS_UNSUCCESSFUL;
406 }
407
408 /* get topology node types */
409 Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
410 if (Status != MM_STATUS_SUCCESS)
411 {
412 /* failed to get topology node types */
413 return Status;
414 }
415
416 /* get topology connections */
417 Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
418 if (Status != MM_STATUS_SUCCESS)
419 {
420 /* failed to get topology connections */
421 MixerContext->Free(NodeTypes);
422 return Status;
423 }
424
425 /* create a topology */
426 Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology);
427
428 /* free node types & connections */
429 MixerContext->Free(NodeConnections);
430 MixerContext->Free(NodeTypes);
431
432 if (Status == MM_STATUS_SUCCESS)
433 {
434 /* store topology object */
435 MixerData->Topology = *OutTopology;
436 }
437
438 /* done */
439 return Status;
440 }
441
442 MIXER_STATUS
MMixerCountMixerControls(IN PMIXER_CONTEXT MixerContext,IN PTOPOLOGY Topology,IN ULONG PinId,IN ULONG bInputMixer,IN ULONG bUpStream,OUT PULONG OutNodesCount,OUT PULONG OutNodes,OUT PULONG OutLineTerminator)443 MMixerCountMixerControls(
444 IN PMIXER_CONTEXT MixerContext,
445 IN PTOPOLOGY Topology,
446 IN ULONG PinId,
447 IN ULONG bInputMixer,
448 IN ULONG bUpStream,
449 OUT PULONG OutNodesCount,
450 OUT PULONG OutNodes,
451 OUT PULONG OutLineTerminator)
452 {
453 PULONG Nodes;
454 ULONG NodesCount, NodeIndex, Count, bTerminator;
455 MIXER_STATUS Status;
456
457 /* allocate an array to store all nodes which are upstream of this pin */
458 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
459
460 if (Status != MM_STATUS_SUCCESS)
461 {
462 /* out of memory */
463 return STATUS_NO_MEMORY;
464 }
465
466 /* mark result array as zero */
467 *OutNodesCount = 0;
468
469 /* get next nodes */
470 MMixerGetNextNodesFromPinIndex(MixerContext, Topology, PinId, bUpStream, &NodesCount, Nodes);
471
472 if (NodesCount == 0)
473 {
474 /* a pin which is not connected from any node
475 * a) it is a topology bug (driver bug)
476 * b) the request is from an alternative mixer
477 alternative mixer code scans all pins which have not been used and tries to build lines
478 */
479 DPRINT1("MMixerCountMixerControls PinId %lu is not connected by any node\n", PinId);
480 MMixerPrintTopology(Topology);
481 return MM_STATUS_UNSUCCESSFUL;
482 }
483
484 /* assume no topology split before getting line terminator */
485 ASSERT(NodesCount == 1);
486
487 /* get first node */
488 NodeIndex = Nodes[0];
489 Count = 0;
490
491 do
492 {
493 /* check if the node is a terminator */
494 MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator);
495
496 if (bTerminator)
497 {
498 /* found terminator */
499 if (bInputMixer)
500 {
501 /* add mux source for source destination line */
502 OutNodes[Count] = NodeIndex;
503 Count++;
504 }
505 break;
506 }
507
508 /* store node id */
509 OutNodes[Count] = NodeIndex;
510
511 /* increment node count */
512 Count++;
513
514 /* get next nodes upstream */
515 MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &NodesCount, Nodes);
516
517 if (NodesCount != 1)
518 {
519 DPRINT("PinId %lu bInputMixer %lu bUpStream %lu NodeIndex %lu is not connected", PinId, bInputMixer, bUpStream, NodeIndex);
520 break;
521 }
522
523 ASSERT(NodesCount == 1);
524
525 /* use first index */
526 NodeIndex = Nodes[0];
527
528 }while(TRUE);
529
530 /* free node index */
531 MixerContext->Free(Nodes);
532
533 /* store nodes count */
534 *OutNodesCount = Count;
535
536 /* store line terminator */
537 *OutLineTerminator = NodeIndex;
538
539 /* done */
540 return MM_STATUS_SUCCESS;
541 }
542
543 MIXER_STATUS
MMixerGetChannelCountEnhanced(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG NodeId,OUT PULONG MaxChannels)544 MMixerGetChannelCountEnhanced(
545 IN PMIXER_CONTEXT MixerContext,
546 IN LPMIXER_INFO MixerInfo,
547 IN HANDLE hMixer,
548 IN ULONG NodeId,
549 OUT PULONG MaxChannels)
550 {
551 KSPROPERTY_DESCRIPTION Description;
552 PKSPROPERTY_DESCRIPTION NewDescription;
553 PKSPROPERTY_MEMBERSHEADER Header;
554 ULONG BytesReturned;
555 KSP_NODE Request;
556 MIXER_STATUS Status;
557
558 /* try #1 obtain it via description */
559 Request.NodeId = NodeId;
560 Request.Reserved = 0;
561 Request.Property.Set = KSPROPSETID_Audio;
562 Request.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
563 Request.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
564
565 /* get description */
566 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)&Description, sizeof(KSPROPERTY_DESCRIPTION), &BytesReturned);
567 if (Status == MM_STATUS_SUCCESS)
568 {
569 if (Description.DescriptionSize >= sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) && (Description.MembersListCount > 0))
570 {
571 /* allocate new description */
572 NewDescription = MixerContext->Alloc(Description.DescriptionSize);
573
574 if (!NewDescription)
575 {
576 /* not enough memory */
577 return MM_STATUS_NO_MEMORY;
578 }
579
580 /* get description */
581 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)NewDescription, Description.DescriptionSize, &BytesReturned);
582 if (Status == MM_STATUS_SUCCESS)
583 {
584 /* get header */
585 Header = (PKSPROPERTY_MEMBERSHEADER)(NewDescription + 1);
586
587 if (Header->Flags & KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL)
588 {
589 /* found enhanced flag */
590 ASSERT(Header->MembersCount > 1);
591
592 /* store channel count */
593 *MaxChannels = Header->MembersCount;
594
595 /* free description */
596 MixerContext->Free(NewDescription);
597
598 /* done */
599 return MM_STATUS_SUCCESS;
600 }
601 }
602
603 /* free description */
604 MixerContext->Free(NewDescription);
605 }
606 }
607
608 /* failed to get channel count enhanced */
609 return MM_STATUS_UNSUCCESSFUL;
610 }
611
612 VOID
MMixerGetChannelCountLegacy(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG NodeId,OUT PULONG MaxChannels)613 MMixerGetChannelCountLegacy(
614 IN PMIXER_CONTEXT MixerContext,
615 IN LPMIXER_INFO MixerInfo,
616 IN HANDLE hMixer,
617 IN ULONG NodeId,
618 OUT PULONG MaxChannels)
619 {
620 ULONG BytesReturned;
621 MIXER_STATUS Status;
622 KSNODEPROPERTY_AUDIO_CHANNEL Channel;
623 LONG Volume;
624
625 /* setup request */
626 Channel.Reserved = 0;
627 Channel.NodeProperty.NodeId = NodeId;
628 Channel.NodeProperty.Reserved = 0;
629 Channel.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
630 Channel.NodeProperty.Property.Set = KSPROPSETID_Audio;
631 Channel.Channel = 0;
632 Channel.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
633
634 do
635 {
636 /* get channel volume */
637 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Channel, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Volume, sizeof(LONG), &BytesReturned);
638 if (Status != MM_STATUS_SUCCESS)
639 break;
640
641 /* increment channel count */
642 Channel.Channel++;
643
644 }while(TRUE);
645
646 /* store channel count */
647 *MaxChannels = Channel.Channel;
648
649 }
650
651 VOID
MMixerGetMaxChannelsForNode(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG NodeId,OUT PULONG MaxChannels)652 MMixerGetMaxChannelsForNode(
653 IN PMIXER_CONTEXT MixerContext,
654 IN LPMIXER_INFO MixerInfo,
655 IN HANDLE hMixer,
656 IN ULONG NodeId,
657 OUT PULONG MaxChannels)
658 {
659 MIXER_STATUS Status;
660
661 /* try to get it enhanced */
662 Status = MMixerGetChannelCountEnhanced(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
663
664 if (Status != MM_STATUS_SUCCESS)
665 {
666 /* get it old-fashioned way */
667 MMixerGetChannelCountLegacy(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
668 }
669 }
670
671 MIXER_STATUS
MMixerAddMixerControlsToMixerLineByNodeIndexArray(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN PTOPOLOGY Topology,IN OUT LPMIXERLINE_EXT DstLine,IN ULONG NodesCount,IN PULONG Nodes)672 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
673 IN PMIXER_CONTEXT MixerContext,
674 IN LPMIXER_INFO MixerInfo,
675 IN HANDLE hMixer,
676 IN PTOPOLOGY Topology,
677 IN OUT LPMIXERLINE_EXT DstLine,
678 IN ULONG NodesCount,
679 IN PULONG Nodes)
680 {
681 ULONG Index, Count, bReserved;
682 MIXER_STATUS Status;
683 LPGUID NodeType;
684 ULONG MaxChannels;
685
686 /* initialize control count */
687 Count = 0;
688
689 for(Index = 0; Index < NodesCount; Index++)
690 {
691 /* check if the node has already been reserved to a line */
692 MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
693 #if 0 /* MS lies */
694 if (bReserved)
695 {
696 /* node is already used, skip it */
697 continue;
698 }
699 #endif
700 /* set node status as used */
701 MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
702
703 /* query node type */
704 NodeType = MMixerGetNodeTypeFromTopology(Topology, Nodes[Index]);
705
706 if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_VOLUME))
707 {
708 /* calculate maximum channel count for node */
709 MMixerGetMaxChannelsForNode(MixerContext, MixerInfo, hMixer, Nodes[Index], &MaxChannels);
710
711 DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes[Index], MaxChannels, DstLine->Line.szName, DstLine->Line.dwLineID);
712 /* calculate maximum channels */
713 DstLine->Line.cChannels = min(DstLine->Line.cChannels, MaxChannels);
714 }
715 else
716 {
717 /* use default of one channel */
718 MaxChannels = 1;
719 }
720
721 /* now add the mixer control */
722 Status = MMixerAddMixerControl(MixerContext, MixerInfo, hMixer, Topology, Nodes[Index], DstLine, MaxChannels);
723
724 if (Status == MM_STATUS_SUCCESS)
725 {
726 /* increment control count */
727 Count++;
728 }
729 }
730
731 /* store control count */
732 DstLine->Line.cControls = Count;
733
734 /* done */
735 return MM_STATUS_SUCCESS;
736 }
737
738 MIXER_STATUS
MMixerGetComponentAndTargetType(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN ULONG PinId,OUT PULONG ComponentType,OUT PULONG TargetType)739 MMixerGetComponentAndTargetType(
740 IN PMIXER_CONTEXT MixerContext,
741 IN OUT LPMIXER_INFO MixerInfo,
742 IN HANDLE hMixer,
743 IN ULONG PinId,
744 OUT PULONG ComponentType,
745 OUT PULONG TargetType)
746 {
747 KSPIN_DATAFLOW DataFlow;
748 KSPIN_COMMUNICATION Communication;
749 MIXER_STATUS Status;
750 KSP_PIN Request;
751 ULONG BytesReturned;
752 GUID Guid;
753 BOOLEAN BridgePin = FALSE;
754 PKSPIN_PHYSICALCONNECTION Connection;
755
756 /* first dataflow type */
757 Status = MMixerGetPinDataFlowAndCommunication(MixerContext, hMixer, PinId, &DataFlow, &Communication);
758
759 if (Status != MM_STATUS_SUCCESS)
760 {
761 /* failed to get dataflow */
762 return Status;
763 }
764
765 /* now get pin category guid */
766 Request.PinId = PinId;
767 Request.Reserved = 0;
768 Request.Property.Flags = KSPROPERTY_TYPE_GET;
769 Request.Property.Set = KSPROPSETID_Pin;
770 Request.Property.Id = KSPROPERTY_PIN_CATEGORY;
771
772 /* get pin category */
773 Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_PIN), &Guid, sizeof(GUID), &BytesReturned);
774 if (Status != MM_STATUS_SUCCESS)
775 {
776 /* failed to get dataflow */
777 return Status;
778 }
779
780 /* check if it has a physical connection */
781 Status = MMixerGetPhysicalConnection(MixerContext, hMixer, PinId, &Connection);
782 if (Status == MM_STATUS_SUCCESS)
783 {
784 /* pin is a brige pin */
785 BridgePin = TRUE;
786
787 /* free physical connection */
788 MixerContext->Free(Connection);
789 }
790
791 if (DataFlow == KSPIN_DATAFLOW_IN)
792 {
793 if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_MICROPHONE) ||
794 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_MICROPHONE))
795 {
796 /* type microphone */
797 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
798 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
799 }
800 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR) ||
801 IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
802 IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER))
803 {
804 /* type waveout */
805 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
806 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
807 }
808 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_CD_PLAYER))
809 {
810 /* type cd player */
811 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
812 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
813 }
814 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SYNTHESIZER))
815 {
816 /* type synthesizer */
817 *TargetType = MIXERLINE_TARGETTYPE_MIDIOUT;
818 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
819 }
820 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LINE_CONNECTOR))
821 {
822 /* type line */
823 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
824 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
825 }
826 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
827 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
828 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
829 {
830 /* type telephone */
831 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
832 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
833 }
834 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
835 {
836 /* type analog */
837 if (BridgePin)
838 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
839 else
840 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
841
842 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_ANALOG;
843 }
844 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
845 {
846 /* type analog */
847 if (BridgePin)
848 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
849 else
850 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
851
852 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
853 }
854 else
855 {
856 /* unknown type */
857 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
858 *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
859 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
860 }
861 }
862 else
863 {
864 if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER) ||
865 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_SPEAKER) ||
866 IsEqualGUIDAligned(&Guid, &KSNODETYPE_ROOM_SPEAKER) ||
867 IsEqualGUIDAligned(&Guid, &KSNODETYPE_COMMUNICATION_SPEAKER))
868 {
869 /* type waveout */
870 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
871 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
872 }
873 else if (IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
874 IsEqualGUIDAligned(&Guid, &PINNAME_CAPTURE))
875 {
876 /* type wavein */
877 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
878 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
879 }
880 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEADPHONES) ||
881 IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO))
882 {
883 /* type head phones */
884 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
885 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
886 }
887 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
888 IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
889 IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
890 {
891 /* type waveout */
892 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
893 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_TELEPHONE;
894 }
895 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
896 {
897 /* type analog */
898 if (BridgePin)
899 {
900 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
901 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
902 }
903 else
904 {
905 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
906 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
907 }
908 }
909 else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
910 {
911 /* type spdif */
912 if (BridgePin)
913 {
914 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
915 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
916 }
917 else
918 {
919 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
920 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
921 }
922 }
923 else
924 {
925 /* unknown type */
926 *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
927 *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
928 DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
929 }
930 }
931
932 /* done */
933 return MM_STATUS_SUCCESS;
934 }
935
936 MIXER_STATUS
MMixerBuildMixerSourceLine(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN PTOPOLOGY Topology,IN ULONG PinId,IN ULONG NodesCount,IN PULONG Nodes,IN ULONG DestinationLineID,OUT LPMIXERLINE_EXT * OutSrcLine)937 MMixerBuildMixerSourceLine(
938 IN PMIXER_CONTEXT MixerContext,
939 IN OUT LPMIXER_INFO MixerInfo,
940 IN HANDLE hMixer,
941 IN PTOPOLOGY Topology,
942 IN ULONG PinId,
943 IN ULONG NodesCount,
944 IN PULONG Nodes,
945 IN ULONG DestinationLineID,
946 OUT LPMIXERLINE_EXT * OutSrcLine)
947 {
948 LPMIXERLINE_EXT SrcLine, DstLine;
949 LPWSTR PinName;
950 MIXER_STATUS Status;
951 ULONG ComponentType, TargetType;
952
953 /* get component and target type */
954 Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, hMixer, PinId, &ComponentType, &TargetType);
955 if (Status != MM_STATUS_SUCCESS)
956 {
957 /* failed to get component status */
958 TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
959 ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
960 }
961
962 /* construct source line */
963 SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
964
965 if (!SrcLine)
966 {
967 /* no memory */
968 return MM_STATUS_NO_MEMORY;
969 }
970
971 /* get destination line */
972 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
973 ASSERT(DstLine);
974
975 /* initialize mixer src line */
976 SrcLine->PinId = PinId;
977
978 /* initialize mixer line */
979 SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
980 SrcLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations-1;
981 SrcLine->Line.dwSource = DstLine->Line.cConnections;
982 SrcLine->Line.dwLineID = (DstLine->Line.cConnections * SOURCE_LINE)+ (MixerInfo->MixCaps.cDestinations-1);
983 SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
984 SrcLine->Line.dwComponentType = ComponentType;
985 SrcLine->Line.dwUser = 0;
986 SrcLine->Line.cChannels = DstLine->Line.cChannels;
987 SrcLine->Line.cConnections = 0;
988 SrcLine->Line.Target.dwType = TargetType;
989 SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
990 SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
991 SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
992 SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
993 InitializeListHead(&SrcLine->ControlsList);
994
995 /* copy name */
996 ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
997 wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
998
999 /* get pin name */
1000 Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
1001
1002 if (Status == MM_STATUS_SUCCESS)
1003 {
1004 /* store pin name as line name */
1005 MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1006 SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
1007
1008 MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
1009 SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
1010
1011 /* free pin name buffer */
1012 MixerContext->Free(PinName);
1013 }
1014
1015 /* add the controls to mixer line */
1016 Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, SrcLine, NodesCount, Nodes);
1017 if (Status != MM_STATUS_SUCCESS)
1018 {
1019 /* failed */
1020 return Status;
1021 }
1022
1023 /* store result */
1024 *OutSrcLine = SrcLine;
1025
1026 return MM_STATUS_SUCCESS;
1027 }
1028
1029 MIXER_STATUS
MMixerAddMixerSourceLines(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN PTOPOLOGY Topology,IN ULONG DestinationLineID,IN ULONG LineTerminator)1030 MMixerAddMixerSourceLines(
1031 IN PMIXER_CONTEXT MixerContext,
1032 IN OUT LPMIXER_INFO MixerInfo,
1033 IN HANDLE hMixer,
1034 IN PTOPOLOGY Topology,
1035 IN ULONG DestinationLineID,
1036 IN ULONG LineTerminator)
1037 {
1038 PULONG AllNodes, AllPins, AllPinNodes;
1039 ULONG AllNodesCount, AllPinsCount, AllPinNodesCount;
1040 ULONG Index, SubIndex, PinId, CurNode, bConnected;
1041 MIXER_STATUS Status;
1042 LPMIXERLINE_EXT DstLine, SrcLine;
1043
1044 /* get destination line */
1045 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
1046 ASSERT(DstLine);
1047
1048 /* allocate an array to store all nodes which are upstream of the line terminator */
1049 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes);
1050
1051 /* check for success */
1052 if (Status != MM_STATUS_SUCCESS)
1053 {
1054 /* out of memory */
1055 return MM_STATUS_NO_MEMORY;
1056 }
1057
1058 /* allocate an array to store all nodes which are downstream of a particular pin */
1059 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes);
1060
1061 /* allocate an array to store all pins which are upstream of this pin */
1062 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &AllPins);
1063
1064 /* check for success */
1065 if (Status != MM_STATUS_SUCCESS)
1066 {
1067 /* out of memory */
1068 MixerContext->Free(AllNodes);
1069 return MM_STATUS_NO_MEMORY;
1070 }
1071
1072 /* get all nodes which indirectly / directly connect to this node */
1073 AllNodesCount = 0;
1074 MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllNodesCount, AllNodes);
1075
1076 /* get all pins which indirectly / directly connect to this node */
1077 AllPinsCount = 0;
1078 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins);
1079
1080 DPRINT("LineTerminator %lu\n", LineTerminator);
1081 DPRINT("PinCount %lu\n", AllPinsCount);
1082 DPRINT("AllNodesCount %lu\n", AllNodesCount);
1083
1084 /* now construct the source lines which are attached to the destination line */
1085 Index = AllPinsCount;
1086
1087 do
1088 {
1089 /* get current pin id */
1090 PinId = AllPins[Index - 1];
1091
1092 /* reset nodes count */
1093 AllPinNodesCount = 0;
1094
1095 /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
1096 for(SubIndex = 0; SubIndex < AllNodesCount; SubIndex++)
1097 {
1098 /* get current node index */
1099 CurNode = AllNodes[SubIndex];
1100
1101 if (CurNode != MAXULONG && CurNode != LineTerminator)
1102 {
1103 /* check if that node is connected in some way to the current pin */
1104 Status = MMixerIsNodeConnectedToPin(MixerContext, Topology, CurNode, PinId, TRUE, &bConnected);
1105
1106 if (Status != MM_STATUS_SUCCESS)
1107 break;
1108
1109 if (bConnected)
1110 {
1111 /* it is connected */
1112 AllPinNodes[AllPinNodesCount] = CurNode;
1113 AllPinNodesCount++;
1114
1115 /* clear current index */
1116 AllNodes[SubIndex] = MAXULONG;
1117 }
1118 }
1119 }
1120
1121 /* decrement pin index */
1122 Index--;
1123
1124 if (AllPinNodesCount)
1125 {
1126 #ifdef MMIXER_DEBUG
1127 ULONG TempIndex;
1128 #endif
1129 /* now build the mixer source line */
1130 Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, hMixer, Topology, PinId, AllPinNodesCount, AllPinNodes, DestinationLineID, &SrcLine);
1131
1132 if (Status == MM_STATUS_SUCCESS)
1133 {
1134 /* insert into line list */
1135 InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
1136
1137 /* increment destination line count */
1138 DstLine->Line.cConnections++;
1139
1140 /* mark pin as reserved */
1141 MMixerSetTopologyPinReserved(Topology, PinId);
1142
1143 #ifdef MMIXER_DEBUG
1144 DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId, AllPinNodesCount, DestinationLineID);
1145 for(TempIndex = 0; TempIndex < AllPinNodesCount; TempIndex++)
1146 DPRINT1("NodeIndex %lu\n", AllPinNodes[TempIndex]);
1147 #endif
1148 }
1149 }
1150 else
1151 {
1152 #ifdef MMIXER_DEBUG
1153 DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID, PinId);
1154 #endif
1155 }
1156
1157 }while(Index != 0);
1158
1159 return MM_STATUS_SUCCESS;
1160 }
1161
1162 MIXER_STATUS
MMixerAddMixerControlsToDestinationLine(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN HANDLE hMixer,IN PTOPOLOGY Topology,IN ULONG PinId,IN ULONG bInput,IN ULONG DestinationLineId,OUT PULONG OutLineTerminator)1163 MMixerAddMixerControlsToDestinationLine(
1164 IN PMIXER_CONTEXT MixerContext,
1165 IN OUT LPMIXER_INFO MixerInfo,
1166 IN HANDLE hMixer,
1167 IN PTOPOLOGY Topology,
1168 IN ULONG PinId,
1169 IN ULONG bInput,
1170 IN ULONG DestinationLineId,
1171 OUT PULONG OutLineTerminator)
1172 {
1173 PULONG Nodes;
1174 ULONG NodesCount, LineTerminator;
1175 MIXER_STATUS Status;
1176 LPMIXERLINE_EXT DstLine;
1177
1178 /* allocate nodes index array */
1179 Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
1180
1181 /* check for success */
1182 if (Status != MM_STATUS_SUCCESS)
1183 {
1184 /* out of memory */
1185 return Status;
1186 }
1187
1188 /* get all destination line controls */
1189 Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
1190
1191 /* check for success */
1192 if (Status != MM_STATUS_SUCCESS)
1193 {
1194 /* failed to count controls */
1195 MixerContext->Free(Nodes);
1196 return Status;
1197 }
1198
1199 /* get destination mixer line */
1200 DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
1201
1202 /* sanity check */
1203 ASSERT(DstLine);
1204
1205 if (NodesCount > 0)
1206 {
1207 /* add all nodes as mixer controls to the destination line */
1208 Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, DstLine, NodesCount, Nodes);
1209 if (Status != MM_STATUS_SUCCESS)
1210 {
1211 /* failed to add controls */
1212 MixerContext->Free(Nodes);
1213 return Status;
1214 }
1215 }
1216
1217 /* store result */
1218 *OutLineTerminator = LineTerminator;
1219
1220 /* return result */
1221 return Status;
1222 }
1223
1224 VOID
MMixerApplyOutputFilterHack(IN PMIXER_CONTEXT MixerContext,IN LPMIXER_DATA MixerData,IN HANDLE hMixer,IN OUT PULONG PinsCount,IN OUT PULONG Pins)1225 MMixerApplyOutputFilterHack(
1226 IN PMIXER_CONTEXT MixerContext,
1227 IN LPMIXER_DATA MixerData,
1228 IN HANDLE hMixer,
1229 IN OUT PULONG PinsCount,
1230 IN OUT PULONG Pins)
1231 {
1232 ULONG Count = 0, Index;
1233 MIXER_STATUS Status;
1234 PKSPIN_PHYSICALCONNECTION Connection;
1235
1236 for(Index = 0; Index < *PinsCount; Index++)
1237 {
1238 /* check if it has a physical connection */
1239 Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Pins[Index], &Connection);
1240
1241 if (Status == MM_STATUS_SUCCESS)
1242 {
1243 /* remove pin */
1244 MixerContext->Copy(&Pins[Index], &Pins[Index + 1], (*PinsCount - (Index + 1)) * sizeof(ULONG));
1245
1246 /* free physical connection */
1247 MixerContext->Free(Connection);
1248
1249 /* decrement index */
1250 Index--;
1251
1252 /* decrement pin count */
1253 (*PinsCount)--;
1254 }
1255 else
1256 {
1257 /* simple pin */
1258 Count++;
1259 }
1260 }
1261
1262 /* store result */
1263 *PinsCount = Count;
1264 }
1265
1266 MIXER_STATUS
MMixerHandleTopologyFilter(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList,IN LPMIXER_DATA MixerData,IN OUT LPMIXER_INFO MixerInfo,IN ULONG bInput,IN ULONG Pin)1267 MMixerHandleTopologyFilter(
1268 IN PMIXER_CONTEXT MixerContext,
1269 IN PMIXER_LIST MixerList,
1270 IN LPMIXER_DATA MixerData,
1271 IN OUT LPMIXER_INFO MixerInfo,
1272 IN ULONG bInput,
1273 IN ULONG Pin)
1274 {
1275 MIXER_STATUS Status;
1276 ULONG PinsCount, LineTerminator, DestinationLineID;
1277 PULONG Pins;
1278 PTOPOLOGY Topology;
1279
1280 /* re-use existing topology */
1281 Topology = MixerData->Topology;
1282
1283 if (!bInput)
1284 {
1285 /* allocate pin index array which will hold all referenced pins */
1286 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1287 if (Status != MM_STATUS_SUCCESS)
1288 {
1289 /* failed to create topology */
1290 return Status;
1291 }
1292
1293 /* the mixer is an output mixer
1294 * find end pin of the node path
1295 */
1296 PinsCount = 0;
1297 Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, Pin, FALSE, &PinsCount, Pins);
1298
1299 /* check for success */
1300 if (Status != MM_STATUS_SUCCESS)
1301 {
1302 /* failed to get end pin */
1303 MixerContext->Free(Pins);
1304 //MMixerFreeTopology(Topology);
1305
1306 /* return error code */
1307 return Status;
1308 }
1309 /* HACK:
1310 * some topologies do not have strict boundaries
1311 * WorkArround: remove all pin ids which have a physical connection
1312 * because bridge pins may belong to different render paths
1313 */
1314 MMixerApplyOutputFilterHack(MixerContext, MixerData, MixerData->hDevice, &PinsCount, Pins);
1315
1316 /* sanity checks */
1317 ASSERT(PinsCount != 0);
1318 if (PinsCount != 1)
1319 {
1320 DPRINT1("MMixerHandlePhysicalConnection Expected 1 pin but got %lu\n", PinsCount);
1321 }
1322
1323 /* create destination line */
1324 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInput);
1325
1326 /* calculate destination line id */
1327 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations - 1);
1328
1329 if (Status != MM_STATUS_SUCCESS)
1330 {
1331 /* failed to build destination line */
1332 MixerContext->Free(Pins);
1333
1334 /* return error code */
1335 return Status;
1336 }
1337
1338 /* add mixer controls to destination line */
1339 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pins[0], bInput, DestinationLineID, &LineTerminator);
1340
1341 if (Status == MM_STATUS_SUCCESS)
1342 {
1343 /* now add the rest of the source lines */
1344 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
1345 }
1346
1347 /* mark pin as consumed */
1348 MMixerSetTopologyPinReserved(Topology, Pins[0]);
1349
1350 /* free topology pin array */
1351 MixerContext->Free(Pins);
1352 }
1353 else
1354 {
1355 /* calculate destination line id */
1356 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations - 1);
1357
1358 /* add mixer controls */
1359 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pin, bInput, DestinationLineID, &LineTerminator);
1360
1361 if (Status == MM_STATUS_SUCCESS)
1362 {
1363 /* now add the rest of the source lines */
1364 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
1365 }
1366 }
1367 return Status;
1368 }
1369
1370 MIXER_STATUS
MMixerHandlePhysicalConnection(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList,IN LPMIXER_DATA MixerData,IN OUT LPMIXER_INFO MixerInfo,IN ULONG bInput,IN PKSPIN_PHYSICALCONNECTION OutConnection)1371 MMixerHandlePhysicalConnection(
1372 IN PMIXER_CONTEXT MixerContext,
1373 IN PMIXER_LIST MixerList,
1374 IN LPMIXER_DATA MixerData,
1375 IN OUT LPMIXER_INFO MixerInfo,
1376 IN ULONG bInput,
1377 IN PKSPIN_PHYSICALCONNECTION OutConnection)
1378 {
1379 MIXER_STATUS Status;
1380 ULONG PinsCount, LineTerminator, DestinationLineID;
1381 PULONG Pins;
1382 PTOPOLOGY Topology;
1383
1384 /* first try to open the connected filter */
1385 OutConnection->SymbolicLinkName[1] = L'\\';
1386 MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
1387
1388 /* check if the linked connection is found */
1389 if (!MixerData)
1390 {
1391 /* filter references invalid physical connection */
1392 return MM_STATUS_UNSUCCESSFUL;
1393 }
1394
1395 DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
1396
1397 /* sanity check */
1398 ASSERT(MixerData->MixerInfo == NULL || MixerData->MixerInfo == MixerInfo);
1399
1400 /* associate with mixer */
1401 MixerData->MixerInfo = MixerInfo;
1402
1403 if (MixerData->Topology == NULL)
1404 {
1405 /* construct new topology */
1406 Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
1407 if (Status != MM_STATUS_SUCCESS)
1408 {
1409 /* failed to create topology */
1410 return Status;
1411 }
1412
1413 /* store topology */
1414 MixerData->Topology = Topology;
1415 }
1416 else
1417 {
1418 /* re-use existing topology */
1419 Topology = MixerData->Topology;
1420 }
1421
1422 /* mark pin as consumed */
1423 MMixerSetTopologyPinReserved(Topology, OutConnection->Pin);
1424
1425 if (!bInput)
1426 {
1427 /* allocate pin index array which will hold all referenced pins */
1428 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1429 if (Status != MM_STATUS_SUCCESS)
1430 {
1431 /* failed to create topology */
1432 return Status;
1433 }
1434
1435 /* the mixer is an output mixer
1436 * find end pin of the node path
1437 */
1438 PinsCount = 0;
1439 Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins);
1440
1441 /* check for success */
1442 if (Status != MM_STATUS_SUCCESS)
1443 {
1444 /* failed to get end pin */
1445 MixerContext->Free(Pins);
1446 //MMixerFreeTopology(Topology);
1447
1448 /* return error code */
1449 return Status;
1450 }
1451 /* HACK:
1452 * some topologies do not have strict boundaries
1453 * WorkArround: remove all pin ids which have a physical connection
1454 * because bridge pins may belong to different render paths
1455 */
1456 MMixerApplyOutputFilterHack(MixerContext, MixerData, MixerData->hDevice, &PinsCount, Pins);
1457
1458 /* sanity checks */
1459 ASSERT(PinsCount != 0);
1460 if (PinsCount != 1)
1461 {
1462 DPRINT1("MMixerHandlePhysicalConnection Expected 1 pin but got %lu\n", PinsCount);
1463 }
1464
1465 /* create destination line */
1466 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInput);
1467
1468 /* calculate destination line id */
1469 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
1470
1471 if (Status != MM_STATUS_SUCCESS)
1472 {
1473 /* failed to build destination line */
1474 MixerContext->Free(Pins);
1475
1476 /* return error code */
1477 return Status;
1478 }
1479
1480 /* add mixer controls to destination line */
1481 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pins[0], bInput, DestinationLineID, &LineTerminator);
1482
1483 if (Status == MM_STATUS_SUCCESS)
1484 {
1485 /* now add the rest of the source lines */
1486 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
1487 }
1488
1489 /* mark pin as consumed */
1490 MMixerSetTopologyPinReserved(Topology, Pins[0]);
1491
1492 /* free topology pin array */
1493 MixerContext->Free(Pins);
1494 }
1495 else
1496 {
1497 /* calculate destination line id */
1498 DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
1499
1500 /* add mixer controls */
1501 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
1502
1503 if (Status == MM_STATUS_SUCCESS)
1504 {
1505 /* now add the rest of the source lines */
1506 Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
1507 }
1508 }
1509
1510 return Status;
1511 }
1512
1513 MIXER_STATUS
MMixerInitializeFilter(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList,IN LPMIXER_DATA MixerData,IN LPMIXER_INFO MixerInfo,IN PTOPOLOGY Topology,IN ULONG NodeIndex,IN ULONG bInputMixer,IN OUT LPMIXER_INFO * OutMixerInfo)1514 MMixerInitializeFilter(
1515 IN PMIXER_CONTEXT MixerContext,
1516 IN PMIXER_LIST MixerList,
1517 IN LPMIXER_DATA MixerData,
1518 IN LPMIXER_INFO MixerInfo,
1519 IN PTOPOLOGY Topology,
1520 IN ULONG NodeIndex,
1521 IN ULONG bInputMixer,
1522 IN OUT LPMIXER_INFO * OutMixerInfo)
1523 {
1524 ULONG Index;
1525 MIXER_STATUS Status;
1526 PKSPIN_PHYSICALCONNECTION OutConnection;
1527 ULONG * Pins;
1528 ULONG PinsFound;
1529 ULONG NewMixerInfo = FALSE;
1530
1531 if (MixerInfo == NULL)
1532 {
1533 /* allocate a mixer info struct */
1534 MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
1535 if (!MixerInfo)
1536 {
1537 /* no memory */
1538 return MM_STATUS_NO_MEMORY;
1539 }
1540
1541 /* new mixer info */
1542 NewMixerInfo = TRUE;
1543
1544 /* intialize mixer caps */
1545 MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
1546 MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
1547 MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
1548 MixerInfo->MixCaps.fdwSupport = 0;
1549 MixerInfo->MixCaps.cDestinations = 0;
1550
1551 /* get mixer name */
1552 Status = MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
1553 if (Status != MM_STATUS_SUCCESS)
1554 {
1555 /* try get name with component id */
1556 Status = MMixerGetDeviceNameWithComponentId(MixerContext, MixerData->hDevice, MixerInfo->MixCaps.szPname);
1557 if (Status != MM_STATUS_SUCCESS)
1558 {
1559 MixerInfo->MixCaps.szPname[0] = L'\0';
1560 }
1561 }
1562
1563 /* initialize line list */
1564 InitializeListHead(&MixerInfo->LineList);
1565 InitializeListHead(&MixerInfo->EventList);
1566
1567 /* associate with mixer data */
1568 MixerData->MixerInfo = MixerInfo;
1569 }
1570
1571 /* store mixer info */
1572 *OutMixerInfo = MixerInfo;
1573
1574 /* now allocate an array which will receive the indices of the pin
1575 * which has a ADC / DAC nodetype in its path
1576 */
1577 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1578 ASSERT(Status == MM_STATUS_SUCCESS);
1579
1580 PinsFound = 0;
1581
1582 /* now get all sink / source pins, which are attached to the ADC / DAC node
1583 * For sink pins (wave out) search up stream
1584 * For source pins (wave in) search down stream
1585 * The search direction is always the opposite of the current mixer type
1586 */
1587 PinsFound = 0;
1588 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
1589
1590 /* if there is no pin found, we have a broken topology */
1591 ASSERT(PinsFound != 0);
1592
1593 /* now create a wave info struct */
1594 Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
1595 if (Status != MM_STATUS_SUCCESS)
1596 {
1597 /* failed to create wave info struct */
1598 MixerContext->Free(MixerInfo);
1599 MixerContext->Free(Pins);
1600 return Status;
1601 }
1602
1603 /* mark all found pins as reserved */
1604 for(Index = 0; Index < PinsFound; Index++)
1605 {
1606 MMixerSetTopologyPinReserved(Topology, Pins[Index]);
1607 }
1608
1609 if (bInputMixer)
1610 {
1611 /* pre create the mixer destination line for input mixers */
1612 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInputMixer);
1613
1614 if (Status != MM_STATUS_SUCCESS)
1615 {
1616 /* failed to create mixer destination line */
1617 return Status;
1618 }
1619 }
1620
1621 /* now get the bridge pin which is at the end of node path
1622 * For sink pins (wave out) search down stream
1623 * For source pins (wave in) search up stream
1624 */
1625 MixerContext->Free(Pins);
1626 Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
1627 ASSERT(Status == MM_STATUS_SUCCESS);
1628
1629 PinsFound = 0;
1630 MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins);
1631
1632 /* if there is no pin found, we have a broken topology */
1633 ASSERT(PinsFound != 0);
1634
1635 /* there should be exactly one bridge pin */
1636 ASSERT(PinsFound == 1);
1637
1638 DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer);
1639
1640 /* does the pin have a physical connection */
1641 Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection);
1642
1643 if (Status == MM_STATUS_SUCCESS)
1644 {
1645 /* mark pin as reserved */
1646 MMixerSetTopologyPinReserved(Topology, Pins[0]);
1647
1648 /* topology on the topoloy filter */
1649 Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
1650
1651 /* free physical connection data */
1652 MixerContext->Free(OutConnection);
1653 }
1654 else
1655 {
1656 /* topology is on the same filter */
1657 Status = MMixerHandleTopologyFilter(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, Pins[0]);
1658 }
1659
1660 /* free pins */
1661 MixerContext->Free(Pins);
1662
1663 if (NewMixerInfo)
1664 {
1665 /* insert mixer */
1666 InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
1667 /* increment mixer count */
1668 MixerList->MixerListCount++;
1669 }
1670
1671 /* done */
1672 return Status;
1673 }
1674
1675 VOID
MMixerHandleAlternativeMixers(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList,IN LPMIXER_DATA MixerData,IN PTOPOLOGY Topology)1676 MMixerHandleAlternativeMixers(
1677 IN PMIXER_CONTEXT MixerContext,
1678 IN PMIXER_LIST MixerList,
1679 IN LPMIXER_DATA MixerData,
1680 IN PTOPOLOGY Topology)
1681 {
1682 ULONG Index, PinCount, Reserved;
1683 MIXER_STATUS Status;
1684 ULONG DestinationLineID, LineTerminator;
1685 LPMIXERLINE_EXT DstLine;
1686
1687 DPRINT("DeviceName %S\n", MixerData->DeviceName);
1688
1689 /* get topology pin count */
1690 MMixerGetTopologyPinCount(Topology, &PinCount);
1691
1692 for(Index = 0; Index < PinCount; Index++)
1693 {
1694 MMixerIsTopologyPinReserved(Topology, Index, &Reserved);
1695
1696 /* check if it has already been reserved */
1697 if (Reserved)
1698 {
1699 /* pin has already been reserved */
1700 continue;
1701 }
1702
1703 DPRINT("MixerName %S Available PinID %lu\n", MixerData->DeviceName, Index);
1704
1705 /* sanity check */
1706 //ASSERT(MixerData->MixerInfo);
1707
1708 if (!MixerData->MixerInfo)
1709 {
1710 DPRINT1("Expected mixer info\n");
1711 continue;
1712 }
1713
1714 /* build the destination line */
1715 Status = MMixerBuildMixerDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, Index, TRUE);
1716 if (Status != MM_STATUS_SUCCESS)
1717 {
1718 /* failed to build destination line */
1719 continue;
1720 }
1721
1722 /* calculate destination line id */
1723 DestinationLineID = (DESTINATION_LINE + MixerData->MixerInfo->MixCaps.cDestinations-1);
1724
1725 /* add mixer controls to destination line */
1726 Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, Index, TRUE, DestinationLineID, &LineTerminator);
1727 if (Status == MM_STATUS_SUCCESS)
1728 {
1729 /* now add the rest of the source lines */
1730 Status = MMixerAddMixerSourceLines(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, DestinationLineID, LineTerminator);
1731 }
1732
1733 /* mark pin as consumed */
1734 MMixerSetTopologyPinReserved(Topology, Index);
1735
1736 /* now grab destination line */
1737 DstLine = MMixerGetSourceMixerLineByLineId(MixerData->MixerInfo, DestinationLineID);
1738
1739 /* set type and target as undefined */
1740 DstLine->Line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
1741 DstLine->Line.Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
1742 DstLine->Line.Target.vDriverVersion = 0;
1743 DstLine->Line.Target.wMid = 0;
1744 DstLine->Line.Target.wPid = 0;
1745 }
1746 }
1747
1748 MIXER_STATUS
MMixerSetupFilter(IN PMIXER_CONTEXT MixerContext,IN PMIXER_LIST MixerList,IN LPMIXER_DATA MixerData,IN PULONG DeviceCount)1749 MMixerSetupFilter(
1750 IN PMIXER_CONTEXT MixerContext,
1751 IN PMIXER_LIST MixerList,
1752 IN LPMIXER_DATA MixerData,
1753 IN PULONG DeviceCount)
1754 {
1755 MIXER_STATUS Status = MM_STATUS_SUCCESS;
1756 PTOPOLOGY Topology;
1757 ULONG NodeIndex;
1758 LPMIXER_INFO MixerInfo = NULL;
1759
1760 /* check if topology has already been built */
1761 if (MixerData->Topology == NULL)
1762 {
1763 /* build topology */
1764 Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
1765
1766 if (Status != MM_STATUS_SUCCESS)
1767 {
1768 /* failed to build topology */
1769 return Status;
1770 }
1771
1772 /* store topology */
1773 MixerData->Topology = Topology;
1774 }
1775 else
1776 {
1777 /* re-use topology */
1778 Topology = MixerData->Topology;
1779 }
1780
1781 /* check if the filter has an wave out node */
1782 NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_DAC);
1783 if (NodeIndex != MAXULONG)
1784 {
1785 /* it has */
1786 Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NULL, Topology, NodeIndex, FALSE, &MixerInfo);
1787
1788 /* check for success */
1789 if (Status == MM_STATUS_SUCCESS)
1790 {
1791 /* increment mixer count */
1792 (*DeviceCount)++;
1793 }
1794 else
1795 {
1796 /* reset mixer info in case of error */
1797 MixerInfo = NULL;
1798 }
1799 }
1800
1801 /* check if the filter has an wave in node */
1802 NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_ADC);
1803 if (NodeIndex != MAXULONG)
1804 {
1805 /* it has */
1806 Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, MixerInfo, Topology, NodeIndex, TRUE, &MixerInfo);
1807
1808 /* check for success */
1809 if (Status == MM_STATUS_SUCCESS)
1810 {
1811 /* increment mixer count */
1812 (*DeviceCount)++;
1813 }
1814
1815 }
1816
1817 /* TODO: apply hacks for Wave source line */
1818
1819 /* activate midi devices */
1820 //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
1821
1822 /* done */
1823 return Status;
1824 }
1825
1826 MIXER_STATUS
MMixerAddEvent(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN PVOID MixerEventContext,IN PMIXER_EVENT MixerEventRoutine)1827 MMixerAddEvent(
1828 IN PMIXER_CONTEXT MixerContext,
1829 IN OUT LPMIXER_INFO MixerInfo,
1830 IN PVOID MixerEventContext,
1831 IN PMIXER_EVENT MixerEventRoutine)
1832 {
1833 //KSE_NODE Property;
1834 //KSEVENTDATA EventData
1835 //ULONG BytesReturned;
1836 //MIXER_STATUS Status;
1837 PEVENT_NOTIFICATION_ENTRY EventNotification;
1838
1839 EventNotification = (PEVENT_NOTIFICATION_ENTRY)MixerContext->Alloc(sizeof(EVENT_NOTIFICATION_ENTRY));
1840 if (!EventNotification)
1841 {
1842 /* not enough memory */
1843 return MM_STATUS_NO_MEMORY;
1844 }
1845
1846 /* FIXME: what is it supposed to happen with KSEVENTDATA ? */
1847 #if 0
1848 /* setup request */
1849 Property.Event.Set = KSEVENTSETID_AudioControlChange;
1850 Property.Event.Flags = KSEVENT_TYPE_TOPOLOGY|KSEVENT_TYPE_ENABLE;
1851 Property.Event.Id = KSEVENT_CONTROL_CHANGE;
1852
1853 Property.NodeId = NodeId;
1854 Property.Reserved = 0;
1855
1856 Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSP_NODE), (PVOID)EventData, sizeof(KSEVENTDATA), &BytesReturned);
1857 if (Status != MM_STATUS_SUCCESS)
1858 {
1859 /* failed to add event */
1860 MixerContext->FreeEventData(EventData);
1861 return Status;
1862 }
1863 #endif
1864
1865 /* initialize notification entry */
1866 EventNotification->MixerEventContext = MixerEventContext;
1867 EventNotification->MixerEventRoutine = MixerEventRoutine;
1868
1869 /* store event */
1870 InsertTailList(&MixerInfo->EventList, &EventNotification->Entry);
1871 return MM_STATUS_SUCCESS;
1872 }
1873
1874 MIXER_STATUS
MMixerRemoveEvent(IN PMIXER_CONTEXT MixerContext,IN OUT LPMIXER_INFO MixerInfo,IN PVOID MixerEventContext,IN PMIXER_EVENT MixerEventRoutine)1875 MMixerRemoveEvent(
1876 IN PMIXER_CONTEXT MixerContext,
1877 IN OUT LPMIXER_INFO MixerInfo,
1878 IN PVOID MixerEventContext,
1879 IN PMIXER_EVENT MixerEventRoutine)
1880 {
1881 PLIST_ENTRY EventList;
1882 PEVENT_NOTIFICATION_ENTRY NotificationEntry;
1883
1884 /* Lookup through mixers */
1885 EventList = MixerInfo->EventList.Flink;
1886 while(EventList != &MixerInfo->EventList)
1887 {
1888 NotificationEntry = CONTAINING_RECORD(EventList, EVENT_NOTIFICATION_ENTRY, Entry);
1889 EventList = EventList->Flink;
1890 /* TODO: find a better way to identify an event ? */
1891 if(NotificationEntry->MixerEventRoutine == MixerEventRoutine &&
1892 NotificationEntry->MixerEventContext == MixerEventContext)
1893 {
1894 DPRINT1("Freeing entry %p\n", NotificationEntry);
1895 /* We found the event to remove */
1896 RemoveEntryList(&NotificationEntry->Entry);
1897 MixerContext->Free(NotificationEntry);
1898 }
1899 }
1900 return MM_STATUS_SUCCESS;
1901 }
1902