ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

controls.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS Kernel Streaming
00004  * FILE:            lib/drivers/sound/mmixer/controls.c
00005  * PURPOSE:         Mixer Control Iteration Functions
00006  * PROGRAMMER:      Johannes Anderwald
00007  */
00008  
00009 #include "priv.h"
00010 
00011 const GUID KSNODETYPE_DESKTOP_MICROPHONE = {0xDFF21BE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00012 const GUID KSNODETYPE_LEGACY_AUDIO_CONNECTOR = {0xDFF21FE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00013 const GUID KSNODETYPE_TELEPHONE = {0xDFF21EE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00014 const GUID KSNODETYPE_PHONE_LINE = {0xDFF21EE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00015 const GUID KSNODETYPE_DOWN_LINE_PHONE = {0xDFF21EE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00016 const GUID KSNODETYPE_DESKTOP_SPEAKER = {0xDFF21CE4, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00017 const GUID KSNODETYPE_ROOM_SPEAKER = {0xDFF21CE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00018 const GUID KSNODETYPE_COMMUNICATION_SPEAKER = {0xDFF21CE6, 0xF70F, 0x11D0, {0xB9,0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00019 const GUID KSNODETYPE_HEADPHONES = {0xDFF21CE2, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00020 const GUID KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO = {0xDFF21CE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00021 const GUID KSNODETYPE_MICROPHONE = {0xDFF21BE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9,0x22, 0x31, 0x96}};
00022 const GUID KSCATEGORY_AUDIO = {0x6994AD04L, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00023 const GUID KSNODETYPE_SPDIF_INTERFACE = {0xDFF21FE5, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00024 const GUID KSNODETYPE_ANALOG_CONNECTOR = {0xDFF21FE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00025 const GUID KSNODETYPE_SPEAKER = {0xDFF21CE1, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00026 const GUID KSNODETYPE_CD_PLAYER = {0xDFF220E3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00027 const GUID KSNODETYPE_SYNTHESIZER = {0xDFF220F3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
00028 const GUID KSNODETYPE_LINE_CONNECTOR = {0xDFF21FE3, 0xF70F, 0x11D0, {0xB9, 0x17, 0x00, 0xA0,0xC9, 0x22, 0x31, 0x96}};
00029 const GUID PINNAME_VIDEO_CAPTURE  = {0xfb6c4281, 0x353, 0x11d1, {0x90, 0x5f, 0x0, 0x0, 0xc0, 0xcc, 0x16, 0xba}};
00030 
00031 MIXER_STATUS
00032 MMixerAddMixerControl(
00033     IN PMIXER_CONTEXT MixerContext,
00034     IN LPMIXER_INFO MixerInfo,
00035     IN HANDLE hMixer,
00036     IN PTOPOLOGY Topology,
00037     IN ULONG NodeIndex,
00038     IN LPMIXERLINE_EXT MixerLine,
00039     IN ULONG MaxChannels)
00040 {
00041     LPGUID NodeType;
00042     KSP_NODE Node;
00043     ULONG BytesReturned;
00044     MIXER_STATUS Status;
00045     LPWSTR Name;
00046     LPMIXERCONTROL_EXT MixerControl;
00047 
00048     /* allocate mixer control */
00049     MixerControl = MixerContext->Alloc(sizeof(MIXERCONTROL_EXT));
00050     if (!MixerControl)
00051     {
00052         /* no memory */
00053         return MM_STATUS_NO_MEMORY;
00054     }
00055 
00056 
00057     /* initialize mixer control */
00058     MixerControl->hDevice = hMixer;
00059     MixerControl->NodeID = NodeIndex;
00060     MixerControl->ExtraData = NULL;
00061 
00062     MixerControl->Control.cbStruct = sizeof(MIXERCONTROLW);
00063     MixerControl->Control.dwControlID = MixerInfo->ControlId;
00064 
00065     /* get node type */
00066     NodeType = MMixerGetNodeTypeFromTopology(Topology, NodeIndex);
00067     /* store control type */
00068     MixerControl->Control.dwControlType = MMixerGetControlTypeFromTopologyNode(NodeType);
00069 
00070     MixerControl->Control.fdwControl = (MaxChannels > 1 ? 0 : MIXERCONTROL_CONTROLF_UNIFORM);
00071     MixerControl->Control.cMultipleItems = 0;
00072 
00073     /* setup request to retrieve name */
00074     Node.NodeId = NodeIndex;
00075     Node.Property.Id = KSPROPERTY_TOPOLOGY_NAME;
00076     Node.Property.Flags = KSPROPERTY_TYPE_GET;
00077     Node.Property.Set = KSPROPSETID_Topology;
00078     Node.Reserved = 0;
00079 
00080     /* get node name size */
00081     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), NULL, 0, &BytesReturned);
00082 
00083     if (Status == MM_STATUS_MORE_ENTRIES)
00084     {
00085         ASSERT(BytesReturned != 0);
00086         Name = (LPWSTR)MixerContext->Alloc(BytesReturned);
00087         if (!Name)
00088         {
00089             /* not enough memory */
00090             return MM_STATUS_NO_MEMORY;
00091         }
00092 
00093         /* get node name */
00094         Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Node, sizeof(KSP_NODE), (LPVOID)Name, BytesReturned, &BytesReturned);
00095 
00096         if (Status == MM_STATUS_SUCCESS)
00097         {
00098             MixerContext->Copy(MixerControl->Control.szShortName, Name, (min(MIXER_SHORT_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
00099             MixerControl->Control.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
00100 
00101             MixerContext->Copy(MixerControl->Control.szName, Name, (min(MIXER_LONG_NAME_CHARS, wcslen(Name)+1)) * sizeof(WCHAR));
00102             MixerControl->Control.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
00103         }
00104 
00105         /* free name buffer */
00106         MixerContext->Free(Name);
00107     }
00108 
00109     /* increment control count */
00110     MixerInfo->ControlId++;
00111 
00112     /* insert control */
00113     InsertTailList(&MixerLine->ControlsList, &MixerControl->Entry);
00114 
00115     if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
00116     {
00117         ULONG NodesCount;
00118         PULONG Nodes;
00119 
00120         /* allocate topology nodes array */
00121         Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
00122 
00123         if (Status != MM_STATUS_SUCCESS)
00124         {
00125             /* out of memory */
00126             return STATUS_NO_MEMORY;
00127         }
00128 
00129         /* get connected node count */
00130         MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, TRUE, &NodesCount, Nodes);
00131 
00132         /* TODO */
00133         MixerContext->Free(Nodes);
00134 
00135         /* setup mux bounds */
00136         MixerControl->Control.Bounds.dwMinimum = 0;
00137         MixerControl->Control.Bounds.dwMaximum = NodesCount - 1;
00138         MixerControl->Control.Metrics.dwReserved[0] = NodesCount;
00139         MixerControl->Control.cMultipleItems = NodesCount;
00140         MixerControl->Control.fdwControl |= MIXERCONTROL_CONTROLF_UNIFORM | MIXERCONTROL_CONTROLF_MULTIPLE;
00141     }
00142     else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
00143     {
00144         MixerControl->Control.Bounds.dwMinimum = 0;
00145         MixerControl->Control.Bounds.dwMaximum = 1;
00146     }
00147     else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_ONOFF)
00148     {
00149         /* only needs to set bounds */
00150         MixerControl->Control.Bounds.dwMinimum = 0;
00151         MixerControl->Control.Bounds.dwMaximum = 1;
00152     }
00153     else if (MixerControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
00154     {
00155         KSNODEPROPERTY_AUDIO_CHANNEL Property;
00156         ULONG Length;
00157         PKSPROPERTY_DESCRIPTION Desc;
00158         PKSPROPERTY_MEMBERSHEADER Members;
00159         PKSPROPERTY_STEPPING_LONG Range;
00160 
00161         MixerControl->Control.Bounds.dwMinimum = 0;
00162         MixerControl->Control.Bounds.dwMaximum = 0xFFFF;
00163         MixerControl->Control.Metrics.cSteps = 0xC0; /* FIXME */
00164 
00165         Length = sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG);
00166         Desc = (PKSPROPERTY_DESCRIPTION)MixerContext->Alloc(Length);
00167         ASSERT(Desc);
00168 
00169         /* setup the request */
00170         RtlZeroMemory(&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL));
00171 
00172         Property.NodeProperty.NodeId = NodeIndex;
00173         Property.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
00174         Property.NodeProperty.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
00175         Property.NodeProperty.Property.Set = KSPROPSETID_Audio;
00176 
00177         /* get node volume level info */
00178         Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), Desc, Length, &BytesReturned);
00179 
00180         if (Status == MM_STATUS_SUCCESS)
00181         {
00182             LPMIXERVOLUME_DATA VolumeData;
00183             ULONG Steps, MaxRange, Index;
00184             LONG Value;
00185 
00186             Members = (PKSPROPERTY_MEMBERSHEADER)(Desc + 1);
00187             Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
00188 
00189             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);
00190 
00191             MaxRange = Range->Bounds.UnsignedMaximum  - Range->Bounds.UnsignedMinimum;
00192 
00193             if (MaxRange)
00194             {
00195                 ASSERT(MaxRange);
00196                 VolumeData = (LPMIXERVOLUME_DATA)MixerContext->Alloc(sizeof(MIXERVOLUME_DATA));
00197                 if (!VolumeData)
00198                     return MM_STATUS_NO_MEMORY;
00199 
00200                 Steps = MaxRange / Range->SteppingDelta + 1;
00201 
00202                 /* store mixer control info there */
00203                 VolumeData->Header.dwControlID = MixerControl->Control.dwControlID;
00204                 VolumeData->SignedMaximum = Range->Bounds.SignedMaximum;
00205                 VolumeData->SignedMinimum = Range->Bounds.SignedMinimum;
00206                 VolumeData->SteppingDelta = Range->SteppingDelta;
00207                 VolumeData->ValuesCount = Steps;
00208                 VolumeData->InputSteppingDelta = 0x10000 / Steps;
00209 
00210                 VolumeData->Values = (PLONG)MixerContext->Alloc(sizeof(LONG) * Steps);
00211                 if (!VolumeData->Values)
00212                 {
00213                     MixerContext->Free(Desc);
00214                     MixerContext->Free(VolumeData);
00215                     return MM_STATUS_NO_MEMORY;
00216                 }
00217 
00218                 Value = Range->Bounds.SignedMinimum;
00219                 for(Index = 0; Index < Steps; Index++)
00220                 {
00221                     VolumeData->Values[Index] = Value;
00222                     Value += Range->SteppingDelta;
00223                 }
00224                 MixerControl->ExtraData = VolumeData;
00225            }
00226        }
00227        MixerContext->Free(Desc);
00228     }
00229 
00230     DPRINT("Status %x Name %S\n", Status, MixerControl->Control.szName);
00231     return MM_STATUS_SUCCESS;
00232 }
00233 
00234 MIXER_STATUS
00235 MMixerCreateDestinationLine(
00236     IN PMIXER_CONTEXT MixerContext,
00237     IN LPMIXER_INFO MixerInfo,
00238     IN ULONG bInputMixer,
00239     IN LPWSTR LineName)
00240 {
00241     LPMIXERLINE_EXT DestinationLine;
00242 
00243     /* allocate a mixer destination line */
00244     DestinationLine = (LPMIXERLINE_EXT) MixerContext->Alloc(sizeof(MIXERLINE_EXT));
00245     if (!MixerInfo)
00246     {
00247         /* no memory */
00248         return MM_STATUS_NO_MEMORY;
00249     }
00250 
00251     /* initialize mixer destination line */
00252     DestinationLine->Line.cbStruct = sizeof(MIXERLINEW);
00253     DestinationLine->Line.cChannels = 2; /* FIXME */
00254     DestinationLine->Line.cConnections = 0;
00255     DestinationLine->Line.cControls = 0;
00256     DestinationLine->Line.dwComponentType = (bInputMixer == 0 ? MIXERLINE_COMPONENTTYPE_DST_SPEAKERS : MIXERLINE_COMPONENTTYPE_DST_WAVEIN);
00257     DestinationLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations;
00258     DestinationLine->Line.dwLineID = MixerInfo->MixCaps.cDestinations + DESTINATION_LINE;
00259     DestinationLine->Line.dwSource = MAXULONG;
00260     DestinationLine->Line.dwUser = 0;
00261     DestinationLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE;
00262 
00263 
00264     if (LineName)
00265     {
00266         MixerContext->Copy(DestinationLine->Line.szShortName, LineName, (min(MIXER_SHORT_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
00267         DestinationLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
00268 
00269         MixerContext->Copy(DestinationLine->Line.szName, LineName, (min(MIXER_LONG_NAME_CHARS, wcslen(LineName)+1)) * sizeof(WCHAR));
00270         DestinationLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
00271 
00272     }
00273 
00274     DestinationLine->Line.Target.dwType = (bInputMixer == 0 ? MIXERLINE_TARGETTYPE_WAVEOUT : MIXERLINE_TARGETTYPE_WAVEIN);
00275     DestinationLine->Line.Target.dwDeviceID = 0; //FIXME
00276     DestinationLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
00277     DestinationLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
00278     DestinationLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
00279 
00280     ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
00281     wcscpy(DestinationLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
00282 
00283     /* initialize extra line */
00284     InitializeListHead(&DestinationLine->ControlsList);
00285 
00286     /* insert into mixer info */
00287     InsertTailList(&MixerInfo->LineList, &DestinationLine->Entry);
00288 
00289     /* increment destination count */
00290     MixerInfo->MixCaps.cDestinations++;
00291 
00292     /* done */
00293     return MM_STATUS_SUCCESS;
00294 }
00295 
00296 MIXER_STATUS
00297 MMixerGetPinName(
00298     IN PMIXER_CONTEXT MixerContext,
00299     IN LPMIXER_INFO MixerInfo,
00300     IN HANDLE hMixer,
00301     IN ULONG PinId,
00302     IN OUT LPWSTR * OutBuffer)
00303 {
00304     KSP_PIN Pin;
00305     ULONG BytesReturned;
00306     LPWSTR Buffer;
00307     MIXER_STATUS Status;
00308 
00309     /* prepare pin */
00310     Pin.PinId = PinId;
00311     Pin.Reserved = 0;
00312     Pin.Property.Flags = KSPROPERTY_TYPE_GET;
00313     Pin.Property.Set = KSPROPSETID_Pin;
00314     Pin.Property.Id = KSPROPERTY_PIN_NAME;
00315 
00316     /* try get pin name size */
00317     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), NULL, 0, &BytesReturned);
00318 
00319     /* check if buffer overflowed */
00320     if (Status == MM_STATUS_MORE_ENTRIES)
00321     {
00322         /* allocate buffer */
00323         Buffer = (LPWSTR)MixerContext->Alloc(BytesReturned);
00324         if (!Buffer)
00325         {
00326             /* out of memory */
00327             return MM_STATUS_NO_MEMORY;
00328         }
00329 
00330         /* try get pin name */
00331         Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Pin, sizeof(KSP_PIN), (PVOID)Buffer, BytesReturned, &BytesReturned);
00332         if (Status != MM_STATUS_SUCCESS)
00333         {
00334             /* failed to get pin name */
00335             MixerContext->Free((PVOID)Buffer);
00336             return Status;
00337         }
00338 
00339         /* successfully obtained pin name */
00340         *OutBuffer = Buffer;
00341         return MM_STATUS_SUCCESS;
00342     }
00343 
00344     /* failed to get pin name */
00345     return Status;
00346 }
00347 
00348 MIXER_STATUS
00349 MMixerBuildMixerDestinationLine(
00350     IN PMIXER_CONTEXT MixerContext,
00351     IN OUT LPMIXER_INFO MixerInfo,
00352     IN HANDLE hMixer,
00353     IN ULONG PinId,
00354     IN ULONG bInput)
00355 {
00356     LPWSTR PinName;
00357     MIXER_STATUS Status;
00358 
00359     /* try get pin name */
00360     Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
00361     if (Status == MM_STATUS_SUCCESS)
00362     {
00363         /* create mixer destination line */
00364 
00365         Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, PinName);
00366 
00367         /* free pin name */
00368         MixerContext->Free(PinName);
00369     }
00370     else
00371     {
00372         /* create mixer destination line unlocalized */
00373         Status = MMixerCreateDestinationLine(MixerContext, MixerInfo, bInput, L"No Name");
00374     }
00375 
00376     return Status;
00377 }
00378 
00379 MIXER_STATUS
00380 MMixerBuildTopology(
00381     IN PMIXER_CONTEXT MixerContext,
00382     IN LPMIXER_DATA MixerData,
00383     OUT PTOPOLOGY * OutTopology)
00384 {
00385     ULONG PinsCount;
00386     PKSMULTIPLE_ITEM NodeTypes = NULL;
00387     PKSMULTIPLE_ITEM NodeConnections = NULL;
00388     MIXER_STATUS Status;
00389 
00390     if (MixerData->Topology)
00391     {
00392         /* re-use existing topology */
00393         *OutTopology = MixerData->Topology;
00394 
00395         return MM_STATUS_SUCCESS;
00396     }
00397 
00398     /* get connected filter pin count */
00399     PinsCount = MMixerGetFilterPinCount(MixerContext, MixerData->hDevice);
00400 
00401     if (!PinsCount)
00402     {
00403         /* referenced filter does not have any pins */
00404         return MM_STATUS_UNSUCCESSFUL;
00405     }
00406 
00407     /* get topology node types */
00408     Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_NODES, &NodeTypes);
00409     if (Status != MM_STATUS_SUCCESS)
00410     {
00411         /* failed to get topology node types */
00412         return Status;
00413     }
00414 
00415     /* get topology connections */
00416     Status = MMixerGetFilterTopologyProperty(MixerContext, MixerData->hDevice, KSPROPERTY_TOPOLOGY_CONNECTIONS, &NodeConnections);
00417     if (Status != MM_STATUS_SUCCESS)
00418     {
00419         /* failed to get topology connections */
00420         MixerContext->Free(NodeTypes);
00421         return Status;
00422     }
00423 
00424     /* create a topology */
00425     Status = MMixerCreateTopology(MixerContext, PinsCount, NodeConnections, NodeTypes, OutTopology);
00426 
00427     /* free node types & connections */
00428     MixerContext->Free(NodeConnections);
00429     MixerContext->Free(NodeTypes);
00430 
00431     if (Status == MM_STATUS_SUCCESS)
00432     {
00433         /* store topology object */
00434         MixerData->Topology = *OutTopology;
00435     }
00436 
00437     /* done */
00438     return Status;
00439 }
00440 
00441 MIXER_STATUS
00442 MMixerCountMixerControls(
00443     IN PMIXER_CONTEXT MixerContext,
00444     IN PTOPOLOGY Topology,
00445     IN ULONG PinId,
00446     IN ULONG bInputMixer,
00447     IN ULONG bUpStream,
00448     OUT PULONG OutNodesCount,
00449     OUT PULONG OutNodes,
00450     OUT PULONG OutLineTerminator)
00451 {
00452     PULONG Nodes;
00453     ULONG NodesCount, NodeIndex, Count, bTerminator;
00454     MIXER_STATUS Status;
00455 
00456     /* allocate an array to store all nodes which are upstream of this pin */
00457     Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
00458 
00459     if (Status != MM_STATUS_SUCCESS)
00460     {
00461         /* out of memory */
00462         return STATUS_NO_MEMORY;
00463     }
00464 
00465     /* mark result array as zero */
00466     *OutNodesCount = 0;
00467 
00468     /* get next nodes */
00469     MMixerGetNextNodesFromPinIndex(MixerContext, Topology, PinId, bUpStream, &NodesCount, Nodes);
00470 
00471     if (NodesCount == 0)
00472     {
00473         /* a pin which is not connected from any node
00474          * a) it is a topology bug (driver bug)
00475          * b) the request is from an alternative mixer
00476               alternative mixer code scans all pins which have not been used and tries to build lines
00477          */
00478         DPRINT1("MMixerCountMixerControls PinId %lu is not connected by any node\n", PinId);
00479         MMixerPrintTopology(Topology);
00480         return MM_STATUS_UNSUCCESSFUL;
00481     }
00482 
00483     /* assume no topology split before getting line terminator */
00484     ASSERT(NodesCount == 1);
00485 
00486     /* get first node */
00487     NodeIndex = Nodes[0];
00488     Count = 0;
00489 
00490     do
00491     {
00492         /* check if the node is a terminator */
00493         MMixerIsNodeTerminator(Topology, NodeIndex, &bTerminator);
00494 
00495         if (bTerminator)
00496         {
00497             /* found terminator */
00498             if (bInputMixer)
00499             {
00500                 /* add mux source for source destination line */
00501                 OutNodes[Count] = NodeIndex;
00502                 Count++;
00503             }
00504             break;
00505         }
00506 
00507         /* store node id */
00508         OutNodes[Count] = NodeIndex;
00509 
00510         /* increment node count */
00511         Count++;
00512 
00513         /* get next nodes upstream */
00514         MMixerGetNextNodesFromNodeIndex(MixerContext, Topology, NodeIndex, bUpStream, &NodesCount, Nodes);
00515 
00516         /* assume there is a node connected */
00517         ASSERT(NodesCount != 0);
00518         ASSERT(NodesCount == 1);
00519 
00520         /* use first index */
00521         NodeIndex = Nodes[0];
00522 
00523     }while(TRUE);
00524 
00525     /* free node index */
00526     MixerContext->Free(Nodes);
00527 
00528     /* store nodes count */
00529     *OutNodesCount = Count;
00530 
00531     /* store line terminator */
00532     *OutLineTerminator = NodeIndex;
00533 
00534     /* done */
00535     return MM_STATUS_SUCCESS;
00536 }
00537 
00538 MIXER_STATUS
00539 MMixerGetChannelCountEnhanced(
00540     IN PMIXER_CONTEXT MixerContext,
00541     IN LPMIXER_INFO MixerInfo,
00542     IN HANDLE hMixer,
00543     IN ULONG NodeId,
00544     OUT PULONG MaxChannels)
00545 {
00546     KSPROPERTY_DESCRIPTION Description;
00547     PKSPROPERTY_DESCRIPTION NewDescription;
00548     PKSPROPERTY_MEMBERSHEADER Header;
00549     ULONG BytesReturned;
00550     KSP_NODE Request;
00551     MIXER_STATUS Status;
00552 
00553     /* try #1 obtain it via description */
00554     Request.NodeId = NodeId;
00555     Request.Reserved = 0;
00556     Request.Property.Set = KSPROPSETID_Audio;
00557     Request.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
00558     Request.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
00559 
00560 
00561     /* get description */
00562     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)&Description, sizeof(KSPROPERTY_DESCRIPTION), &BytesReturned);
00563     if (Status == MM_STATUS_SUCCESS)
00564     {
00565         if (Description.DescriptionSize >= sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) && (Description.MembersListCount > 0))
00566         {
00567             /* allocate new description */
00568             NewDescription = MixerContext->Alloc(Description.DescriptionSize);
00569 
00570             if (!NewDescription)
00571             {
00572                 /* not enough memory */
00573                 return MM_STATUS_NO_MEMORY;
00574             }
00575 
00576             /* get description */
00577             Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_NODE), (PVOID)NewDescription, Description.DescriptionSize, &BytesReturned);
00578             if (Status == MM_STATUS_SUCCESS)
00579             {
00580                 /* get header */
00581                 Header = (PKSPROPERTY_MEMBERSHEADER)(NewDescription + 1);
00582 
00583                 if (Header->Flags & KSPROPERTY_MEMBER_FLAG_BASICSUPPORT_MULTICHANNEL)
00584                 {
00585                     /* found enhanced flag */
00586                     ASSERT(Header->MembersCount > 1);
00587 
00588                     /* store channel count */
00589                     *MaxChannels = Header->MembersCount;
00590 
00591                     /* free description */
00592                     MixerContext->Free(NewDescription);
00593 
00594                     /* done */
00595                     return MM_STATUS_SUCCESS;
00596                 }
00597             }
00598 
00599             /* free description */
00600             MixerContext->Free(NewDescription);
00601         }
00602     }
00603 
00604     /* failed to get channel count enhanced */
00605     return MM_STATUS_UNSUCCESSFUL;
00606 }
00607 
00608 VOID
00609 MMixerGetChannelCountLegacy(
00610     IN PMIXER_CONTEXT MixerContext,
00611     IN LPMIXER_INFO MixerInfo,
00612     IN HANDLE hMixer,
00613     IN ULONG NodeId,
00614     OUT PULONG MaxChannels)
00615 {
00616     ULONG BytesReturned;
00617     MIXER_STATUS Status;
00618     KSNODEPROPERTY_AUDIO_CHANNEL Channel;
00619     LONG Volume;
00620 
00621     /* setup request */
00622     Channel.Reserved = 0;
00623     Channel.NodeProperty.NodeId = NodeId;
00624     Channel.NodeProperty.Reserved = 0;
00625     Channel.NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
00626     Channel.NodeProperty.Property.Set = KSPROPSETID_Audio;
00627     Channel.Channel = 0;
00628     Channel.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
00629 
00630     do
00631     {
00632         /* get channel volume */
00633         Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Channel, sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), (PVOID)&Volume, sizeof(LONG), &BytesReturned);
00634         if (Status != MM_STATUS_SUCCESS)
00635             break;
00636 
00637         /* increment channel count */
00638         Channel.Channel++;
00639 
00640     }while(TRUE);
00641 
00642     /* store channel count */
00643     *MaxChannels = Channel.Channel;
00644 
00645 }
00646 
00647 VOID
00648 MMixerGetMaxChannelsForNode(
00649     IN PMIXER_CONTEXT MixerContext,
00650     IN LPMIXER_INFO MixerInfo,
00651     IN HANDLE hMixer,
00652     IN ULONG NodeId,
00653     OUT PULONG MaxChannels)
00654 {
00655     MIXER_STATUS Status;
00656 
00657     /* try to get it enhanced */
00658     Status = MMixerGetChannelCountEnhanced(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
00659 
00660     if (Status != MM_STATUS_SUCCESS)
00661     {
00662         /* get it old-fashioned way */
00663         MMixerGetChannelCountLegacy(MixerContext, MixerInfo, hMixer, NodeId, MaxChannels);
00664     }
00665 }
00666 
00667 MIXER_STATUS
00668 MMixerAddMixerControlsToMixerLineByNodeIndexArray(
00669     IN PMIXER_CONTEXT MixerContext,
00670     IN LPMIXER_INFO MixerInfo,
00671     IN HANDLE hMixer,
00672     IN PTOPOLOGY Topology,
00673     IN OUT LPMIXERLINE_EXT DstLine,
00674     IN ULONG NodesCount,
00675     IN PULONG Nodes)
00676 {
00677     ULONG Index, Count, bReserved;
00678     MIXER_STATUS Status;
00679     LPGUID NodeType;
00680     ULONG MaxChannels;
00681 
00682     /* initialize control count */
00683     Count = 0;
00684 
00685     for(Index = 0; Index < NodesCount; Index++)
00686     {
00687         /* check if the node has already been reserved to a line */
00688         MMixerIsTopologyNodeReserved(Topology, Nodes[Index], &bReserved);
00689 #if 0 /* MS lies */
00690         if (bReserved)
00691         {
00692             /* node is already used, skip it */
00693             continue;
00694         }
00695 #endif
00696         /* set node status as used */
00697         MMixerSetTopologyNodeReserved(Topology, Nodes[Index]);
00698 
00699         /* query node type */
00700         NodeType = MMixerGetNodeTypeFromTopology(Topology, Nodes[Index]);
00701 
00702         if (IsEqualGUIDAligned(NodeType, &KSNODETYPE_VOLUME))
00703         {
00704             /* calculate maximum channel count for node */
00705             MMixerGetMaxChannelsForNode(MixerContext, MixerInfo, hMixer, Nodes[Index], &MaxChannels);
00706 
00707             DPRINT("NodeId %lu MaxChannels %lu Line %S Id %lu\n", Nodes[Index], MaxChannels, DstLine->Line.szName, DstLine->Line.dwLineID);
00708             /* calculate maximum channels */
00709             DstLine->Line.cChannels = min(DstLine->Line.cChannels, MaxChannels);
00710         }
00711         else
00712         {
00713             /* use default of one channel */
00714             MaxChannels = 1;
00715         }
00716 
00717         /* now add the mixer control */
00718         Status = MMixerAddMixerControl(MixerContext, MixerInfo, hMixer, Topology, Nodes[Index], DstLine, MaxChannels);
00719 
00720         if (Status == MM_STATUS_SUCCESS)
00721         {
00722             /* increment control count */
00723             Count++;
00724         }
00725     }
00726 
00727     /* store control count */
00728     DstLine->Line.cControls = Count;
00729 
00730     /* done */
00731     return MM_STATUS_SUCCESS;
00732 }
00733 
00734 MIXER_STATUS
00735 MMixerGetComponentAndTargetType(
00736     IN PMIXER_CONTEXT MixerContext,
00737     IN OUT LPMIXER_INFO MixerInfo,
00738     IN HANDLE hMixer,
00739     IN ULONG PinId,
00740     OUT PULONG ComponentType,
00741     OUT PULONG TargetType)
00742 {
00743     KSPIN_DATAFLOW DataFlow;
00744     KSPIN_COMMUNICATION Communication;
00745     MIXER_STATUS Status;
00746     KSP_PIN Request;
00747     ULONG BytesReturned;
00748     GUID Guid;
00749     BOOLEAN BridgePin = FALSE;
00750     PKSPIN_PHYSICALCONNECTION Connection;
00751 
00752     /* first dataflow type */
00753     Status = MMixerGetPinDataFlowAndCommunication(MixerContext, hMixer, PinId, &DataFlow, &Communication);
00754 
00755     if (Status != MM_STATUS_SUCCESS)
00756     {
00757         /* failed to get dataflow */
00758         return Status;
00759     }
00760 
00761     /* now get pin category guid */
00762     Request.PinId = PinId;
00763     Request.Reserved = 0;
00764     Request.Property.Flags = KSPROPERTY_TYPE_GET;
00765     Request.Property.Set = KSPROPSETID_Pin;
00766     Request.Property.Id = KSPROPERTY_PIN_CATEGORY;
00767 
00768 
00769     /* get pin category */
00770     Status = MixerContext->Control(hMixer, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSP_PIN), &Guid, sizeof(GUID), &BytesReturned);
00771     if (Status != MM_STATUS_SUCCESS)
00772     {
00773         /* failed to get dataflow */
00774         return Status;
00775     }
00776 
00777     /* check if it has a physical connection */
00778     Status = MMixerGetPhysicalConnection(MixerContext, hMixer, PinId, &Connection);
00779     if (Status == MM_STATUS_SUCCESS)
00780     {
00781         /* pin is a brige pin */
00782         BridgePin = TRUE;
00783 
00784         /* free physical connection */
00785         MixerContext->Free(Connection);
00786     }
00787 
00788     if (DataFlow == KSPIN_DATAFLOW_IN)
00789     {
00790         if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_MICROPHONE) ||
00791             IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_MICROPHONE))
00792         {
00793             /* type microphone */
00794             *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
00795             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
00796         }
00797         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LEGACY_AUDIO_CONNECTOR) ||
00798                  IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
00799                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER))
00800         {
00801             /* type waveout */
00802             *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
00803             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
00804         }
00805         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_CD_PLAYER))
00806         {
00807             /* type cd player */
00808             *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
00809             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
00810         }
00811         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SYNTHESIZER))
00812         {
00813             /* type synthesizer */
00814             *TargetType = MIXERLINE_TARGETTYPE_MIDIOUT;
00815             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
00816         }
00817         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_LINE_CONNECTOR))
00818         {
00819             /* type line */
00820             *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
00821             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
00822         }
00823         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
00824                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
00825                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
00826         {
00827             /* type telephone */
00828             *TargetType =  MIXERLINE_TARGETTYPE_UNDEFINED;
00829             *ComponentType =  MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE;
00830         }
00831         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
00832         {
00833             /* type analog */
00834             if (BridgePin)
00835                 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
00836             else
00837                 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
00838 
00839             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_ANALOG;
00840         }
00841         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
00842         {
00843             /* type analog */
00844             if (BridgePin)
00845                 *TargetType = MIXERLINE_TARGETTYPE_WAVEIN;
00846             else
00847                 *TargetType = MIXERLINE_TARGETTYPE_WAVEOUT;
00848 
00849             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_DIGITAL;
00850         }
00851         else
00852         {
00853             /* unknown type */
00854             *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
00855             *ComponentType = MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED;
00856             DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
00857         }
00858     }
00859     else
00860     {
00861         if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPEAKER) ||
00862                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_DESKTOP_SPEAKER) ||
00863                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_ROOM_SPEAKER) ||
00864                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_COMMUNICATION_SPEAKER))
00865         {
00866             /* type waveout */
00867             *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
00868             *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
00869         }
00870         else if (IsEqualGUIDAligned(&Guid, &KSCATEGORY_AUDIO) ||
00871                  IsEqualGUIDAligned(&Guid, &PINNAME_CAPTURE))
00872         {
00873             /* type wavein */
00874             *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
00875             *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
00876         }
00877         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEADPHONES) ||
00878                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO))
00879         {
00880             /* type head phones */
00881             *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
00882             *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_HEADPHONES;
00883         }
00884         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_TELEPHONE) ||
00885                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_PHONE_LINE) ||
00886                  IsEqualGUIDAligned(&Guid, &KSNODETYPE_DOWN_LINE_PHONE))
00887         {
00888             /* type waveout */
00889             *TargetType =   MIXERLINE_TARGETTYPE_UNDEFINED;
00890             *ComponentType =   MIXERLINE_COMPONENTTYPE_DST_TELEPHONE;
00891         }
00892         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_ANALOG_CONNECTOR))
00893         {
00894             /* type analog */
00895             if (BridgePin)
00896             {
00897                 *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
00898                 *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
00899             }
00900             else
00901             {
00902                 *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
00903                 *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
00904             }
00905         }
00906         else if (IsEqualGUIDAligned(&Guid, &KSNODETYPE_SPDIF_INTERFACE))
00907         {
00908             /* type spdif */
00909             if (BridgePin)
00910             {
00911                 *TargetType =  MIXERLINE_TARGETTYPE_WAVEOUT;
00912                 *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
00913             }
00914             else
00915             {
00916                 *TargetType =  MIXERLINE_TARGETTYPE_WAVEIN;
00917                 *ComponentType =  MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
00918             }
00919         }
00920         else
00921         {
00922             /* unknown type */
00923             *TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
00924             *ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
00925             DPRINT1("Unknown Category for PinId %lu BridgePin %lu\n", PinId, BridgePin);
00926         }
00927     }
00928 
00929     /* done */
00930     return MM_STATUS_SUCCESS;
00931 }
00932 
00933 MIXER_STATUS
00934 MMixerBuildMixerSourceLine(
00935     IN PMIXER_CONTEXT MixerContext,
00936     IN OUT LPMIXER_INFO MixerInfo,
00937     IN HANDLE hMixer,
00938     IN PTOPOLOGY Topology,
00939     IN ULONG PinId,
00940     IN ULONG NodesCount,
00941     IN PULONG Nodes,
00942     IN ULONG DestinationLineID,
00943     OUT LPMIXERLINE_EXT * OutSrcLine)
00944 {
00945     LPMIXERLINE_EXT SrcLine, DstLine;
00946     LPWSTR PinName;
00947     MIXER_STATUS Status;
00948     ULONG ComponentType, TargetType;
00949 
00950     /* get component and target type */
00951     Status = MMixerGetComponentAndTargetType(MixerContext, MixerInfo, hMixer, PinId, &ComponentType, &TargetType);
00952     if (Status != MM_STATUS_SUCCESS)
00953     {
00954         /* failed to get component status */
00955         TargetType = MIXERLINE_TARGETTYPE_UNDEFINED;
00956         ComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
00957     }
00958 
00959     /* construct source line */
00960     SrcLine = (LPMIXERLINE_EXT)MixerContext->Alloc(sizeof(MIXERLINE_EXT));
00961 
00962     if (!SrcLine)
00963     {
00964         /* no memory */
00965         return MM_STATUS_NO_MEMORY;
00966     }
00967 
00968     /* get destination line */
00969     DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
00970     ASSERT(DstLine);
00971 
00972     /* initialize mixer src line */
00973     SrcLine->PinId = PinId;
00974 
00975     /* initialize mixer line */
00976     SrcLine->Line.cbStruct = sizeof(MIXERLINEW);
00977     SrcLine->Line.dwDestination = MixerInfo->MixCaps.cDestinations-1;
00978     SrcLine->Line.dwSource = DstLine->Line.cConnections;
00979     SrcLine->Line.dwLineID = (DstLine->Line.cConnections * SOURCE_LINE)+ (MixerInfo->MixCaps.cDestinations-1);
00980     SrcLine->Line.fdwLine = MIXERLINE_LINEF_ACTIVE | MIXERLINE_LINEF_SOURCE;
00981     SrcLine->Line.dwComponentType = ComponentType;
00982     SrcLine->Line.dwUser = 0;
00983     SrcLine->Line.cChannels = DstLine->Line.cChannels;
00984     SrcLine->Line.cConnections = 0;
00985     SrcLine->Line.Target.dwType = TargetType;
00986     SrcLine->Line.Target.dwDeviceID = DstLine->Line.Target.dwDeviceID;
00987     SrcLine->Line.Target.wMid = MixerInfo->MixCaps.wMid;
00988     SrcLine->Line.Target.wPid = MixerInfo->MixCaps.wPid;
00989     SrcLine->Line.Target.vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
00990     InitializeListHead(&SrcLine->ControlsList);
00991 
00992     /* copy name */
00993     ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == L'\0');
00994     wcscpy(SrcLine->Line.Target.szPname, MixerInfo->MixCaps.szPname);
00995 
00996     /* get pin name */
00997     Status = MMixerGetPinName(MixerContext, MixerInfo, hMixer, PinId, &PinName);
00998 
00999     if (Status == MM_STATUS_SUCCESS)
01000     {
01001         /* store pin name as line name */
01002         MixerContext->Copy(SrcLine->Line.szShortName, PinName, (min(MIXER_SHORT_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
01003         SrcLine->Line.szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
01004 
01005         MixerContext->Copy(SrcLine->Line.szName, PinName, (min(MIXER_LONG_NAME_CHARS, wcslen(PinName)+1)) * sizeof(WCHAR));
01006         SrcLine->Line.szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
01007 
01008         /* free pin name buffer */
01009         MixerContext->Free(PinName);
01010     }
01011 
01012     /* add the controls to mixer line */
01013     Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, SrcLine, NodesCount, Nodes);
01014     if (Status != MM_STATUS_SUCCESS)
01015     {
01016         /* failed */
01017         return Status;
01018     }
01019 
01020     /* store result */
01021     *OutSrcLine = SrcLine;
01022 
01023     return MM_STATUS_SUCCESS;
01024 }
01025 
01026 MIXER_STATUS
01027 MMixerAddMixerSourceLines(
01028     IN PMIXER_CONTEXT MixerContext,
01029     IN OUT LPMIXER_INFO MixerInfo,
01030     IN HANDLE hMixer,
01031     IN PTOPOLOGY Topology,
01032     IN ULONG DestinationLineID,
01033     IN ULONG LineTerminator)
01034 {
01035     PULONG AllNodes, AllPins, AllPinNodes;
01036     ULONG AllNodesCount, AllPinsCount, AllPinNodesCount;
01037     ULONG Index, SubIndex, PinId, CurNode, bConnected;
01038     MIXER_STATUS Status;
01039     LPMIXERLINE_EXT DstLine, SrcLine;
01040 
01041     /* get destination line */
01042     DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);
01043     ASSERT(DstLine);
01044 
01045     /* allocate an array to store all nodes which are upstream of the line terminator */
01046     Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllNodes);
01047 
01048     /* check for success */
01049     if (Status != MM_STATUS_SUCCESS)
01050     {
01051         /* out of memory */
01052         return MM_STATUS_NO_MEMORY;
01053     }
01054 
01055     /* allocate an array to store all nodes which are downstream of a particular pin */
01056     Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &AllPinNodes);
01057 
01058     /* allocate an array to store all pins which are upstream of this pin */
01059     Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &AllPins);
01060 
01061     /* check for success */
01062     if (Status != MM_STATUS_SUCCESS)
01063     {
01064         /* out of memory */
01065         MixerContext->Free(AllNodes);
01066         return MM_STATUS_NO_MEMORY;
01067     }
01068 
01069      /* get all nodes which indirectly / directly connect to this node */
01070     AllNodesCount = 0;
01071     MMixerGetAllUpOrDownstreamNodesFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllNodesCount, AllNodes);
01072 
01073     /* get all pins which indirectly / directly connect to this node */
01074     AllPinsCount = 0;
01075     MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, LineTerminator, TRUE, &AllPinsCount, AllPins);
01076 
01077     DPRINT("LineTerminator %lu\n", LineTerminator);
01078     DPRINT("PinCount %lu\n", AllPinsCount);
01079     DPRINT("AllNodesCount %lu\n", AllNodesCount);
01080 
01081     /* now construct the source lines which are attached to the destination line */
01082     Index = AllPinsCount;
01083 
01084     do
01085     {
01086         /* get current pin id */
01087         PinId = AllPins[Index - 1];
01088 
01089         /* reset nodes count */
01090         AllPinNodesCount = 0;
01091 
01092         /* now scan all nodes and add them to AllPinNodes array when they are connected to this pin */
01093         for(SubIndex = 0; SubIndex < AllNodesCount; SubIndex++)
01094         {
01095             /* get current node index */
01096             CurNode = AllNodes[SubIndex];
01097 
01098             if (CurNode != MAXULONG && CurNode != LineTerminator)
01099             {
01100                 /* check if that node is connected in some way to the current pin */
01101                 Status = MMixerIsNodeConnectedToPin(MixerContext, Topology, CurNode, PinId, TRUE, &bConnected);
01102 
01103                 if (Status != MM_STATUS_SUCCESS)
01104                     break;
01105 
01106                 if (bConnected)
01107                 {
01108                     /* it is connected */
01109                     AllPinNodes[AllPinNodesCount] = CurNode;
01110                     AllPinNodesCount++;
01111 
01112                     /* clear current index */
01113                     AllNodes[SubIndex] = MAXULONG;
01114                 }
01115             }
01116         }
01117 
01118         /* decrement pin index */
01119         Index--;
01120 
01121         if (AllPinNodesCount)
01122         {
01123 #ifdef MMIXER_DEBUG
01124             ULONG TempIndex;
01125 #endif
01126             /* now build the mixer source line */
01127             Status = MMixerBuildMixerSourceLine(MixerContext, MixerInfo, hMixer, Topology, PinId, AllPinNodesCount, AllPinNodes, DestinationLineID, &SrcLine);
01128 
01129              if (Status == MM_STATUS_SUCCESS)
01130              {
01131                  /* insert into line list */
01132                  InsertTailList(&MixerInfo->LineList, &SrcLine->Entry);
01133 
01134                  /* increment destination line count */
01135                  DstLine->Line.cConnections++;
01136 
01137                  /* mark pin as reserved */
01138                  MMixerSetTopologyPinReserved(Topology, PinId);
01139 
01140 #ifdef MMIXER_DEBUG
01141                  DPRINT1("Adding PinId %lu AllPinNodesCount %lu to DestinationLine %lu\n", PinId, AllPinNodesCount, DestinationLineID);
01142                  for(TempIndex = 0; TempIndex < AllPinNodesCount; TempIndex++)
01143                      DPRINT1("NodeIndex %lu\n", AllPinNodes[TempIndex]);
01144 #endif
01145              }
01146         }
01147         else
01148         {
01149 #ifdef MMIXER_DEBUG
01150             DPRINT1("Discarding DestinationLineID %lu PinId %lu NO NODES!\n", DestinationLineID, PinId);
01151 #endif
01152         }
01153 
01154     }while(Index != 0);
01155 
01156     return MM_STATUS_SUCCESS;
01157 }
01158 
01159 
01160 MIXER_STATUS
01161 MMixerAddMixerControlsToDestinationLine(
01162     IN PMIXER_CONTEXT MixerContext,
01163     IN OUT LPMIXER_INFO MixerInfo,
01164     IN HANDLE hMixer,
01165     IN PTOPOLOGY Topology,
01166     IN ULONG PinId,
01167     IN ULONG bInput,
01168     IN ULONG DestinationLineId,
01169     OUT PULONG OutLineTerminator)
01170 {
01171     PULONG Nodes;
01172     ULONG NodesCount, LineTerminator;
01173     MIXER_STATUS Status;
01174     LPMIXERLINE_EXT DstLine;
01175 
01176     /* allocate nodes index array */
01177     Status = MMixerAllocateTopologyNodeArray(MixerContext, Topology, &Nodes);
01178 
01179     /* check for success */
01180     if (Status != MM_STATUS_SUCCESS)
01181     {
01182         /* out of memory */
01183         return Status;
01184     }
01185 
01186     /* get all destination line controls */
01187     Status = MMixerCountMixerControls(MixerContext, Topology, PinId, bInput, TRUE, &NodesCount, Nodes, &LineTerminator);
01188 
01189     /* check for success */
01190     if (Status != MM_STATUS_SUCCESS)
01191     {
01192         /* failed to count controls */
01193         MixerContext->Free(Nodes);
01194         return Status;
01195     }
01196 
01197     /* get destination mixer line */
01198     DstLine = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineId);
01199 
01200     /* sanity check */
01201     ASSERT(DstLine);
01202 
01203     if (NodesCount > 0)
01204     {
01205         /* add all nodes as mixer controls to the destination line */
01206         Status = MMixerAddMixerControlsToMixerLineByNodeIndexArray(MixerContext, MixerInfo, hMixer, Topology, DstLine, NodesCount, Nodes);
01207         if (Status != MM_STATUS_SUCCESS)
01208         {
01209             /* failed to add controls */
01210             MixerContext->Free(Nodes);
01211             return Status;
01212         }
01213     }
01214 
01215     /* store result */
01216     *OutLineTerminator = LineTerminator;
01217 
01218     /* return result */
01219     return Status;
01220 }
01221 
01222 VOID
01223 MMixerApplyOutputFilterHack(
01224     IN PMIXER_CONTEXT MixerContext,
01225     IN LPMIXER_DATA MixerData,
01226     IN HANDLE hMixer,
01227     IN OUT PULONG PinsCount,
01228     IN OUT PULONG Pins)
01229 {
01230     ULONG Count = 0, Index;
01231     MIXER_STATUS Status;
01232     PKSPIN_PHYSICALCONNECTION Connection;
01233 
01234     for(Index = 0; Index < *PinsCount; Index++)
01235     {
01236         /* check if it has a physical connection */
01237         Status = MMixerGetPhysicalConnection(MixerContext, hMixer, Pins[Index], &Connection);
01238 
01239         if (Status == MM_STATUS_SUCCESS)
01240         {
01241             /* remove pin */
01242             MixerContext->Copy(&Pins[Index], &Pins[Index + 1], (*PinsCount - (Index + 1)) * sizeof(ULONG));
01243 
01244             /* free physical connection */
01245             MixerContext->Free(Connection);
01246 
01247             /* decrement index */
01248             Index--;
01249 
01250             /* decrement pin count */
01251             (*PinsCount)--;
01252         }
01253         else
01254         {
01255             /* simple pin */
01256             Count++;
01257         }
01258     }
01259 
01260     /* store result */
01261     *PinsCount = Count;
01262 }
01263 
01264 MIXER_STATUS
01265 MMixerHandlePhysicalConnection(
01266     IN PMIXER_CONTEXT MixerContext,
01267     IN PMIXER_LIST MixerList,
01268     IN LPMIXER_DATA MixerData,
01269     IN OUT LPMIXER_INFO MixerInfo,
01270     IN ULONG bInput,
01271     IN PKSPIN_PHYSICALCONNECTION OutConnection)
01272 {
01273     MIXER_STATUS Status;
01274     ULONG PinsCount, LineTerminator, DestinationLineID;
01275     PULONG Pins;
01276     PTOPOLOGY Topology;
01277 
01278     /* first try to open the connected filter */
01279     OutConnection->SymbolicLinkName[1] = L'\\';
01280     MixerData = MMixerGetDataByDeviceName(MixerList, OutConnection->SymbolicLinkName);
01281 
01282      /* check if the linked connection is found */
01283      if (!MixerData)
01284      {
01285          /* filter references invalid physical connection */
01286          return MM_STATUS_UNSUCCESSFUL;
01287      }
01288 
01289     DPRINT("Name %S, Pin %lu bInput %lu\n", OutConnection->SymbolicLinkName, OutConnection->Pin, bInput);
01290 
01291     /* sanity check */
01292     ASSERT(MixerData->MixerInfo == NULL || MixerData->MixerInfo == MixerInfo);
01293 
01294     /* associate with mixer */
01295     MixerData->MixerInfo = MixerInfo;
01296 
01297     if (MixerData->Topology == NULL)
01298     {
01299         /* construct new topology */
01300         Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
01301         if (Status != MM_STATUS_SUCCESS)
01302         {
01303             /* failed to create topology */
01304             return Status;
01305         }
01306 
01307         /* store topology */
01308         MixerData->Topology = Topology;
01309     }
01310     else
01311     {
01312         /* re-use existing topology */
01313         Topology = MixerData->Topology;
01314     }
01315 
01316     /* mark pin as consumed */
01317     MMixerSetTopologyPinReserved(Topology, OutConnection->Pin);
01318 
01319     if (!bInput)
01320     {
01321         /* allocate pin index array which will hold all referenced pins */
01322         Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
01323         if (Status != MM_STATUS_SUCCESS)
01324         {
01325             /* failed to create topology */
01326             return Status;
01327         }
01328 
01329         /* the mixer is an output mixer
01330          * find end pin of the node path
01331          */
01332         PinsCount = 0;
01333         Status = MMixerGetAllUpOrDownstreamPinsFromPinIndex(MixerContext, Topology, OutConnection->Pin, FALSE, &PinsCount, Pins);
01334 
01335         /* check for success */
01336         if (Status != MM_STATUS_SUCCESS)
01337         {
01338             /* failed to get end pin */
01339             MixerContext->Free(Pins);
01340             //MMixerFreeTopology(Topology);
01341 
01342             /* return error code */
01343             return Status;
01344         }
01345         /* HACK:
01346          * some topologies do not have strict boundaries
01347          * WorkArround: remove all pin ids which have a physical connection
01348          * because bridge pins may belong to different render paths
01349          */
01350         MMixerApplyOutputFilterHack(MixerContext, MixerData, MixerData->hDevice, &PinsCount, Pins);
01351 
01352         /* sanity checks */
01353         ASSERT(PinsCount != 0);
01354         ASSERT(PinsCount == 1);
01355 
01356         /* create destination line */
01357         Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInput);
01358 
01359         /* calculate destination line id */
01360         DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
01361 
01362         if (Status != MM_STATUS_SUCCESS)
01363         {
01364             /* failed to build destination line */
01365             MixerContext->Free(Pins);
01366 
01367             /* return error code */
01368             return Status;
01369         }
01370 
01371         /* add mixer controls to destination line */
01372         Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, Pins[0], bInput, DestinationLineID,  &LineTerminator);
01373 
01374         if (Status == MM_STATUS_SUCCESS)
01375         {
01376             /* now add the rest of the source lines */
01377             Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
01378         }
01379 
01380         /* mark pin as consumed */
01381         MMixerSetTopologyPinReserved(Topology, Pins[0]);
01382 
01383         /* free topology pin array */
01384         MixerContext->Free(Pins);
01385     }
01386     else
01387     {
01388         /* calculate destination line id */
01389         DestinationLineID = (DESTINATION_LINE + MixerInfo->MixCaps.cDestinations-1);
01390 
01391         /* add mixer controls */
01392         Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Topology, OutConnection->Pin, bInput, DestinationLineID, &LineTerminator);
01393 
01394         if (Status == MM_STATUS_SUCCESS)
01395         {
01396             /* now add the rest of the source lines */
01397             Status = MMixerAddMixerSourceLines(MixerContext, MixerInfo, MixerData->hDevice, Topology, DestinationLineID, LineTerminator);
01398         }
01399     }
01400 
01401     return Status;
01402 }
01403 
01404 MIXER_STATUS
01405 MMixerInitializeFilter(
01406     IN PMIXER_CONTEXT MixerContext,
01407     IN PMIXER_LIST MixerList,
01408     IN LPMIXER_DATA MixerData,
01409     IN LPMIXER_INFO MixerInfo,
01410     IN PTOPOLOGY Topology,
01411     IN ULONG NodeIndex,
01412     IN ULONG bInputMixer,
01413     IN OUT LPMIXER_INFO * OutMixerInfo)
01414 {
01415     ULONG Index;
01416     MIXER_STATUS Status;
01417     PKSPIN_PHYSICALCONNECTION OutConnection;
01418     ULONG * Pins;
01419     ULONG PinsFound;
01420     ULONG NewMixerInfo = FALSE;
01421 
01422     if (MixerInfo == NULL)
01423     {
01424         /* allocate a mixer info struct */
01425         MixerInfo = (LPMIXER_INFO) MixerContext->Alloc(sizeof(MIXER_INFO));
01426         if (!MixerInfo)
01427         {
01428             /* no memory */
01429             return MM_STATUS_NO_MEMORY;
01430         }
01431 
01432         /* new mixer info */
01433         NewMixerInfo = TRUE;
01434 
01435         /* intialize mixer caps */
01436         MixerInfo->MixCaps.wMid = MM_MICROSOFT; /* FIXME */
01437         MixerInfo->MixCaps.wPid = MM_PID_UNMAPPED; /* FIXME */
01438         MixerInfo->MixCaps.vDriverVersion = 1; /* FIXME */
01439         MixerInfo->MixCaps.fdwSupport = 0;
01440         MixerInfo->MixCaps.cDestinations = 0;
01441 
01442         /* get mixer name */
01443         MMixerGetDeviceName(MixerContext, MixerInfo->MixCaps.szPname, MixerData->hDeviceInterfaceKey);
01444 
01445         /* initialize line list */
01446         InitializeListHead(&MixerInfo->LineList);
01447         InitializeListHead(&MixerInfo->EventList);
01448 
01449         /* associate with mixer data */
01450         MixerData->MixerInfo = MixerInfo;
01451     }
01452 
01453     /* store mixer info */
01454     *OutMixerInfo = MixerInfo;
01455 
01456     /* now allocate an array which will receive the indices of the pin 
01457      * which has a ADC / DAC nodetype in its path
01458      */
01459     Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
01460     ASSERT(Status == MM_STATUS_SUCCESS);
01461 
01462     PinsFound = 0;
01463 
01464     /* now get all sink / source pins, which are attached to the ADC / DAC node
01465      * For sink pins (wave out) search up stream
01466      * For source pins (wave in) search down stream
01467      * The search direction is always the opposite of the current mixer type
01468      */
01469     PinsFound = 0;
01470     MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, !bInputMixer, &PinsFound, Pins);
01471 
01472     /* if there is no pin found, we have a broken topology */
01473     ASSERT(PinsFound != 0);
01474 
01475     /* now create a wave info struct */
01476     Status = MMixerInitializeWaveInfo(MixerContext, MixerList, MixerData, MixerInfo->MixCaps.szPname, bInputMixer, PinsFound, Pins);
01477     if (Status != MM_STATUS_SUCCESS)
01478     {
01479         /* failed to create wave info struct */
01480         MixerContext->Free(MixerInfo);
01481         MixerContext->Free(Pins);
01482         return Status;
01483     }
01484 
01485     /* mark all found pins as reserved */
01486     for(Index = 0; Index < PinsFound; Index++)
01487     {
01488         MMixerSetTopologyPinReserved(Topology, Pins[Index]);
01489     }
01490 
01491     if (bInputMixer)
01492     {
01493         /* pre create the mixer destination line for input mixers */
01494         Status = MMixerBuildMixerDestinationLine(MixerContext, MixerInfo, MixerData->hDevice, Pins[0], bInputMixer);
01495 
01496         if (Status != MM_STATUS_SUCCESS)
01497         {
01498             /* failed to create mixer destination line */
01499             return Status;
01500         }
01501     }
01502 
01503 
01504     /* now get the bridge pin which is at the end of node path 
01505      * For sink pins (wave out) search down stream
01506      * For source pins (wave in) search up stream
01507      */
01508     MixerContext->Free(Pins);
01509     Status = MMixerAllocateTopologyPinArray(MixerContext, Topology, &Pins);
01510     ASSERT(Status == MM_STATUS_SUCCESS);
01511 
01512     PinsFound = 0;
01513     MMixerGetAllUpOrDownstreamPinsFromNodeIndex(MixerContext, Topology, NodeIndex, bInputMixer, &PinsFound, Pins);
01514 
01515     /* if there is no pin found, we have a broken topology */
01516     ASSERT(PinsFound != 0);
01517 
01518     /* there should be exactly one bridge pin */
01519     ASSERT(PinsFound == 1);
01520 
01521     DPRINT("BridgePin %lu bInputMixer %lu\n", Pins[0], bInputMixer);
01522 
01523     /* does the pin have a physical connection */
01524     Status = MMixerGetPhysicalConnection(MixerContext, MixerData->hDevice, Pins[0], &OutConnection);
01525 
01526     if (Status == MM_STATUS_SUCCESS)
01527     {
01528         /* mark pin as reserved */
01529         MMixerSetTopologyPinReserved(Topology, Pins[0]);
01530 
01531         /* topology on the topoloy filter */
01532         Status = MMixerHandlePhysicalConnection(MixerContext, MixerList, MixerData, MixerInfo, bInputMixer, OutConnection);
01533 
01534         /* free physical connection data */
01535         MixerContext->Free(OutConnection);
01536     }
01537     else
01538     {
01539         /* FIXME
01540          * handle drivers which expose their topology on the same filter
01541          */
01542         ASSERT(0);
01543     }
01544 
01545     /* free pins */
01546     MixerContext->Free(Pins);
01547 
01548     if (NewMixerInfo)
01549     {
01550         /* insert mixer */
01551         InsertHeadList(&MixerList->MixerList, &MixerInfo->Entry);
01552         /* increment mixer count */
01553         MixerList->MixerListCount++;
01554     }
01555 
01556     /* done */
01557     return Status;
01558 }
01559 
01560 VOID
01561 MMixerHandleAlternativeMixers(
01562     IN PMIXER_CONTEXT MixerContext,
01563     IN PMIXER_LIST MixerList,
01564     IN LPMIXER_DATA MixerData,
01565     IN PTOPOLOGY Topology)
01566 {
01567     ULONG Index, PinCount, Reserved;
01568     MIXER_STATUS Status;
01569     ULONG DestinationLineID, LineTerminator;
01570     LPMIXERLINE_EXT DstLine;
01571 
01572     DPRINT("DeviceName %S\n", MixerData->DeviceName);
01573 
01574     /* get topology pin count */
01575     MMixerGetTopologyPinCount(Topology, &PinCount);
01576 
01577     for(Index = 0; Index < PinCount; Index++)
01578     {
01579         MMixerIsTopologyPinReserved(Topology, Index, &Reserved);
01580 
01581         /* check if it has already been reserved */
01582         if (Reserved == TRUE)
01583         {
01584             /* pin has already been reserved */
01585             continue;
01586         }
01587 
01588         DPRINT("MixerName %S Available PinID %lu\n", MixerData->DeviceName, Index);
01589 
01590         /* sanity check */
01591         //ASSERT(MixerData->MixerInfo);
01592 
01593         if (!MixerData->MixerInfo)
01594         {
01595             DPRINT1("Expected mixer info\n");
01596             continue;
01597         }
01598 
01599         /* build the destination line */
01600         Status = MMixerBuildMixerDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, Index, TRUE);
01601         if (Status != MM_STATUS_SUCCESS)
01602         {
01603             /* failed to build destination line */
01604             continue;
01605         }
01606 
01607         /* calculate destination line id */
01608         DestinationLineID = (DESTINATION_LINE + MixerData->MixerInfo->MixCaps.cDestinations-1);
01609 
01610         /* add mixer controls to destination line */
01611         Status = MMixerAddMixerControlsToDestinationLine(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, Index, TRUE, DestinationLineID,  &LineTerminator);
01612         if (Status == MM_STATUS_SUCCESS)
01613         {
01614             /* now add the rest of the source lines */
01615             Status = MMixerAddMixerSourceLines(MixerContext, MixerData->MixerInfo, MixerData->hDevice, MixerData->Topology, DestinationLineID, LineTerminator);
01616         }
01617 
01618         /* mark pin as consumed */
01619         MMixerSetTopologyPinReserved(Topology, Index);
01620 
01621         /* now grab destination line */
01622         DstLine = MMixerGetSourceMixerLineByLineId(MixerData->MixerInfo, DestinationLineID);
01623 
01624         /* set type and target as undefined */
01625         DstLine->Line.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_UNDEFINED;
01626         DstLine->Line.Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
01627         DstLine->Line.Target.vDriverVersion = 0;
01628         DstLine->Line.Target.wMid = 0;
01629         DstLine->Line.Target.wPid = 0;
01630     }
01631 }
01632 
01633 MIXER_STATUS
01634 MMixerSetupFilter(
01635     IN PMIXER_CONTEXT MixerContext,
01636     IN PMIXER_LIST MixerList,
01637     IN LPMIXER_DATA MixerData,
01638     IN PULONG DeviceCount)
01639 {
01640     MIXER_STATUS Status;
01641     PTOPOLOGY Topology;
01642     ULONG NodeIndex;
01643     LPMIXER_INFO MixerInfo = NULL;
01644 
01645     /* check if topology has already been built */
01646     if (MixerData->Topology == NULL)
01647     {
01648         /* build topology */
01649         Status = MMixerBuildTopology(MixerContext, MixerData, &Topology);
01650 
01651         if (Status != MM_STATUS_SUCCESS)
01652         {
01653             /* failed to build topology */
01654             return Status;
01655         }
01656 
01657         /* store topology */
01658         MixerData->Topology = Topology;
01659     }
01660     else
01661     {
01662         /* re-use topology */
01663         Topology = MixerData->Topology;
01664     }
01665 
01666     /* check if the filter has an wave out node */
01667     NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_DAC);
01668     if (NodeIndex != MAXULONG)
01669     {
01670         /* it has */
01671         Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, NULL, Topology, NodeIndex, FALSE, &MixerInfo);
01672 
01673         /* check for success */
01674         if (Status == MM_STATUS_SUCCESS)
01675         {
01676             /* increment mixer count */
01677             (*DeviceCount)++;
01678         }
01679         else
01680         {
01681             /* reset mixer info in case of error */
01682             MixerInfo = NULL;
01683         }
01684     }
01685 
01686     /* check if the filter has an wave in node */
01687     NodeIndex = MMixerGetNodeIndexFromGuid(Topology, &KSNODETYPE_ADC);
01688     if (NodeIndex != MAXULONG)
01689     {
01690         /* it has */
01691         Status = MMixerInitializeFilter(MixerContext, MixerList, MixerData, MixerInfo, Topology, NodeIndex, TRUE, &MixerInfo);
01692 
01693         /* check for success */
01694         if (Status == MM_STATUS_SUCCESS)
01695         {
01696             /* increment mixer count */
01697             (*DeviceCount)++;
01698         }
01699 
01700     }
01701 
01702     /* TODO: apply hacks for Wave source line */
01703 
01704     /* activate midi devices */
01705     //MMixerInitializeMidiForFilter(MixerContext, MixerList, MixerData, Topology);
01706 
01707     /* done */
01708     return Status;
01709 }
01710 
01711 
01712 MIXER_STATUS
01713 MMixerAddEvent(
01714     IN PMIXER_CONTEXT MixerContext,
01715     IN OUT LPMIXER_INFO MixerInfo,
01716     IN PVOID MixerEventContext,
01717     IN PMIXER_EVENT MixerEventRoutine)
01718 {
01719     //KSE_NODE Property;
01720     PEVENT_NOTIFICATION_ENTRY EventData;
01721     //ULONG BytesReturned;
01722     //MIXER_STATUS Status;
01723 
01724     EventData = (PEVENT_NOTIFICATION_ENTRY)MixerContext->AllocEventData(sizeof(EVENT_NOTIFICATION_ENTRY));
01725     if (!EventData)
01726     {
01727         /* not enough memory */
01728         return MM_STATUS_NO_MEMORY;
01729     }
01730 
01731 #if 0
01732     /* setup request */
01733     Property.Event.Set = KSEVENTSETID_AudioControlChange;
01734     Property.Event.Flags = KSEVENT_TYPE_TOPOLOGY|KSEVENT_TYPE_ENABLE;
01735     Property.Event.Id = KSEVENT_CONTROL_CHANGE;
01736 
01737     Property.NodeId = NodeId;
01738     Property.Reserved = 0;
01739 
01740     Status = MixerContext->Control(MixerInfo->hMixer, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSP_NODE), (PVOID)EventData, sizeof(KSEVENTDATA), &BytesReturned);
01741     if (Status != MM_STATUS_SUCCESS)
01742     {
01743         /* failed to add event */
01744         MixerContext->FreeEventData(EventData);
01745         return Status;
01746     }
01747 #endif
01748 
01749     /* initialize notification entry */
01750     EventData->MixerEventContext = MixerEventContext;
01751     EventData->MixerEventRoutine = MixerEventRoutine;
01752 
01753     /* store event */
01754     InsertTailList(&MixerInfo->EventList, &EventData->Entry);
01755     return MM_STATUS_SUCCESS;
01756 }
01757 

Generated on Fri May 25 2012 04:34:39 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.