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