Esempio n. 1
0
MMRESULT
WdmAudResetStreamByLegacy(
    IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
    IN  MMDEVICE_TYPE DeviceType,
    IN  BOOLEAN bStartReset)
{
    MMRESULT Result;
    HANDLE Handle;
    WDMAUD_DEVICE_INFO DeviceInfo;

    Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.hDevice = Handle;
    DeviceInfo.DeviceType = DeviceType;
    DeviceInfo.u.ResetStream = (bStartReset ? KSRESET_BEGIN : KSRESET_END);

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_RESET_STREAM,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);
    return Result;
}
Esempio n. 2
0
MMRESULT
WdmAudGetNumWdmDevsByLegacy(
    IN  MMDEVICE_TYPE DeviceType,
    OUT DWORD* DeviceCount)
{
    MMRESULT Result;
    WDMAUD_DEVICE_INFO DeviceInfo;

    VALIDATE_MMSYS_PARAMETER( KernelHandle != INVALID_HANDLE_VALUE );
    VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
    VALIDATE_MMSYS_PARAMETER( DeviceCount );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.DeviceType = DeviceType;

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_GETNUMDEVS_TYPE,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS( Result ) )
    {
        SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
        *DeviceCount = 0;
        return TranslateInternalMmResult(Result);
    }

    *DeviceCount = DeviceInfo.DeviceCount;

    return MMSYSERR_NOERROR;
}
Esempio n. 3
0
MMRESULT
SetNt4WaveDeviceFormat(
    IN  PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
    IN  DWORD DeviceId,
    IN  LPWAVEFORMATEX Format,
    IN  DWORD FormatSize)
{
    MMRESULT Result;
    HANDLE Handle;

    VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
    VALIDATE_MMSYS_PARAMETER( Format );
    VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );

    Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);

    if ( ! MMSUCCESS(Result) )
        return TranslateInternalMmResult(Result);

    SND_TRACE(L"Setting wave device format on handle %x\n", Handle);

    Result = SyncOverlappedDeviceIoControl(Handle,
                                           IOCTL_WAVE_SET_FORMAT,
                                           (LPVOID) Format,
                                           FormatSize,
                                           NULL,
                                           0,
                                           NULL);

    if ( ! MMSUCCESS(Result) )
        return TranslateInternalMmResult(Result);

    return MMSYSERR_NOERROR;
}
Esempio n. 4
0
DWORD
WINAPI
MixerEventThreadRoutine(
    LPVOID Parameter)
{
    HANDLE WaitObjects[2];
    DWORD dwResult;
    MMRESULT Result;
    WDMAUD_DEVICE_INFO DeviceInfo;
    PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)Parameter;

    /* setup wait objects */
    WaitObjects[0] = Instance->hNotifyEvent;
    WaitObjects[1] = Instance->hStopEvent;

    /* zero device info */
    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));

    DeviceInfo.hDevice = Instance->Handle;
    DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;

    do
    {
        dwResult = WaitForMultipleObjects(2, WaitObjects, FALSE, INFINITE);

        if (dwResult == WAIT_OBJECT_0 + 1)
        {
            /* stop event was signalled */
            break;
        }

        do
        {
            Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                                   IOCTL_GET_MIXER_EVENT,
                                                   (LPVOID) &DeviceInfo,
                                                   sizeof(WDMAUD_DEVICE_INFO),
                                                   (LPVOID) &DeviceInfo,
                                                   sizeof(WDMAUD_DEVICE_INFO),
                                                   NULL);

            if (Result == MMSYSERR_NOERROR)
            {
                DriverCallback(Instance->WinMM.ClientCallback,
                               HIWORD(Instance->WinMM.Flags),
                               Instance->WinMM.Handle,
                               DeviceInfo.u.MixerEvent.NotificationType,
                               Instance->WinMM.ClientCallbackInstanceData,
                               (DWORD_PTR)DeviceInfo.u.MixerEvent.Value,
                               0);
            }
        } while(Result == MMSYSERR_NOERROR);
    } while(TRUE);

    /* done */
    return 0;
}
Esempio n. 5
0
MMRESULT
WdmAudSetMixerDeviceFormatByLegacy(
    IN  PSOUND_DEVICE_INSTANCE Instance,
    IN  DWORD DeviceId,
    IN  PWAVEFORMATEX WaveFormat,
    IN  DWORD WaveFormatSize)
{
    MMRESULT Result;
    WDMAUD_DEVICE_INFO DeviceInfo;
    HANDLE hThread;

    Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
    if ( ! Instance->hNotifyEvent )
        return MMSYSERR_NOMEM;

    if (Instance->Handle != NULL)
    {
        /* device is already open */
        return MMSYSERR_NOERROR;
    }

    Instance->hStopEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
    if ( ! Instance->hStopEvent )
        return MMSYSERR_NOMEM;

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
    DeviceInfo.DeviceIndex = DeviceId;
    DeviceInfo.u.hNotifyEvent = Instance->hNotifyEvent;

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_OPEN_WDMAUD,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        CloseHandle(Instance->hNotifyEvent);
        CloseHandle(Instance->hStopEvent);
        return TranslateInternalMmResult(Result);
    }

    hThread = CreateThread(NULL, 0, MixerEventThreadRoutine, (LPVOID)Instance, 0, NULL);
    if (  hThread )
    {
        CloseHandle(hThread);
    }

    /* Store sound device handle instance handle */
    Instance->Handle = (PVOID)DeviceInfo.hDevice;

    return MMSYSERR_NOERROR;
}
Esempio n. 6
0
HRESULT
WINAPI
IDirectSoundCaptureBufferImpl_Stop( LPDIRECTSOUNDCAPTUREBUFFER8 iface )
{
    KSPROPERTY Property;
    DWORD Result;
    KSSTATE State;

    LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);

    if (This->State == KSSTATE_STOP)
    {
        /* stream has already been stopped */
        return DS_OK;
    }

    if (!This->hPin)
        return DSERR_GENERIC;

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


    /* set pin to stop */
    Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), NULL);

    ASSERT(Result == ERROR_SUCCESS);


    if (This->bMix)
    {
        /* sanity check */
        ASSERT(This->hStopEvent);
        /* reset event */
        ResetEvent(This->hStopEvent);
        /* signal event to stop */
        This->StopMixerThread = TRUE;
        /* Wait for the event to stop */
        WaitForSingleObject(This->hStopEvent, INFINITE);
    }


    if (Result == ERROR_SUCCESS)
    {
        /* store result */
        This->State = State;
        return DS_OK;
    }

    DPRINT("Failed to stop pin\n");
    return DSERR_GENERIC;
}
Esempio n. 7
0
MMRESULT
WdmAudGetWavePositionByLegacy(
    IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
    IN  MMTIME* Time)
{
    MMRESULT Result;
    PSOUND_DEVICE SoundDevice;
    WDMAUD_DEVICE_INFO DeviceInfo;
    MMDEVICE_TYPE DeviceType;
    HANDLE Handle;

    Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    Result = GetSoundDeviceType(SoundDevice, &DeviceType);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.hDevice = Handle;
    DeviceInfo.DeviceType = DeviceType;

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_OPEN_WDMAUD,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    Time->wType = TIME_BYTES;
    Time->u.cb = (DWORD)DeviceInfo.u.Position;

    return MMSYSERR_NOERROR;
}
Esempio n. 8
0
/*
    Querying/setting the format of a wave device. Querying format support
    requires us to first open the device, whereas setting format is done
    on an already opened device.
*/
MMRESULT
QueryNt4WaveDeviceFormatSupport(
    IN  PSOUND_DEVICE SoundDevice,
    IN  LPWAVEFORMATEX Format,
    IN  DWORD FormatSize)
{
    MMRESULT Result;
    HANDLE Handle;

    SND_TRACE(L"NT4 wave format support querying routine called\n");

    VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) );
    VALIDATE_MMSYS_PARAMETER( Format );
    VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) );

    /* Get the device path */
    Result = OpenNt4KernelSoundDevice(SoundDevice,
                                      FALSE,
                                      &Handle);

    if ( ! MMSUCCESS(Result) )
    {
        SND_ERR(L"Unable to open kernel sound device\n");
        return TranslateInternalMmResult(Result);
    }

    Result = SyncOverlappedDeviceIoControl(Handle,
                                           IOCTL_WAVE_QUERY_FORMAT,
                                           (LPVOID) Format,
                                           FormatSize,
                                           NULL,
                                           0,
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        SND_ERR(L"Sync overlapped I/O failed - MMSYS_ERROR %d\n", Result);
        Result = TranslateInternalMmResult(Result);
    }

    CloseKernelSoundDevice(Handle);

    return MMSYSERR_NOERROR;
}
Esempio n. 9
0
MMRESULT
WdmAudSetWaveStateByLegacy(
    IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
    IN BOOL bStart)
{
    MMRESULT Result;
    PSOUND_DEVICE SoundDevice;
    WDMAUD_DEVICE_INFO DeviceInfo;
    MMDEVICE_TYPE DeviceType;
    HANDLE Handle;

    Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    Result = GetSoundDeviceType(SoundDevice, &DeviceType);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.hDevice = Handle;
    DeviceInfo.DeviceType = DeviceType;

    if (bStart)
        DeviceInfo.u.State = KSSTATE_RUN;
    else
        DeviceInfo.u.State = KSSTATE_PAUSE;
    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_SETDEVICE_STATE,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    return Result;
}
Esempio n. 10
0
DWORD
WINAPI
IoStreamingThread(
    LPVOID lpParameter)
{
    DWORD Length;
    //MMRESULT Result;
    LPIO_PACKET Packet = (LPIO_PACKET)lpParameter;

    /*Result = */ SyncOverlappedDeviceIoControl(Packet->hDevice,
                    Packet->IoCtl,
                    NULL,
                    0,
                    &Packet->Header,
                    sizeof(KSSTREAM_HEADER),
                    &Length);

    Packet->CompletionRoutine(ERROR_SUCCESS, Packet->Header.DataUsed, (LPOVERLAPPED)Packet->Overlap);

    HeapFree(GetProcessHeap(), 0, Packet);
    return 0;
}
Esempio n. 11
0
HRESULT
WINAPI
IDirectSoundNotify_fnSetNotificationPositions(
    LPDIRECTSOUNDNOTIFY iface,
    DWORD dwPositionNotifies,
    LPCDSBPOSITIONNOTIFY pcPositionNotifies)
{
    DWORD Index;
    LPNOTIFYEVENT Notify;
    DWORD Result;
    KSEVENT Request;

    LPCDirectSoundNotifyImpl This = (LPCDirectSoundNotifyImpl)CONTAINING_RECORD(iface, CDirectSoundNotifyImpl, lpVtbl);

    if (dwPositionNotifies > DSBNOTIFICATIONS_MAX)
    {
        /* invalid param */
        return DSERR_INVALIDPARAM;
    }

    /* verify notification event handles */
    for(Index = 0; Index < dwPositionNotifies; Index++)
    {
        ASSERT(pcPositionNotifies[Index].hEventNotify);
        ASSERT(pcPositionNotifies[Index].dwOffset < This->BufferSize || pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP);

        if (pcPositionNotifies[Index].hEventNotify == NULL)
            return DSERR_INVALIDPARAM;

        if (pcPositionNotifies[Index].dwOffset > This->BufferSize && pcPositionNotifies[Index].dwOffset != DSBPN_OFFSETSTOP)
            return DSERR_INVALIDPARAM;
    }

    /* allocate new array */
    Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(NOTIFYEVENT));
    if (!Notify)
    {
        /* not enough memory */
        return DSERR_OUTOFMEMORY;
    }

    /* allocate new array */
    Notify->Notify = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwPositionNotifies * sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA));
    if (!Notify->Notify)
    {
        /* not enough memory */
        HeapFree(GetProcessHeap(), 0, Notify);
        return DSERR_OUTOFMEMORY;
    }

    /* FIXME support non-looped streaming */
    ASSERT(This->bLoop);

    /* prepare request */
    Request.Set = KSEVENTSETID_LoopedStreaming;
    Request.Id = KSEVENT_LOOPEDSTREAMING_POSITION;
    Request.Flags = KSEVENT_TYPE_ENABLE;

    for(Index = 0; Index < dwPositionNotifies; Index++)
    {
        /* initialize event entries */
        Notify->Notify[Index].Position = pcPositionNotifies[Index].dwOffset;
        Notify->Notify[Index].KsEventData.EventHandle.Event = pcPositionNotifies[Index].hEventNotify;
        Notify->Notify[Index].KsEventData.NotificationType = KSEVENTF_EVENT_HANDLE;

        if (This->bMix == FALSE)
        {
            /* format is supported natively */
            Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_ENABLE_EVENT, (PVOID)&Request, sizeof(KSEVENT), (PVOID)&Notify->Notify[Index], sizeof(LOOPEDSTREAMING_POSITION_EVENT_DATA), NULL);

            if (Result != ERROR_SUCCESS)
            {
                DPRINT1("Failed to enable event %p Position %u\n", pcPositionNotifies[Index].hEventNotify, pcPositionNotifies[Index].dwOffset);
            }
        }
    }

    /* enlarge notify count */
    Notify->NotifyCount = dwPositionNotifies;

    if (This->EventListHead)
    {
        Notify->lpNext = This->EventListHead;
    }

    /* insert at front */
    (void)InterlockedExchangePointer((LPVOID*)&This->EventListHead, Notify);

    return DS_OK;
}
Esempio n. 12
0
DWORD
WINAPI
MixerThreadRoutine(
    LPVOID lpParameter)
{
    KSPROPERTY Request;
    KSAUDIO_POSITION Position;
    DWORD Result, MixPosition, BufferPosition, BytesWritten, BytesRead, MixLength, BufferLength;
    LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)lpParameter;

    /* setup audio position property request */
    Request.Id = KSPROPERTY_AUDIO_POSITION;
    Request.Set = KSPROPSETID_Audio;
    Request.Flags = KSPROPERTY_TYPE_GET;

    MixPosition = 0;
    BufferPosition = 0;
    do
    {
        /* query current position */
        Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL);

        /* sanity check */
        ASSERT(Result == ERROR_SUCCESS);

        /* FIXME implement samplerate conversion */
        ASSERT(This->MixFormat.nSamplesPerSec == This->Format->nSamplesPerSec);

        /* FIXME implement bitrate conversion */
        ASSERT(This->MixFormat.wBitsPerSample == This->Format->wBitsPerSample);

        /* sanity check */
        ASSERT(BufferPosition <= This->BufferSize);
        ASSERT(MixPosition  <= This->MixBufferSize);

        if (BufferPosition == This->BufferSize)
        {
            /* restart from front */
            BufferPosition = 0;
        }

        if (MixPosition == This->MixBufferSize)
        {
            /* restart from front */
            MixPosition = 0;
        }

        if (This->MixFormat.nChannels != This->Format->nChannels)
        {
            if ((DWORD)Position.PlayOffset >= MixPosition)
            {
                /* calculate buffer position difference */
                MixLength = Position.PlayOffset - MixPosition;
            }
            else
            {
                /* buffer overlap */
                MixLength = This->MixBufferSize - MixPosition;
            }

            BufferLength = This->BufferSize - BufferPosition;

            /* convert the format */
            PerformChannelConversion(&This->MixBuffer[MixPosition], MixLength, &BytesRead, This->MixFormat.nChannels, This->Format->nChannels, This->Format->wBitsPerSample, &This->Buffer[BufferPosition], BufferLength, &BytesWritten);

            /* update buffer offsets */
            MixPosition += BytesRead;
            BufferPosition += BytesWritten;
            DPRINT("MixPosition %u BufferPosition %u BytesRead %u BytesWritten %u MixLength %u BufferLength %u\n", MixPosition, BufferPosition, BytesRead, BytesWritten, MixLength, BufferLength);
        }

        /* Notify Events */
        if (This->Notify)
        {
            DoNotifyPositionEvents(This->Notify, This->CurrentMixPosition, BufferPosition);
        }

        /* update offset */
        InterlockedExchange(&This->CurrentMixPosition, (LONG)BufferPosition);

        /* FIXME use timer */
        Sleep(10);

    }while(InterlockedCompareExchange(&This->StopMixerThread, 0, 0) == 0);


    /* signal stop event */
    SetEvent(This->hStopEvent);

    /* done */
    return 0;
}
Esempio n. 13
0
/*
    Provides an implementation for the "get capabilities" request,
    using the standard IOCTLs used by NT4 sound drivers.
*/
MMRESULT
GetNt4SoundDeviceCapabilities(
    IN  PSOUND_DEVICE SoundDevice,
    OUT PVOID Capabilities,
    IN  DWORD CapabilitiesSize)
{
    MMRESULT Result;
    MMDEVICE_TYPE DeviceType;
    DWORD IoCtl;
    HANDLE DeviceHandle;

    /* If these are bad there's an internal error with MME-Buddy! */
    SND_ASSERT( SoundDevice );
    SND_ASSERT( Capabilities );
    SND_ASSERT( CapabilitiesSize > 0 );

    SND_TRACE(L"NT4 get-capabilities routine called\n");

    /* Get the device type */
    Result = GetSoundDeviceType(SoundDevice, &DeviceType);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    if ( ! MMSUCCESS(Result) )
        return TranslateInternalMmResult(Result);

    /* Choose the appropriate IOCTL */
    if ( IS_WAVE_DEVICE_TYPE(DeviceType) )
    {
        IoCtl = IOCTL_WAVE_GET_CAPABILITIES;
    }
    else if ( IS_MIDI_DEVICE_TYPE(DeviceType) )
    {
        IoCtl = IOCTL_MIDI_GET_CAPABILITIES;
    }
    else
    {
        /* FIXME - need to support AUX and mixer devices */
        SND_ASSERT( FALSE );
        IoCtl = 0;
    }

    /* Get the capabilities information from the driver */
    Result = OpenNt4KernelSoundDevice(SoundDevice, TRUE, &DeviceHandle);

    if ( ! MMSUCCESS(Result) )
    {
        SND_ERR(L"Failed to open device");
        return TranslateInternalMmResult(Result);
    }

    Result = SyncOverlappedDeviceIoControl(DeviceHandle,
                                           IoCtl,
                                           Capabilities,
                                           CapabilitiesSize,
                                           NULL,
                                           0,
                                           NULL);

    CloseKernelSoundDevice(DeviceHandle);

    if ( ! MMSUCCESS(Result) )
    {
        SND_ERR(L"Retrieval of capabilities information failed\n");
        Result = TranslateInternalMmResult(Result);
    }

    return Result;
}
Esempio n. 14
0
MMRESULT
WdmAudGetCapabilitiesByLegacy(
    IN  PSOUND_DEVICE SoundDevice,
    IN  DWORD DeviceId,
    OUT PVOID Capabilities,
    IN  DWORD CapabilitiesSize)
{
    MMRESULT Result;
    MMDEVICE_TYPE DeviceType;
    WDMAUD_DEVICE_INFO DeviceInfo;

    SND_ASSERT( SoundDevice );
    SND_ASSERT( Capabilities );

    Result = GetSoundDeviceType(SoundDevice, &DeviceType);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    if ( ! MMSUCCESS(Result) )
        return Result;

    SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities DeviceType %u DeviceId %u\n", DeviceType, DeviceId);

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.DeviceType = DeviceType;
    DeviceInfo.DeviceIndex = DeviceId;

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_GETCAPABILITIES,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    /* This is pretty much a big hack right now */
    switch ( DeviceType )
    {
    case MIXER_DEVICE_TYPE:
    {
        LPMIXERCAPSW MixerCaps = (LPMIXERCAPSW) Capabilities;

        DeviceInfo.u.MixCaps.szPname[MAXPNAMELEN-1] = L'\0';
        CopyWideString(MixerCaps->szPname, DeviceInfo.u.MixCaps.szPname);

        MixerCaps->cDestinations = DeviceInfo.u.MixCaps.cDestinations;
        MixerCaps->fdwSupport = DeviceInfo.u.MixCaps.fdwSupport;
        MixerCaps->vDriverVersion = DeviceInfo.u.MixCaps.vDriverVersion;
        MixerCaps->wMid = DeviceInfo.u.MixCaps.wMid;
        MixerCaps->wPid = DeviceInfo.u.MixCaps.wPid;
        break;
    }
    case WAVE_OUT_DEVICE_TYPE :
    {
        LPWAVEOUTCAPSW WaveOutCaps = (LPWAVEOUTCAPSW) Capabilities;

        DeviceInfo.u.WaveOutCaps.szPname[MAXPNAMELEN-1] = L'\0';
        WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
        WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;

        WaveOutCaps->vDriverVersion = DeviceInfo.u.WaveOutCaps.vDriverVersion;
        CopyWideString(WaveOutCaps->szPname, DeviceInfo.u.WaveOutCaps.szPname);

        WaveOutCaps->dwFormats = DeviceInfo.u.WaveOutCaps.dwFormats;
        WaveOutCaps->wChannels = DeviceInfo.u.WaveOutCaps.wChannels;
        WaveOutCaps->dwSupport = DeviceInfo.u.WaveOutCaps.dwSupport;
        break;
    }
    case WAVE_IN_DEVICE_TYPE :
    {
        LPWAVEINCAPSW WaveInCaps = (LPWAVEINCAPSW) Capabilities;

        DeviceInfo.u.WaveInCaps.szPname[MAXPNAMELEN-1] = L'\0';

        WaveInCaps->wMid = DeviceInfo.u.WaveInCaps.wMid;
        WaveInCaps->wPid = DeviceInfo.u.WaveInCaps.wPid;

        WaveInCaps->vDriverVersion = DeviceInfo.u.WaveInCaps.vDriverVersion;
        CopyWideString(WaveInCaps->szPname, DeviceInfo.u.WaveInCaps.szPname);

        WaveInCaps->dwFormats = DeviceInfo.u.WaveInCaps.dwFormats;
        WaveInCaps->wChannels = DeviceInfo.u.WaveInCaps.wChannels;
        WaveInCaps->wReserved1 = 0;
        break;
    }
    case MIDI_IN_DEVICE_TYPE :
    {
        LPMIDIINCAPSW MidiInCaps = (LPMIDIINCAPSW)Capabilities;

        DeviceInfo.u.MidiInCaps.szPname[MAXPNAMELEN-1] = L'\0';

        MidiInCaps->vDriverVersion = DeviceInfo.u.MidiInCaps.vDriverVersion;
        MidiInCaps->wMid = DeviceInfo.u.MidiInCaps.wMid;
        MidiInCaps->wPid = DeviceInfo.u.MidiInCaps.wPid;
        MidiInCaps->dwSupport = DeviceInfo.u.MidiInCaps.dwSupport;

        CopyWideString(MidiInCaps->szPname, DeviceInfo.u.MidiInCaps.szPname);
        break;
    }
    case MIDI_OUT_DEVICE_TYPE :
    {
        LPMIDIOUTCAPSW MidiOutCaps = (LPMIDIOUTCAPSW)Capabilities;

        DeviceInfo.u.MidiOutCaps.szPname[MAXPNAMELEN-1] = L'\0';

        MidiOutCaps->vDriverVersion = DeviceInfo.u.MidiOutCaps.vDriverVersion;
        MidiOutCaps->wMid = DeviceInfo.u.MidiOutCaps.wMid;
        MidiOutCaps->wPid = DeviceInfo.u.MidiOutCaps.wPid;
        MidiOutCaps->dwSupport = DeviceInfo.u.MidiOutCaps.dwSupport;

        CopyWideString(MidiOutCaps->szPname, DeviceInfo.u.MidiOutCaps.szPname);
        break;
    }
    }

    return MMSYSERR_NOERROR;
}
Esempio n. 15
0
HRESULT
WINAPI
IDirectSoundCaptureBufferImpl_Start(
    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
    DWORD dwFlags )
{
    KSPROPERTY Property;
    KSSTREAM_HEADER Header;
    DWORD Result, BytesTransferred;
    OVERLAPPED Overlapped;
    KSSTATE State;
    HANDLE hThread;

    LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);

    DPRINT("IDirectSoundCaptureBufferImpl_Start Flags %x\n", dwFlags);
    ASSERT(dwFlags == DSCBSTART_LOOPING);

    /* check if pin is already running */
    if (This->State == KSSTATE_RUN)
        return DS_OK;


    /* check if there is a pin instance */
    if (!This->hPin)
        return DSERR_GENERIC;

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

    /* set pin to run */
    Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesTransferred);

    ASSERT(Result == ERROR_SUCCESS);

    if (Result == ERROR_SUCCESS)
    {
        /* store result */
        This->State = State;
    }

    /* initialize overlapped struct */
    ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
    Overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    /* clear stream header */
    ZeroMemory(&Header, sizeof(KSSTREAM_HEADER));

    /* initialize stream header */
    Header.FrameExtent = This->BufferSize;
    Header.DataUsed = 0;
    Header.Data = (This->bMix ? This->MixBuffer : This->Buffer);
    Header.Size = sizeof(KSSTREAM_HEADER);
    Header.PresentationTime.Numerator = 1;
    Header.PresentationTime.Denominator = 1;

    Result = DeviceIoControl(This->hPin, IOCTL_KS_WRITE_STREAM, NULL, 0, &Header, sizeof(KSSTREAM_HEADER), &BytesTransferred, &Overlapped);

    if (Result != ERROR_SUCCESS)
    {
        DPRINT("Failed submit buffer with %lx\n", Result);
        return DSERR_GENERIC;
    }

    if (This->bMix)
    {
        if (!This->hStopEvent)
        {
            /* create stop event */
            This->hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
            if (!This->hStopEvent)
            {
                DPRINT1("Failed to create event object with %x\n", GetLastError());
                return DSERR_GENERIC;
            }
        }

        /* set state to stop false */
        This->StopMixerThread = FALSE;

        hThread = CreateThread(NULL, 0, MixerThreadRoutine, (PVOID)This, 0, NULL);
        if (!hThread)
        {
            DPRINT1("Failed to create thread with %x\n", GetLastError());
            return DSERR_GENERIC;
        }

        /* close thread handle */
        CloseHandle(hThread);
    }


    return DS_OK;
}
Esempio n. 16
0
MMRESULT
WdmAudQueryMixerInfoByLegacy(
    IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
    IN DWORD DeviceId,
    IN UINT uMsg,
    IN LPVOID Parameter,
    IN DWORD Flags)
{
    MMRESULT Result;
    WDMAUD_DEVICE_INFO DeviceInfo;
    HANDLE Handle;
    DWORD IoControlCode;
    LPMIXERLINEW MixLine;
    LPMIXERLINECONTROLSW MixControls;
    LPMIXERCONTROLDETAILS MixDetails;

    SND_TRACE(L"uMsg %x Flags %x\n", uMsg, Flags);

    Result = GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.hDevice = Handle;
    DeviceInfo.DeviceIndex = DeviceId;
    DeviceInfo.DeviceType = MIXER_DEVICE_TYPE;
    DeviceInfo.Flags = Flags;

    MixLine = (LPMIXERLINEW)Parameter;
    MixControls = (LPMIXERLINECONTROLSW)Parameter;
    MixDetails = (LPMIXERCONTROLDETAILS)Parameter;

    switch(uMsg)
    {
    case MXDM_GETLINEINFO:
        RtlCopyMemory(&DeviceInfo.u.MixLine, MixLine, sizeof(MIXERLINEW));
        IoControlCode = IOCTL_GETLINEINFO;
        break;
    case MXDM_GETLINECONTROLS:
        RtlCopyMemory(&DeviceInfo.u.MixControls, MixControls, sizeof(MIXERLINECONTROLSW));
        IoControlCode = IOCTL_GETLINECONTROLS;
        break;
    case MXDM_SETCONTROLDETAILS:
        RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
        IoControlCode = IOCTL_SETCONTROLDETAILS;
        break;
    case MXDM_GETCONTROLDETAILS:
        RtlCopyMemory(&DeviceInfo.u.MixDetails, MixDetails, sizeof(MIXERCONTROLDETAILS));
        IoControlCode = IOCTL_GETCONTROLDETAILS;
        break;
    default:
        SND_ASSERT(0);
        return MMSYSERR_NOTSUPPORTED;
    }

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IoControlCode,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        return Result;
    }

    switch(uMsg)
    {
    case MXDM_GETLINEINFO:
    {
        RtlCopyMemory(MixLine, &DeviceInfo.u.MixLine, sizeof(MIXERLINEW));
        break;
    }
    }

    return Result;
}
Esempio n. 17
0
MMRESULT
WdmAudCloseSoundDeviceByLegacy(
    IN  struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
    IN  PVOID Handle)
{
    WDMAUD_DEVICE_INFO DeviceInfo;
    MMRESULT Result;
    MMDEVICE_TYPE DeviceType;
    PSOUND_DEVICE SoundDevice;

    Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    if ( OpenCount == 0 )
    {
        return MMSYSERR_NOERROR;
    }

    SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );

    Result = GetSoundDeviceType(SoundDevice, &DeviceType);
    SND_ASSERT( Result == MMSYSERR_NOERROR );

    if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
    {
        ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));

        DeviceInfo.DeviceType = DeviceType;
        DeviceInfo.hDevice = SoundDeviceInstance->Handle;

        /* First stop the stream */
        if (DeviceType != MIXER_DEVICE_TYPE)
        {
            DeviceInfo.u.State = KSSTATE_PAUSE;
            SyncOverlappedDeviceIoControl(KernelHandle,
                                          IOCTL_SETDEVICE_STATE,
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          NULL);

            DeviceInfo.u.State = KSSTATE_ACQUIRE;
            SyncOverlappedDeviceIoControl(KernelHandle,
                                          IOCTL_SETDEVICE_STATE,
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          NULL);


            DeviceInfo.u.State = KSSTATE_STOP;
            SyncOverlappedDeviceIoControl(KernelHandle,
                                          IOCTL_SETDEVICE_STATE,
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          (LPVOID) &DeviceInfo,
                                          sizeof(WDMAUD_DEVICE_INFO),
                                          NULL);
        }

        SyncOverlappedDeviceIoControl(KernelHandle,
                                      IOCTL_CLOSE_WDMAUD,
                                      (LPVOID) &DeviceInfo,
                                      sizeof(WDMAUD_DEVICE_INFO),
                                      (LPVOID) &DeviceInfo,
                                      sizeof(WDMAUD_DEVICE_INFO),
                                      NULL);
    }

    if (DeviceType == MIXER_DEVICE_TYPE)
    {
        SetEvent(SoundDeviceInstance->hStopEvent);
        CloseHandle(SoundDeviceInstance->hStopEvent);
        CloseHandle(SoundDeviceInstance->hNotifyEvent);
    }

    --OpenCount;

    if ( OpenCount < 1 )
    {
        CloseHandle(KernelHandle);
        KernelHandle = INVALID_HANDLE_VALUE;
    }

    return MMSYSERR_NOERROR;
}
Esempio n. 18
0
MMRESULT
WdmAudSetWaveDeviceFormatByLegacy(
    IN  PSOUND_DEVICE_INSTANCE Instance,
    IN  DWORD DeviceId,
    IN  PWAVEFORMATEX WaveFormat,
    IN  DWORD WaveFormatSize)
{
    MMRESULT Result;
    PSOUND_DEVICE SoundDevice;
    PVOID Identifier;
    WDMAUD_DEVICE_INFO DeviceInfo;
    MMDEVICE_TYPE DeviceType;

    Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    if (Instance->Handle != NULL)
    {
        /* device is already open */
        return MMSYSERR_NOERROR;
    }

    Result = GetSoundDeviceType(SoundDevice, &DeviceType);

    SND_ASSERT( Result == MMSYSERR_NOERROR );

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.DeviceType = DeviceType;
    DeviceInfo.DeviceIndex = DeviceId;
    DeviceInfo.u.WaveFormatEx.cbSize = sizeof(WAVEFORMATEX); //WaveFormat->cbSize;
    DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
#ifdef USERMODE_MIXER
    DeviceInfo.u.WaveFormatEx.nChannels = 2;
    DeviceInfo.u.WaveFormatEx.nSamplesPerSec = 44100;
    DeviceInfo.u.WaveFormatEx.nBlockAlign = 4;
    DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = 176400;
    DeviceInfo.u.WaveFormatEx.wBitsPerSample = 16;
#else
    DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
    DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
    DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
    DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
    DeviceInfo.u.WaveFormatEx.wBitsPerSample = (DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec * 8) / (DeviceInfo.u.WaveFormatEx.nSamplesPerSec * DeviceInfo.u.WaveFormatEx.nChannels);
#endif

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_OPEN_WDMAUD,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }

    if (WaveFormatSize >= sizeof(WAVEFORMAT))
    {
        /* Store format */
        Instance->WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
        Instance->WaveFormatEx.nChannels = WaveFormat->nChannels;
        Instance->WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
        Instance->WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
        Instance->WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
    }

    /* store details */
    Instance->WaveFormatEx.cbSize = sizeof(WAVEFORMATEX);
    Instance->WaveFormatEx.wBitsPerSample = (DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec * 8) / (DeviceInfo.u.WaveFormatEx.nSamplesPerSec * DeviceInfo.u.WaveFormatEx.nChannels);

    /* Store sound device handle instance handle */
    Instance->Handle = (PVOID)DeviceInfo.hDevice;

    /* Now determine framing requirements */
    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_GETFRAMESIZE,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if ( MMSUCCESS(Result) )
    {
        if (DeviceInfo.u.FrameSize)
        {
            Instance->FrameSize = DeviceInfo.u.FrameSize * 2;
            Instance->BufferCount = WaveFormat->nAvgBytesPerSec / Instance->FrameSize;
            SND_TRACE(L"FrameSize %u BufferCount %u\n", Instance->FrameSize, Instance->BufferCount);
        }
    }
    else
    {
        // use a default of 100 buffers
        Instance->BufferCount = 100;
    }

    /* Now acquire resources */
    DeviceInfo.u.State = KSSTATE_ACQUIRE;
    SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL);

    /* pause the pin */
    DeviceInfo.u.State = KSSTATE_PAUSE;
    SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL);

    /* start the pin */
    DeviceInfo.u.State = KSSTATE_RUN;
    SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_SETDEVICE_STATE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL);


    return MMSYSERR_NOERROR;
}
Esempio n. 19
0
MMRESULT
WdmAudGetDeviceInterfaceStringByLegacy(
    IN  MMDEVICE_TYPE DeviceType,
    IN  DWORD DeviceId,
    IN  LPWSTR Interface,
    IN  DWORD  InterfaceLength,
    OUT  DWORD * InterfaceSize)
{
    WDMAUD_DEVICE_INFO DeviceInfo;
    MMRESULT Result;

    ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
    DeviceInfo.DeviceType = DeviceType;
    DeviceInfo.DeviceIndex = DeviceId;


    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_QUERYDEVICEINTERFACESTRING,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);


    if ( ! MMSUCCESS(Result) )
    {
        return TranslateInternalMmResult(Result);
    }


    if (!Interface)
    {
        SND_ASSERT(InterfaceSize);

        *InterfaceSize = DeviceInfo.u.Interface.DeviceInterfaceStringSize;
        return MMSYSERR_NOERROR;
    }

    if (InterfaceLength < DeviceInfo.u.Interface.DeviceInterfaceStringSize)
    {
        /* buffer is too small */
        return MMSYSERR_MOREDATA;
    }

    DeviceInfo.u.Interface.DeviceInterfaceStringSize = InterfaceLength;
    DeviceInfo.u.Interface.DeviceInterfaceString = Interface;

    Result = SyncOverlappedDeviceIoControl(KernelHandle,
                                           IOCTL_QUERYDEVICEINTERFACESTRING,
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           (LPVOID) &DeviceInfo,
                                           sizeof(WDMAUD_DEVICE_INFO),
                                           NULL);

    if (  MMSUCCESS(Result) && InterfaceLength > 2)
    {
        Interface[1] = L'\\';
        Interface[InterfaceLength-1] = L'\0';
    }

    return Result;
}
Esempio n. 20
0
HRESULT
WINAPI
IDirectSoundCaptureBufferImpl_GetCurrentPosition(
    LPDIRECTSOUNDCAPTUREBUFFER8 iface,
    LPDWORD lpdwCapturePosition,
    LPDWORD lpdwReadPosition)
{
    KSAUDIO_POSITION Position;
    KSPROPERTY Request;
    DWORD Result;
    DWORD Value;

    LPCDirectSoundCaptureBufferImpl This = (LPCDirectSoundCaptureBufferImpl)CONTAINING_RECORD(iface, CDirectSoundCaptureBufferImpl, lpVtbl);

    if (!This->hPin)
    {
        if (lpdwCapturePosition)
            *lpdwCapturePosition = 0;

        if (lpdwReadPosition)
            *lpdwReadPosition = 0;

        DPRINT("No Audio Pin\n");
        return DS_OK;
    }

    if (This->bMix)
    {
        /* read current position */
        Value = InterlockedCompareExchange(&This->CurrentMixPosition, 0, 0);

        if (lpdwCapturePosition)
            *lpdwCapturePosition = (DWORD)Value;

        if (lpdwReadPosition)
            *lpdwReadPosition = (DWORD)Value;

        return DS_OK;
    }

    /* setup audio position property request */
    Request.Id = KSPROPERTY_AUDIO_POSITION;
    Request.Set = KSPROPSETID_Audio;
    Request.Flags = KSPROPERTY_TYPE_GET;


    Result = SyncOverlappedDeviceIoControl(This->hPin, IOCTL_KS_PROPERTY, (PVOID)&Request, sizeof(KSPROPERTY), (PVOID)&Position, sizeof(KSAUDIO_POSITION), NULL);

    if (Result != ERROR_SUCCESS)
    {
        DPRINT("GetPosition failed with %x\n", Result);
        return DSERR_UNSUPPORTED;
    }

    //DPRINT("Play %I64u Write %I64u \n", Position.PlayOffset, Position.WriteOffset);

    if (lpdwCapturePosition)
        *lpdwCapturePosition = (DWORD)Position.PlayOffset;

    if (lpdwReadPosition)
        *lpdwReadPosition = (DWORD)Position.WriteOffset;

    return DS_OK;
}