/*
+ * PROJECT: ReactOS Sound System
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: dll/win32/wdmaud.drv/wdmaud.c
*
- * PROJECT: ReactOS WDM Audio driver mapper
- * FILE: dll/win32/wdmaud.drv/wdmaud.c
- * PURPOSE: wdmaud.drv
- * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
+ * PURPOSE: WDM Audio Driver (User-mode part)
+ * PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
+ *
+ * NOTES: Looking for wodMessage & co? You won't find them here. Try
+ * the MME Buddy library, which is where these routines are
+ * actually implemented.
*
- * UPDATE HISTORY:
- * 25/05/2008 Created
*/
-#include <stdarg.h>
-
#include <windows.h>
-#include <mmsystem.h>
+#include <ntddsnd.h>
+#include <sndtypes.h>
#include <mmddk.h>
-#include <mmreg.h>
-#include <debug.h>
+#include <mmebuddy.h>
+
+#include <ks.h>
+#include <ksmedia.h>
+#include "interface.h"
+
+#define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
+
+PWSTR UnknownWaveIn = L"Wave Input";
+PWSTR UnknownWaveOut = L"Wave Output";
+PWSTR UnknownMidiIn = L"Midi Input";
+PWSTR UnknownMidiOut = L"Midi Output";
+
+HANDLE KernelHandle = INVALID_HANDLE_VALUE;
+DWORD OpenCount = 0;
+
+MMRESULT
+WriteFileEx_Remixer(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID OffsetPtr,
+ IN DWORD Length,
+ IN PSOUND_OVERLAPPED Overlap,
+ IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
+
-DWORD APIENTRY
-mxdMessage(UINT uDevice,
- UINT uMsg,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
+
+MMRESULT
+GetNumWdmDevs(
+ IN HANDLE Handle,
+ IN MMDEVICE_TYPE DeviceType,
+ OUT DWORD* DeviceCount)
{
- DPRINT1("mxdMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
+ MMRESULT Result;
+ WDMAUD_DEVICE_INFO DeviceInfo;
+
+ VALIDATE_MMSYS_PARAMETER( Handle != 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(Handle,
+ IOCTL_GETNUMDEVS_TYPE,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
- switch (uMsg)
+ if ( ! MMSUCCESS( Result ) )
{
- case MXDM_INIT:
- break;
+ SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n");
+ *DeviceCount = 0;
+ return TranslateInternalMmResult(Result);
+ }
- case MXDM_GETNUMDEVS:
- break;
+ *DeviceCount = DeviceInfo.DeviceCount;
- case MXDM_GETDEVCAPS:
- break;
+ return MMSYSERR_NOERROR;
+}
- case MXDM_OPEN:
- break;
+MMRESULT
+GetWdmDeviceCapabilities(
+ IN PSOUND_DEVICE SoundDevice,
+ IN DWORD DeviceId,
+ OUT PVOID Capabilities,
+ IN DWORD CapabilitiesSize)
+{
+ /* NOTE - At this time, WDMAUD does not support this properly */
- case MXDM_CLOSE:
- break;
+ MMRESULT Result;
+ MMDEVICE_TYPE DeviceType;
+ WDMAUD_DEVICE_INFO DeviceInfo;
- case MXDM_GETLINEINFO:
- break;
+ SND_ASSERT( SoundDevice );
+ SND_ASSERT( Capabilities );
- case MXDM_GETLINECONTROLS:
- break;
+ 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;
- case MXDM_GETCONTROLDETAILS:
- break;
+ Result = SyncOverlappedDeviceIoControl(KernelHandle,
+ IOCTL_GETCAPABILITIES,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
- case MXDM_SETCONTROLDETAILS:
- break;
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
}
- return MMSYSERR_NOTSUPPORTED;
+ /* This is pretty much a big hack right now */
+ switch ( DeviceType )
+ {
+ case MIXER_DEVICE_TYPE:
+ {
+ LPMIXERCAPS MixerCaps = (LPMIXERCAPS) 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 :
+ {
+ LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
+
+ DeviceInfo.u.WaveOutCaps.szPname[MAXPNAMELEN-1] = L'\0';
+ WaveOutCaps->wMid = DeviceInfo.u.WaveOutCaps.wMid;
+ WaveOutCaps->wPid = DeviceInfo.u.WaveOutCaps.wPid;
+
+ WaveOutCaps->vDriverVersion = 0x0001;
+ 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 = 0x0001;
+ CopyWideString(WaveInCaps->szPname, DeviceInfo.u.WaveInCaps.szPname);
+
+ WaveInCaps->dwFormats = DeviceInfo.u.WaveInCaps.dwFormats;
+ WaveInCaps->wChannels = DeviceInfo.u.WaveInCaps.wChannels;
+ WaveInCaps->wReserved1 = 0;
+ break;
+ }
+ }
+
+ return MMSYSERR_NOERROR;
+}
+
+
+MMRESULT
+OpenWdmSoundDevice(
+ IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
+ OUT PVOID* Handle)
+{
+ /* Only open this if it's not already open */
+ if ( KernelHandle == INVALID_HANDLE_VALUE )
+ {
+ SND_TRACE(L"Opening wdmaud device\n");
+ KernelHandle = CreateFileW(KERNEL_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ }
+
+ if ( KernelHandle == INVALID_HANDLE_VALUE )
+ return MMSYSERR_ERROR;
+
+ SND_ASSERT( Handle );
+
+ *Handle = KernelHandle;
+ ++ OpenCount;
+
+ return MMSYSERR_NOERROR;
}
-DWORD APIENTRY
-auxMessage(UINT uDevice,
- UINT uMsg,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
+MMRESULT
+CloseWdmSoundDevice(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN PVOID Handle)
{
- DPRINT1("auxMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
+ WDMAUD_DEVICE_INFO DeviceInfo;
+ MMRESULT Result;
+ MMDEVICE_TYPE DeviceType;
+ PSOUND_DEVICE SoundDevice;
- switch (uMsg)
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
+
+ if ( ! MMSUCCESS(Result) )
{
- case AUXDM_GETDEVCAPS:
+ return TranslateInternalMmResult(Result);
+ }
- break;
+ if ( OpenCount == 0 )
+ {
+ return MMSYSERR_NOERROR;
+ }
- case AUXDM_GETNUMDEVS:
+ SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
- break;
+ Result = GetSoundDeviceType(SoundDevice, &DeviceType);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
- case AUXDM_GETVOLUME:
+ if (SoundDeviceInstance->Handle != (PVOID)KernelHandle)
+ {
+ ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
- break;
+ DeviceInfo.DeviceType = DeviceType;
+ DeviceInfo.hDevice = SoundDeviceInstance->Handle;
- case AUXDM_SETVOLUME:
+ /* First stop the stream */
+ if (DeviceType != MIXER_DEVICE_TYPE)
+ {
+ DeviceInfo.u.State = KSSTATE_STOP;
+ SyncOverlappedDeviceIoControl(KernelHandle,
+ IOCTL_SETDEVICE_STATE,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
+ }
- break;
+ SyncOverlappedDeviceIoControl(KernelHandle,
+ IOCTL_CLOSE_WDMAUD,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
+ }
- default:
- return MMSYSERR_NOTSUPPORTED;
+ if (DeviceType == MIXER_DEVICE_TYPE)
+ {
+ SetEvent(SoundDeviceInstance->hStopEvent);
+ CloseHandle(SoundDeviceInstance->hStopEvent);
+ CloseHandle(SoundDeviceInstance->hNotifyEvent);
}
- return MMSYSERR_NOTSUPPORTED;
+ --OpenCount;
+
+ if ( OpenCount < 1 )
+ {
+ CloseHandle(KernelHandle);
+ KernelHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return MMSYSERR_NOERROR;
}
-DWORD APIENTRY
-wodMessage(UINT uDevice,
- UINT uMsg,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
+
+MMRESULT
+QueryWdmWaveDeviceFormatSupport(
+ IN PSOUND_DEVICE Device,
+ IN PWAVEFORMATEX WaveFormat,
+ IN DWORD WaveFormatSize)
{
- DPRINT1("wodMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
+ /* Whatever... */
+ return MMSYSERR_NOERROR;
+}
+
- switch (uMsg)
+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;
+}
+
+
+MMRESULT
+SetWdmMixerDeviceFormat(
+ IN PSOUND_DEVICE_INSTANCE Instance,
+ IN DWORD DeviceId,
+ IN PWAVEFORMATEX WaveFormat,
+ IN DWORD WaveFormatSize)
+{
+ MMRESULT Result;
+ WDMAUD_DEVICE_INFO DeviceInfo;
+ HANDLE hThread;
+
+ if (Instance->Handle != KernelHandle)
{
- case WODM_GETNUMDEVS:
- break;
+ /* device is already open */
+ return MMSYSERR_NOERROR;
+ }
+
+ Instance->hNotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
+ if ( ! Instance->hNotifyEvent )
+ return MMSYSERR_NOMEM;
+
+ 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);
+ }
- case WODM_GETDEVCAPS:
- break;
+ 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;
+}
+
+MMRESULT
+SetWdmWaveDeviceFormat(
+ 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;
- case WODM_OPEN:
- break;
+ Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
- case WODM_CLOSE:
- break;
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
+ }
- case WODM_WRITE:
- break;
+ Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
- case WODM_PAUSE:
- break;
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
+ }
- case WODM_RESTART:
- break;
+ if (Instance->Handle != KernelHandle)
+ {
+ /* device is already open */
+ return MMSYSERR_NOERROR;
+ }
- case WODM_RESET:
- break;
- case WODM_BREAKLOOP:
- break;
+ Result = GetSoundDeviceType(SoundDevice, &DeviceType);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
- case WODM_GETPOS:
- break;
+ 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 = WaveFormat->wBitsPerSample;
+#endif
- case WODM_SETPITCH:
- break;
+ Result = SyncOverlappedDeviceIoControl(KernelHandle,
+ IOCTL_OPEN_WDMAUD,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
- case WODM_SETVOLUME:
- break;
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
+ }
- case WODM_SETPLAYBACKRATE:
- break;
+ /* Store format */
+ Instance->WaveFormatEx.cbSize = WaveFormat->cbSize;
+ 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;
+ Instance->WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
- case WODM_GETPITCH:
- break;
+ /* Store sound device handle instance handle */
+ Instance->Handle = (PVOID)DeviceInfo.hDevice;
- case WODM_GETVOLUME:
- break;
+ /* Now determine framing requirements */
+ Result = SyncOverlappedDeviceIoControl(KernelHandle,
+ IOCTL_GETFRAMESIZE,
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ (LPVOID) &DeviceInfo,
+ sizeof(WDMAUD_DEVICE_INFO),
+ NULL);
- case WODM_GETPLAYBACKRATE:
- break;
+ 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;
+ }
- default:
- return MMSYSERR_NOTSUPPORTED;
+ if (DeviceType == WAVE_OUT_DEVICE_TYPE)
+ {
+ /* Now start the stream */
+ 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_NOTSUPPORTED;
+ return MMSYSERR_NOERROR;
}
-DWORD APIENTRY
-widMessage(UINT uDevice,
- UINT uMsg,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
+MMRESULT
+WriteFileEx_Committer2(
+ IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
+ IN PVOID OffsetPtr,
+ IN DWORD Length,
+ IN PSOUND_OVERLAPPED Overlap,
+ IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
{
- DPRINT1("widMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
+ HANDLE Handle;
+ MMRESULT Result;
+ WDMAUD_DEVICE_INFO DeviceInfo;
+ PSOUND_DEVICE SoundDevice;
+ MMDEVICE_TYPE DeviceType;
+ BOOL Ret;
+
+ VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
+ VALIDATE_MMSYS_PARAMETER( OffsetPtr );
+ VALIDATE_MMSYS_PARAMETER( Overlap );
+ VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
+
+ GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
- switch (uMsg)
+
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
+
+ if ( ! MMSUCCESS(Result) )
{
- case WIDM_GETNUMDEVS:
- break;
+ return TranslateInternalMmResult(Result);
+ }
- case WIDM_GETDEVCAPS:
- break;
+ Result = GetSoundDeviceType(SoundDevice, &DeviceType);
+ SND_ASSERT( Result == MMSYSERR_NOERROR );
- case WIDM_OPEN:
- break;
+ SND_ASSERT(Handle);
- case WIDM_CLOSE:
- break;
+ ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
- case WIDM_ADDBUFFER:
- break;
+ DeviceInfo.Header.FrameExtent = Length;
+ if (DeviceType == WAVE_OUT_DEVICE_TYPE)
+ {
+ DeviceInfo.Header.DataUsed = Length;
+ }
+ DeviceInfo.Header.Data = OffsetPtr;
+ DeviceInfo.Header.Size = sizeof(WDMAUD_DEVICE_INFO);
+ DeviceInfo.Header.PresentationTime.Numerator = 1;
+ DeviceInfo.Header.PresentationTime.Denominator = 1;
+ DeviceInfo.hDevice = Handle;
+ DeviceInfo.DeviceType = DeviceType;
- case WIDM_STOP:
- break;
+ Overlap->Standard.hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
- case WIDM_START:
- break;
+ if (DeviceType == WAVE_OUT_DEVICE_TYPE)
+ {
+ Ret = WriteFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
+ if (Ret)
+ WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
+ }
+ else if (DeviceType == WAVE_IN_DEVICE_TYPE)
+ {
+ Ret = ReadFileEx(KernelHandle, &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, CompletionRoutine);
+ //if (Ret)
+ // WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
+ }
+
+ return MMSYSERR_NOERROR;
+}
- case WIDM_RESET:
- break;
+MMRESULT
+SetWdmWaveState(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN BOOL bStart)
+{
+ MMRESULT Result;
+ PSOUND_DEVICE SoundDevice;
+ WDMAUD_DEVICE_INFO DeviceInfo;
+ MMDEVICE_TYPE DeviceType;
+ HANDLE Handle;
- case WIDM_GETPOS:
- break;
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
- default:
- return MMSYSERR_NOTSUPPORTED;
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
}
- return MMSYSERR_NOTSUPPORTED;
+ 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;
+}
+
+MMRESULT
+GetDeviceInterfaceString(
+ 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;
}
-DWORD APIENTRY
-modMessage(UINT uDevice,
- UINT uMsg,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
+MMRESULT
+GetWdmPosition(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN MMTIME* Time)
{
- DPRINT1("modMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
+ MMRESULT Result;
+ PSOUND_DEVICE SoundDevice;
+ WDMAUD_DEVICE_INFO DeviceInfo;
+ MMDEVICE_TYPE DeviceType;
+ HANDLE Handle;
+
+ Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
+
+ if ( ! MMSUCCESS(Result) )
+ {
+ return TranslateInternalMmResult(Result);
+ }
- return MMSYSERR_NOTSUPPORTED;
+ 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;
}
-LRESULT APIENTRY
-DriverProc(DWORD dwDriverID,
- HDRVR hDriver,
- UINT uiMessage,
- LPARAM lParam1,
- LPARAM lParam2)
+MMRESULT
+ResetStream(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN MMDEVICE_TYPE DeviceType,
+ IN BOOLEAN bStartReset)
{
- return DefDriverProc(dwDriverID, hDriver, uiMessage, lParam1, lParam2);
+ 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;
}
-BOOL WINAPI
-DllMain(IN HINSTANCE hinstDLL,
- IN DWORD dwReason,
- IN LPVOID lpvReserved)
+
+MMRESULT
+QueryMixerInfo(
+ IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
+ IN UINT uMsg,
+ IN LPVOID Parameter,
+ IN DWORD Flags)
{
- switch (dwReason)
+ 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.DeviceType = MIXER_DEVICE_TYPE;
+ DeviceInfo.Flags = Flags;
+
+ MixLine = (LPMIXERLINEW)Parameter;
+ MixControls = (LPMIXERLINECONTROLSW)Parameter;
+ MixDetails = (LPMIXERCONTROLDETAILS)Parameter;
+
+ switch(uMsg)
{
- case DLL_PROCESS_ATTACH:
- DisableThreadLibraryCalls(hinstDLL);
+ 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;
}
- return TRUE;
+ 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;
+}
+
+
+MMRESULT
+PopulateWdmDeviceList(
+ HANDLE Handle,
+ MMDEVICE_TYPE DeviceType)
+{
+ MMRESULT Result;
+ DWORD DeviceCount = 0;
+ PSOUND_DEVICE SoundDevice = NULL;
+ MMFUNCTION_TABLE FuncTable;
+ DWORD i;
+
+ VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
+ VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
+
+ Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
+
+ if ( ! MMSUCCESS(Result) )
+ {
+ SND_ERR(L"Error %d while obtaining number of devices\n", Result);
+ return TranslateInternalMmResult(Result);
+ }
+
+ SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
+
+
+ for ( i = 0; i < DeviceCount; ++ i )
+ {
+ Result = ListSoundDevice(DeviceType, UlongToPtr(i), &SoundDevice);
+
+ if ( ! MMSUCCESS(Result) )
+ {
+ SND_ERR(L"Failed to list sound device - error %d\n", Result);
+ return TranslateInternalMmResult(Result);
+ }
+
+ /* Set up our function table */
+ ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
+ FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
+ FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
+ if (DeviceType == MIXER_DEVICE_TYPE)
+ {
+ FuncTable.SetWaveFormat = SetWdmMixerDeviceFormat;
+ FuncTable.QueryMixerInfo = QueryMixerInfo;
+ }
+ else
+ {
+ FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
+ }
+
+ if (DeviceType == WAVE_IN_DEVICE_TYPE || DeviceType == WAVE_OUT_DEVICE_TYPE)
+ {
+ FuncTable.SetState = SetWdmWaveState;
+ FuncTable.ResetStream = ResetStream;
+ }
+
+ FuncTable.Open = OpenWdmSoundDevice;
+ FuncTable.Close = CloseWdmSoundDevice;
+ FuncTable.GetDeviceInterfaceString = GetDeviceInterfaceString;
+#ifndef USERMODE_MIXER
+ FuncTable.CommitWaveBuffer = WriteFileEx_Committer2;
+#else
+ FuncTable.CommitWaveBuffer = WriteFileEx_Remixer;
+#endif
+ FuncTable.GetPos = GetWdmPosition;
+
+ SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
+ }
+
+ return MMSYSERR_NOERROR;
+}
+
+
+
+LONG
+APIENTRY
+DriverProc(
+ DWORD DriverId,
+ HANDLE DriverHandle,
+ UINT Message,
+ LONG Parameter1,
+ LONG Parameter2)
+{
+ MMRESULT Result;
+
+ switch ( Message )
+ {
+ case DRV_LOAD :
+ {
+ HANDLE Handle;
+ SND_TRACE(L"DRV_LOAD\n");
+
+ Result = InitEntrypointMutexes();
+
+ if ( ! MMSUCCESS(Result) )
+ return 0L;
+
+ OpenWdmSoundDevice(NULL, &Handle);
+
+ if ( Handle == INVALID_HANDLE_VALUE )
+ {
+ SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
+ CleanupEntrypointMutexes();
+
+ //UnlistAllSoundDevices();
+
+ return 0L;
+ }
+
+ /* Populate the device lists */
+ SND_TRACE(L"Populating device lists\n");
+ PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
+ PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
+ PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
+ PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
+ PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
+ PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
+
+ SND_TRACE(L"Initialisation complete\n");
+
+ return 1L;
+ }
+
+ case DRV_FREE :
+ {
+ SND_TRACE(L"DRV_FREE\n");
+
+ if ( KernelHandle != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle(KernelHandle);
+ KernelHandle = INVALID_HANDLE_VALUE;
+ }
+
+ /* TODO: Clean up the path names! */
+ UnlistAllSoundDevices();
+
+ CleanupEntrypointMutexes();
+
+ SND_TRACE(L"Unfreed memory blocks: %d\n",
+ GetMemoryAllocationCount());
+
+ return 1L;
+ }
+
+ case DRV_ENABLE :
+ case DRV_DISABLE :
+ {
+ SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
+ return 1L;
+ }
+
+ case DRV_OPEN :
+ case DRV_CLOSE :
+ {
+ SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
+ return 1L;
+ }
+
+ case DRV_QUERYCONFIGURE :
+ {
+ SND_TRACE(L"DRV_QUERYCONFIGURE\n");
+ return 0L;
+ }
+ case DRV_CONFIGURE :
+ return DRVCNF_OK;
+
+ default :
+ SND_TRACE(L"Unhandled message %d\n", Message);
+ return DefDriverProc(DriverId,
+ DriverHandle,
+ Message,
+ Parameter1,
+ Parameter2);
+ }
}
+
+BOOL WINAPI DllMain(
+ HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved)
+{
+ switch ( fdwReason )
+ {
+ case DLL_PROCESS_ATTACH :
+ SND_TRACE(L"WDMAUD.DRV - Process attached\n");
+ break;
+ case DLL_PROCESS_DETACH :
+ SND_TRACE(L"WDMAUD.DRV - Process detached\n");
+ break;
+ case DLL_THREAD_ATTACH :
+ SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
+ break;
+ case DLL_THREAD_DETACH :
+ SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
+ break;
+ }
+
+ return TRUE;
+}