mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
9046cc97ee
Implement volume level changing for Aux/MidiOut/WaveOut devices. It's represented the following WINMM functions: - auxGetVolume, - auxSetVolume, - midiOutGetVolume, - midiOutSetVolume, - waveOutGetVolume, - waveOutSetVolume, which are calling the followind messages appropriately: - AUXDM_GETVOLUME, - AUXDM_SETVOLUME, - MODM_GETVOLUME, - MODM_SETVOLUME, - WODM_GETVOLUME, - WODM_SETVOLUME. This fixes volume control for several 3rd-party programs (like Fox Audio Player 0.10.2 from Rapps, Winamp 2.95 with WaveOut plugin). However it does not fix changing the volume in system volume mixers (SndVol32, MMSys), since they are using their own functionality instead. They technically do the same things, but apart from the functions mentioned above. CORE-14780
978 lines
32 KiB
C
978 lines
32 KiB
C
/*
|
|
* PROJECT: ReactOS Sound System
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: dll/win32/wdmaud.drv/wdmaud.c
|
|
*
|
|
* PURPOSE: WDM Audio Driver (User-mode part)
|
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
|
Johannes Anderwald
|
|
*
|
|
* NOTES: Looking for wodMessage & co? You won't find them here. Try
|
|
* the MME Buddy library, which is where these routines are
|
|
* actually implemented.
|
|
*
|
|
*/
|
|
|
|
#include "wdmaud.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
#include <mmebuddy_debug.h>
|
|
|
|
#define KERNEL_DEVICE_NAME L"\\\\.\\wdmaud"
|
|
|
|
HANDLE KernelHandle = INVALID_HANDLE_VALUE;
|
|
DWORD OpenCount = 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;
|
|
}
|
|
|
|
MMRESULT
|
|
WdmAudCleanupByLegacy()
|
|
{
|
|
if (KernelHandle != INVALID_HANDLE_VALUE)
|
|
{
|
|
CloseHandle(KernelHandle);
|
|
KernelHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
MMRESULT
|
|
WdmAudOpenSoundDeviceByLegacy(
|
|
IN PSOUND_DEVICE SoundDevice,
|
|
OUT PVOID *Handle)
|
|
{
|
|
HDEVINFO hDevInfo;
|
|
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
|
|
GUID SWBusGuid = {STATIC_KSCATEGORY_WDMAUD};
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData;
|
|
|
|
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
|
{
|
|
hDevInfo = SetupDiGetClassDevsW(&SWBusGuid, NULL, NULL, DIGCF_DEVICEINTERFACE| DIGCF_PRESENT);
|
|
if (!hDevInfo)
|
|
{
|
|
// failed
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
|
|
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &SWBusGuid, 0, &DeviceInterfaceData))
|
|
{
|
|
// failed
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
|
|
DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W));
|
|
if (!DeviceInterfaceDetailData)
|
|
{
|
|
// failed
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
|
|
DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
|
if (!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &DeviceInterfaceData, DeviceInterfaceDetailData,MAX_PATH * sizeof(WCHAR) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W), NULL, NULL))
|
|
{
|
|
// failed
|
|
HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
return MMSYSERR_ERROR;
|
|
}
|
|
SND_TRACE(L"Opening wdmaud device '%s'\n",DeviceInterfaceDetailData->DevicePath);
|
|
KernelHandle = CreateFileW(DeviceInterfaceDetailData->DevicePath,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_OVERLAPPED,
|
|
NULL);
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceInterfaceDetailData);
|
|
SetupDiDestroyDeviceInfoList(hDevInfo);
|
|
}
|
|
|
|
|
|
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
|
return MMSYSERR_ERROR;
|
|
|
|
++ OpenCount;
|
|
return MMSYSERR_NOERROR;
|
|
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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 = 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 = WaveFormat->cbSize;
|
|
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;
|
|
}
|
|
|
|
VOID
|
|
CALLBACK
|
|
LegacyCompletionRoutine(
|
|
IN DWORD dwErrorCode,
|
|
IN DWORD dwNumberOfBytesTransferred,
|
|
IN LPOVERLAPPED lpOverlapped)
|
|
{
|
|
PSOUND_OVERLAPPED Overlap;
|
|
PWDMAUD_DEVICE_INFO DeviceInfo;
|
|
|
|
Overlap = (PSOUND_OVERLAPPED)lpOverlapped;
|
|
DeviceInfo = (PWDMAUD_DEVICE_INFO)Overlap->CompletionContext;
|
|
|
|
/* Call mmebuddy overlap routine */
|
|
Overlap->OriginalCompletionRoutine(dwErrorCode, DeviceInfo->Header.DataUsed, lpOverlapped);
|
|
|
|
HeapFree(GetProcessHeap(), 0, DeviceInfo);
|
|
}
|
|
|
|
MMRESULT
|
|
WdmAudCommitWaveBufferByLegacy(
|
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
|
IN PVOID OffsetPtr,
|
|
IN DWORD Length,
|
|
IN PSOUND_OVERLAPPED Overlap,
|
|
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
|
|
{
|
|
HANDLE Handle;
|
|
MMRESULT Result;
|
|
PWDMAUD_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);
|
|
SND_ASSERT(Handle);
|
|
|
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
|
|
|
if ( ! MMSUCCESS(Result) )
|
|
{
|
|
return TranslateInternalMmResult(Result);
|
|
}
|
|
|
|
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
|
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
|
|
|
DeviceInfo = (PWDMAUD_DEVICE_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WDMAUD_DEVICE_INFO));
|
|
if (!DeviceInfo)
|
|
{
|
|
// no memory
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
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;
|
|
|
|
|
|
// create completion event
|
|
Overlap->Standard.hEvent = Handle = CreateEventW(NULL, FALSE, FALSE, NULL);
|
|
if (Overlap->Standard.hEvent == NULL)
|
|
{
|
|
// no memory
|
|
HeapFree(GetProcessHeap(), 0, DeviceInfo);
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
Overlap->OriginalCompletionRoutine = CompletionRoutine;
|
|
Overlap->CompletionContext = (PVOID)DeviceInfo;
|
|
|
|
if (DeviceType == WAVE_OUT_DEVICE_TYPE)
|
|
{
|
|
Ret = WriteFileEx(KernelHandle, DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, LegacyCompletionRoutine);
|
|
if (Ret)
|
|
WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
|
|
}
|
|
else if (DeviceType == WAVE_IN_DEVICE_TYPE)
|
|
{
|
|
Ret = ReadFileEx(KernelHandle, DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPOVERLAPPED)Overlap, LegacyCompletionRoutine);
|
|
if (Ret)
|
|
WaitForSingleObjectEx (KernelHandle, INFINITE, TRUE);
|
|
}
|
|
|
|
// close event handle
|
|
CloseHandle(Handle);
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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_GETPOS,
|
|
(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;
|
|
}
|
|
|
|
MMRESULT
|
|
WdmAudGetVolumeByLegacy(
|
|
_In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
|
_In_ DWORD DeviceId,
|
|
_Out_ PDWORD pdwVolume)
|
|
{
|
|
/* FIXME */
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
MMRESULT
|
|
WdmAudSetVolumeByLegacy(
|
|
_In_ PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
|
_In_ DWORD DeviceId,
|
|
_In_ DWORD dwVolume)
|
|
{
|
|
/* FIXME */
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|