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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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