Exemplo n.º 1
0
MIXER_STATUS
MMixerMidiInCapabilities(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG DeviceIndex,
    OUT LPMIDIINCAPSW Caps)
{
    PMIXER_LIST MixerList;
    MIXER_STATUS Status;
    LPMIDI_INFO MidiInfo;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    /* find destination midi */
    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, TRUE, &MidiInfo);
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find midi info */
        return MM_STATUS_UNSUCCESSFUL;
    }

    /* copy capabilities */
    MixerContext->Copy(Caps, &MidiInfo->u.InCaps, sizeof(MIDIINCAPSW));

    return MM_STATUS_SUCCESS;
}
Exemplo n.º 2
0
MIXER_STATUS
MMixerSetWaveStatus(
    IN PMIXER_CONTEXT MixerContext,
    IN HANDLE PinHandle,
    IN KSSTATE State)
{
    KSPROPERTY Property;
    ULONG Length;
    MIXER_STATUS Status;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* setup property request */
    Property.Set = KSPROPSETID_Connection;
    Property.Id = KSPROPERTY_CONNECTION_STATE;
    Property.Flags = KSPROPERTY_TYPE_SET;

    return MixerContext->Control(PinHandle, IOCTL_KS_PROPERTY, &Property, sizeof(KSPROPERTY), &State, sizeof(KSSTATE), &Length);
}
Exemplo n.º 3
0
MIXER_STATUS
MMixerWaveOutCapabilities(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG DeviceIndex,
    OUT LPWAVEOUTCAPSW Caps)
{
    PMIXER_LIST MixerList;
    MIXER_STATUS Status;
    LPWAVE_INFO WaveInfo;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    /* find destination wave */
    Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, FALSE, &WaveInfo);
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find wave info */
        return MM_STATUS_UNSUCCESSFUL;
    }

    /* copy capabilities */
    MixerContext->Copy(Caps, &WaveInfo->u.OutCaps, sizeof(WAVEOUTCAPSW));

    return MM_STATUS_SUCCESS;
}
Exemplo n.º 4
0
MIXER_STATUS
MMixerGetMidiDevicePath(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG bMidiIn,
    IN ULONG DeviceId,
    OUT LPWSTR * DevicePath)
{
    PMIXER_LIST MixerList;
    LPMIXER_DATA MixerData;
    LPMIDI_INFO MidiInfo;
    ULONG Length;
    MIXER_STATUS Status;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    /* find destination midi */
    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceId, bMidiIn, &MidiInfo);
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find midi info */
        return MM_STATUS_INVALID_PARAMETER;
    }

    /* get associated device id */
    MixerData = MMixerGetDataByDeviceId(MixerList, MidiInfo->DeviceId);
    if (!MixerData)
        return MM_STATUS_INVALID_PARAMETER;

    /* calculate length */
    Length = wcslen(MixerData->DeviceName)+1;

    /* allocate destination buffer */
    *DevicePath = MixerContext->Alloc(Length * sizeof(WCHAR));

    if (!*DevicePath)
    {
        /* no memory */
        return MM_STATUS_NO_MEMORY;
    }

    /* copy device path */
    MixerContext->Copy(*DevicePath, MixerData->DeviceName, Length * sizeof(WCHAR));

    /* done */
    return MM_STATUS_SUCCESS;
}
Exemplo n.º 5
0
MIXER_STATUS
MMixerOpenWave(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG DeviceIndex,
    IN ULONG bWaveIn,
    IN LPWAVEFORMATEX WaveFormat,
    IN PIN_CREATE_CALLBACK CreateCallback,
    IN PVOID Context,
    OUT PHANDLE PinHandle)
{
    PMIXER_LIST MixerList;
    MIXER_STATUS Status;
    LPWAVE_INFO WaveInfo;
    ACCESS_MASK DesiredAccess = 0;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    if (WaveFormat->wFormatTag != WAVE_FORMAT_PCM)
    {
        /* not implemented */
        return MM_STATUS_NOT_IMPLEMENTED;
    }

    /* find destination wave */
    Status = MMixerGetWaveInfoByIndexAndType(MixerList, DeviceIndex, bWaveIn, &WaveInfo);
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find wave info */
        return MM_STATUS_INVALID_PARAMETER;
    }

    /* get desired access */
    if (bWaveIn)
    {
        DesiredAccess |= GENERIC_READ;
    }
     else
    {
        DesiredAccess |= GENERIC_WRITE;
    }

    /* now try open the pin */
    return MMixerOpenWavePin(MixerContext, MixerList, WaveInfo->DeviceId, WaveInfo->PinId, WaveFormat, DesiredAccess, CreateCallback, Context, PinHandle);
}
Exemplo n.º 6
0
MIXER_STATUS
MMixerOpenMidi(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG DeviceIndex,
    IN ULONG bMidiIn,
    IN PIN_CREATE_CALLBACK CreateCallback,
    IN PVOID Context,
    OUT PHANDLE PinHandle)
{
    PMIXER_LIST MixerList;
    MIXER_STATUS Status;
    LPMIDI_INFO MidiInfo;
    ACCESS_MASK DesiredAccess = 0;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    /* find destination midi */
    Status = MMixerGetMidiInfoByIndexAndType(MixerList, DeviceIndex, bMidiIn, &MidiInfo);
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find midi info */
        return MM_STATUS_INVALID_PARAMETER;
    }

    /* get desired access */
    if (bMidiIn)
    {
        DesiredAccess |= GENERIC_READ;
    }
     else
    {
        DesiredAccess |= GENERIC_WRITE;
    }

    /* now try open the pin */
    return MMixerOpenMidiPin(MixerContext, MixerList, MidiInfo->DeviceId, MidiInfo->PinId, DesiredAccess, CreateCallback, Context, PinHandle);
}
Exemplo n.º 7
0
ULONG
MMixerGetMidiOutCount(
    IN PMIXER_CONTEXT MixerContext)
{
    PMIXER_LIST MixerList;
    MIXER_STATUS Status;

     /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* grab mixer list */
    MixerList = (PMIXER_LIST)MixerContext->MixerContext;

    return MixerList->MidiOutListCount;
}
Exemplo n.º 8
0
MIXER_STATUS
MMixerOpen(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG MixerId,
    IN PVOID MixerEventContext,
    IN PMIXER_EVENT MixerEventRoutine,
    OUT PHANDLE MixerHandle)
{
    MIXER_STATUS Status;
    LPMIXER_INFO MixerInfo;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        DPRINT1("invalid context\n");
        return Status;
    }

    /* get mixer info */
    MixerInfo = (LPMIXER_INFO)MMixerGetMixerInfoByIndex(MixerContext, MixerId);
    if (!MixerInfo)
    {
        /* invalid mixer id */
        DPRINT1("invalid mixer id %lu\n", MixerId);
        return MM_STATUS_INVALID_PARAMETER;
    }

    /* add the event */
    Status = MMixerAddEvent(MixerContext, MixerInfo, MixerEventContext, MixerEventRoutine);


    /* store result */
    *MixerHandle = (HANDLE)MixerInfo;
    return MM_STATUS_SUCCESS;
}
Exemplo n.º 9
0
MIXER_STATUS
MMixerGetCapabilities(
    IN PMIXER_CONTEXT MixerContext,
    IN ULONG MixerIndex,
    OUT LPMIXERCAPSW MixerCaps)
{
    MIXER_STATUS Status;
    LPMIXER_INFO MixerInfo;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* get mixer info */
    MixerInfo = MMixerGetMixerInfoByIndex(MixerContext, MixerIndex);

    if (!MixerInfo)
    {
        // invalid device index
        return MM_STATUS_INVALID_PARAMETER;
    }

    MixerCaps->wMid = MixerInfo->MixCaps.wMid;
    MixerCaps->wPid = MixerInfo->MixCaps.wPid;
    MixerCaps->vDriverVersion = MixerInfo->MixCaps.vDriverVersion;
    MixerCaps->fdwSupport = MixerInfo->MixCaps.fdwSupport;
    MixerCaps->cDestinations = MixerInfo->MixCaps.cDestinations;

    ASSERT(MixerInfo->MixCaps.szPname[MAXPNAMELEN-1] == 0);
    wcscpy(MixerCaps->szPname, MixerInfo->MixCaps.szPname);

    return MM_STATUS_SUCCESS;
}
Exemplo n.º 10
0
MIXER_STATUS
MMixerSetWaveResetState(
    IN PMIXER_CONTEXT MixerContext,
    IN HANDLE PinHandle,
    IN ULONG bBegin)
{
    ULONG Length;
    MIXER_STATUS Status;
    KSRESET Reset;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    /* begin / stop reset */
    Reset = (bBegin ? KSRESET_BEGIN : KSRESET_END);

    return MixerContext->Control(PinHandle, IOCTL_KS_RESET_STATE, &Reset, sizeof(KSRESET), NULL, 0, &Length);
}
Exemplo n.º 11
0
MIXER_STATUS
MMixerGetControlDetails(
    IN PMIXER_CONTEXT MixerContext,
    IN HANDLE MixerHandle,
    IN ULONG MixerId,
    IN ULONG Flags,
    OUT LPMIXERCONTROLDETAILS MixerControlDetails)
{
    MIXER_STATUS Status;
    ULONG NodeId;
    LPMIXER_INFO MixerInfo;
    LPMIXERLINE_EXT MixerLine;
    LPMIXERCONTROL_EXT MixerControl;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
    {
        /* caller passed mixer id */
        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);

        if (!MixerHandle)
        {
            /* invalid parameter */
            return MM_STATUS_INVALID_PARAMETER;
        }
    }

    /* get mixer info */
    MixerInfo = (LPMIXER_INFO)MixerHandle;

    /* get mixer control */
     Status = MMixerGetMixerControlById(MixerInfo, MixerControlDetails->dwControlID, &MixerLine, &MixerControl, &NodeId);

    /* check for success */
    if (Status != MM_STATUS_SUCCESS)
    {
        /* failed to find control id */
        return MM_STATUS_INVALID_PARAMETER;
    }

    switch(MixerControl->Control.dwControlType)
    {
        case MIXERCONTROL_CONTROLTYPE_MUTE:
            Status = MMixerSetGetMuteControlDetails(MixerContext, MixerInfo, MixerControl, MixerLine->Line.dwLineID, MixerControlDetails, FALSE);
            break;
        case MIXERCONTROL_CONTROLTYPE_VOLUME:
            Status = MMixerSetGetVolumeControlDetails(MixerContext, MixerInfo, NodeId, FALSE, MixerControl, MixerControlDetails, MixerLine);
            break;
        case MIXERCONTROL_CONTROLTYPE_ONOFF:
            DPRINT1("Not Implemented MIXERCONTROL_CONTROLTYPE_ONOFF\n");
            break;
        case MIXERCONTROL_CONTROLTYPE_MUX:
            Status = MMixerSetGetMuxControlDetails(MixerContext, MixerInfo, NodeId, FALSE, Flags, MixerControl, MixerControlDetails, MixerLine);
            break;

        default:
            Status = MM_STATUS_NOT_IMPLEMENTED;
            DPRINT1("ControlType %lx not implemented\n", MixerControl->Control.dwControlType);
    }

    return Status;
}
Exemplo n.º 12
0
MIXER_STATUS
MMixerGetLineControls(
    IN PMIXER_CONTEXT MixerContext,
    IN HANDLE MixerHandle,
    IN ULONG MixerId,
    IN ULONG Flags,
    OUT LPMIXERLINECONTROLSW MixerLineControls)
{
    LPMIXER_INFO MixerInfo;
    LPMIXERLINE_EXT MixerLineSrc;
    LPMIXERCONTROL_EXT MixerControl;
    MIXER_STATUS Status;
    PLIST_ENTRY Entry;
    ULONG Index;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }

    if (MixerLineControls->cbStruct != sizeof(MIXERLINECONTROLSW))
    {
        DPRINT1("Invalid MixerLineControls cbStruct passed %lu expected %lu\n", MixerLineControls->cbStruct, sizeof(MIXERLINECONTROLSW));
        /* invalid parameter */
        return MM_STATUS_INVALID_PARAMETER;
    }

    if (MixerLineControls->cbmxctrl != sizeof(MIXERCONTROLW))
    {
        DPRINT1("Invalid MixerLineControls cbmxctrl passed %lu expected %lu\n", MixerLineControls->cbStruct, sizeof(MIXERLINECONTROLSW));
        /* invalid parameter */
        return MM_STATUS_INVALID_PARAMETER;
    }

    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
    {
        /* caller passed mixer id */
        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);

        if (!MixerHandle)
        {
            /* invalid parameter */
            return MM_STATUS_INVALID_PARAMETER;
        }
    }

    Flags &= ~MIXER_OBJECTF_HMIXER;

    DPRINT("MMixerGetLineControls MixerId %lu Flags %lu\n", MixerId, Flags);

    if (Flags == MIXER_GETLINECONTROLSF_ALL)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* get mixer line */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);

        if (!MixerLineSrc)
        {
            /* invalid line id */
            DPRINT("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
            return MM_STATUS_INVALID_PARAMETER;
        }

        if (MixerLineSrc->Line.cControls != MixerLineControls->cControls)
        {
            /* invalid parameter */
            DPRINT1("Invalid control count %lu expected %lu\n", MixerLineControls->cControls, MixerLineSrc->Line.cControls);
            return MM_STATUS_INVALID_PARAMETER;
        }

        /* copy line control(s) */
        Entry = MixerLineSrc->ControlsList.Flink;
        Index = 0;
        while(Entry != &MixerLineSrc->ControlsList)
        {
            /* get mixer control */
            MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);

            /* copy mixer control */
            MixerContext->Copy(&MixerLineControls->pamxctrl[Index], &MixerControl->Control, sizeof(MIXERCONTROLW));

            /* move to next */
            Entry = Entry->Flink;

            /* increment mixer control offset */
            Index++;
        }
        return MM_STATUS_SUCCESS;
    }
    else if (Flags == MIXER_GETLINECONTROLSF_ONEBYTYPE)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* get mixer line */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLineControls->dwLineID);

        if (!MixerLineSrc)
        {
            /* invalid line id */
            DPRINT1("MMixerGetLineControls Line not found %lx\n", MixerLineControls->dwLineID);
            return MM_STATUS_INVALID_PARAMETER;
        }

        /* sanity checks */
        ASSERT(MixerLineControls->cControls == 1);
        ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
        ASSERT(MixerLineControls->pamxctrl != NULL);

        Entry = MixerLineSrc->ControlsList.Flink;
        while(Entry != &MixerLineSrc->ControlsList)
        {
            MixerControl = (LPMIXERCONTROL_EXT)CONTAINING_RECORD(Entry, MIXERCONTROL_EXT, Entry);
            if (MixerLineControls->dwControlType == MixerControl->Control.dwControlType)
            {
                /* found a control with that type */
                MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
                return MM_STATUS_SUCCESS;
            }

            /* move to next entry */
            Entry = Entry->Flink;
         }

         DPRINT("DeviceInfo->u.MixControls.dwControlType %x not found in Line %x cControls %u \n", MixerLineControls->dwControlType, MixerLineControls->dwLineID, MixerLineSrc->Line.cControls);
         return MM_STATUS_UNSUCCESSFUL;
    }
    else if (Flags == MIXER_GETLINECONTROLSF_ONEBYID)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        Status = MMixerGetMixerControlById(MixerInfo, MixerLineControls->dwControlID, NULL, &MixerControl, NULL);

        if (Status != MM_STATUS_SUCCESS)
        {
            /* invalid parameter */
            DPRINT("MMixerGetLineControls ControlID not found %lx\n", MixerLineControls->dwLineID);
            return MM_STATUS_INVALID_PARAMETER;
        }

        ASSERT(MixerLineControls->cControls == 1);
        ASSERT(MixerLineControls->cbmxctrl == sizeof(MIXERCONTROLW));
        ASSERT(MixerLineControls->pamxctrl != NULL);

       DPRINT("MMixerGetLineControls ControlID %lx ControlType %lx Name %S\n", MixerControl->Control.dwControlID, MixerControl->Control.dwControlType, MixerControl->Control.szName);

        /* copy the controls */
        MixerContext->Copy(MixerLineControls->pamxctrl, &MixerControl->Control, sizeof(MIXERCONTROLW));
        MixerLineControls->pamxctrl->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
        MixerLineControls->pamxctrl->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';

        return MM_STATUS_SUCCESS;
    }
    UNIMPLEMENTED
    return MM_STATUS_NOT_IMPLEMENTED;
}
Exemplo n.º 13
0
MIXER_STATUS
MMixerGetLineInfo(
    IN PMIXER_CONTEXT MixerContext,
    IN HANDLE MixerHandle,
    IN ULONG MixerId,
    IN ULONG Flags,
    OUT LPMIXERLINEW MixerLine)
{
    MIXER_STATUS Status;
    LPMIXER_INFO MixerInfo;
    LPMIXERLINE_EXT MixerLineSrc;
    ULONG DestinationLineID;

    /* verify mixer context */
    Status = MMixerVerifyContext(MixerContext);

    if (Status != MM_STATUS_SUCCESS)
    {
        /* invalid context passed */
        return Status;
    }
    if ((Flags & (MIXER_OBJECTF_MIXER | MIXER_OBJECTF_HMIXER)) == MIXER_OBJECTF_MIXER)
    {
        /* caller passed mixer id */
        MixerHandle = (HANDLE)MMixerGetMixerInfoByIndex(MixerContext, MixerId);

        if (!MixerHandle)
        {
            /* invalid parameter */
            return MM_STATUS_INVALID_PARAMETER;
        }
    }

    if (MixerLine->cbStruct != sizeof(MIXERLINEW))
    {
        DPRINT1("MixerLine Expected %lu but got %lu\n", sizeof(MIXERLINEW), MixerLine->cbStruct);
        return MM_STATUS_INVALID_PARAMETER;
    }

    /* clear hmixer from flags */
    Flags &=~MIXER_OBJECTF_HMIXER;

    DPRINT("MMixerGetLineInfo MixerId %lu Flags %lu\n", MixerId, Flags);

    if (Flags == MIXER_GETLINEINFOF_DESTINATION)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* calculate destination line id */
        DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);

        /* get destination line */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);

        if (MixerLineSrc == NULL)
        {
            DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
            return MM_STATUS_UNSUCCESSFUL;
        }
        /* copy mixer line */
        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));

        /* make sure it is null terminated */
        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';

        /* done */
        return MM_STATUS_SUCCESS;
    }
    else if (Flags == MIXER_GETLINEINFOF_SOURCE)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* calculate destination line id */
        DestinationLineID = (MixerLine->dwDestination + DESTINATION_LINE);

        /* get destination line */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);

        if (MixerLineSrc == NULL)
        {
            DPRINT1("MixerCaps Name %S DestinationLineCount %lu dwDestination %lu not found\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations, MixerLine->dwDestination);
            return MM_STATUS_UNSUCCESSFUL;
        }

        /* check if dwSource is out of bounds */
        if (MixerLine->dwSource >= MixerLineSrc->Line.cConnections)
        {
            DPRINT1("MixerCaps Name %S MixerLineName %S Connections %lu dwSource %lu not found\n", MixerInfo->MixCaps.szPname, MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections, MixerLine->dwSource);
            return MM_STATUS_UNSUCCESSFUL;
        }

        /* calculate destination line id */
        DestinationLineID = (MixerLine->dwSource * SOURCE_LINE) + MixerLine->dwDestination;

        DPRINT("MixerName %S cDestinations %lu MixerLineName %S cConnections %lu dwSource %lu dwDestination %lu ID %lx\n", MixerInfo->MixCaps.szPname, MixerInfo->MixCaps.cDestinations,
                                                                                                                            MixerLineSrc->Line.szName, MixerLineSrc->Line.cConnections,
                                                                                                                            MixerLine->dwSource, MixerLine->dwDestination,
                                                                                                                            DestinationLineID);
        /* get target destination line id */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, DestinationLineID);

        /* sanity check */
        ASSERT(MixerLineSrc);

        DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);

        /* copy mixer line */
        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));

        /* make sure it is null terminated */
        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';

        /* done */
        return MM_STATUS_SUCCESS;
    }
    else if (Flags == MIXER_GETLINEINFOF_LINEID)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* try to find line */
        MixerLineSrc = MMixerGetSourceMixerLineByLineId(MixerInfo, MixerLine->dwLineID);
        if (!MixerLineSrc)
        {
            /* invalid parameter */
            DPRINT1("MMixerGetLineInfo: MixerName %S Line not found 0x%lx\n", MixerInfo->MixCaps.szPname, MixerLine->dwLineID);
            return MM_STATUS_INVALID_PARAMETER;
        }

        DPRINT("Line %u Name %S\n", MixerLineSrc->Line.dwSource, MixerLineSrc->Line.szName);

        /* copy mixer line*/
        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));

        /* make sure it is null terminated */
        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';

        return MM_STATUS_SUCCESS;
    }
    else if (Flags == MIXER_GETLINEINFOF_COMPONENTTYPE)
    {
        /* cast to mixer info */
        MixerInfo = (LPMIXER_INFO)MixerHandle;

        /* find mixer line by component type */
        MixerLineSrc = MMixerGetSourceMixerLineByComponentType(MixerInfo, MixerLine->dwComponentType);
        if (!MixerLineSrc)
        {
            DPRINT1("Failed to find component type %x\n", MixerLine->dwComponentType);
            return MM_STATUS_UNSUCCESSFUL;
        }

        /* copy mixer line */
        MixerContext->Copy(MixerLine, &MixerLineSrc->Line, sizeof(MIXERLINEW));

        /* make sure it is null terminated */
        MixerLine->szName[MIXER_LONG_NAME_CHARS-1] = L'\0';
        MixerLine->szShortName[MIXER_SHORT_NAME_CHARS-1] = L'\0';
        MixerLine->Target.szPname[MAXPNAMELEN-1] = L'\0';

        /* done */
        return MM_STATUS_SUCCESS;
    }
    else if (Flags == MIXER_GETLINEINFOF_TARGETTYPE)
    {
        DPRINT1("MIXER_GETLINEINFOF_TARGETTYPE handling is unimplemented\n");
    }
    else
    {
        DPRINT1("Unknown Flags %lx handling is unimplemented\n", Flags);
    }

    return MM_STATUS_NOT_IMPLEMENTED;
}