mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-30 19:26:05 +00:00
implement GetDeviceCapabilities GetDeviceCount modMessage implement GetDeviceCapabilities svn path=/trunk/; revision=19381
337 lines
9.8 KiB
C
337 lines
9.8 KiB
C
/*
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Multimedia
|
|
* FILE: lib/mmdrv/wave.c
|
|
* PURPOSE: Multimedia User Mode Driver
|
|
* PROGRAMMER: Andrew Greenwood
|
|
* Aleksey Bragin (aleksey at studiocerebral.com)
|
|
* UPDATE HISTORY:
|
|
* Jan 30, 2004: Imported into ReactOS tree (Greenwood)
|
|
* Mar 16, 2004: Implemented some funcs (Bragin)
|
|
*/
|
|
|
|
#include "mmdrv.h"
|
|
#include "wave.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* ============================
|
|
* INTERNAL
|
|
* functions start here
|
|
* ============================
|
|
*/
|
|
|
|
MMRESULT GetDeviceCapabilities(DWORD ID, UINT DeviceType,
|
|
LPBYTE pCaps, DWORD Size)
|
|
{
|
|
HANDLE DeviceHandle = NULL;
|
|
MMRESULT Result = MMSYSERR_NOERROR;
|
|
DWORD BytesReturned = 0;
|
|
|
|
// Open the wave device
|
|
|
|
Result = OpenDevice(DeviceType, ID, &DeviceHandle, GENERIC_READ);
|
|
if (Result != MMSYSERR_NOERROR)
|
|
return Result;
|
|
|
|
//
|
|
// Set our data.
|
|
//
|
|
// Setting the overlapped parameter (last) to null means we
|
|
// wait until the operation completes.
|
|
//
|
|
|
|
|
|
if (DeviceType == WaveOutDevice)
|
|
{
|
|
Result = DeviceIoControl(DeviceHandle, IOCTL_WAVE_GET_CAPABILITIES,
|
|
NULL, 0, (LPVOID)pCaps, Size,
|
|
&BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
|
|
}
|
|
|
|
else if (DeviceType == MidiOutDevice)
|
|
{
|
|
Result = DeviceIoControl(DeviceHandle, IOCTL_MIDI_GET_CAPABILITIES,
|
|
NULL, 0, (LPVOID)pCaps, Size,
|
|
&BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
|
|
}
|
|
|
|
else if (DeviceType == AuxDevice)
|
|
{
|
|
Result = DeviceIoControl(DeviceHandle, IOCTL_AUX_GET_CAPABILITIES,
|
|
NULL, 0, (LPVOID)pCaps, Size,
|
|
&BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close the handle and return the result code
|
|
// CloseHandle(DeviceHandle);
|
|
|
|
return Result;
|
|
}
|
|
|
|
static MMRESULT OpenWaveDevice(UINT DeviceType,
|
|
DWORD id,
|
|
DWORD dwUser,
|
|
DWORD dwParam1,
|
|
DWORD dwParam2)
|
|
{
|
|
// TODO: Implement
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//FIXME: Params are MS-specific
|
|
static MMRESULT ThreadCallWaveDevice(WAVETHREADFUNCTION Function, PWAVEALLOC pClient)
|
|
{
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//FIXME: Params are MS-specific
|
|
static void CallbackWaveDevice(PWAVEALLOC pWave, DWORD msg, DWORD dw1)
|
|
{
|
|
}
|
|
|
|
//FIXME: Params are MS-specific
|
|
static MMRESULT WriteWaveDevice(LPWAVEHDR pHdr, PWAVEALLOC pClient)
|
|
{
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//FIXME: MS-specific code, except for name of the func!
|
|
MMRESULT GetPositionWaveDevice(PWAVEALLOC pClient, LPMMTIME lpmmt, DWORD dwSize)
|
|
{
|
|
/*
|
|
WAVE_DD_POSITION PositionData;
|
|
MMRESULT mErr;
|
|
|
|
if (dwSize < sizeof(MMTIME))
|
|
return MMSYSERR_ERROR;
|
|
|
|
//
|
|
// Get the current position from the driver
|
|
//
|
|
mErr = sndGetHandleData(pClient->hDev,
|
|
sizeof(PositionData),
|
|
&PositionData,
|
|
IOCTL_WAVE_GET_POSITION,
|
|
pClient->Event);
|
|
|
|
if (mErr == MMSYSERR_NOERROR) {
|
|
if (lpmmt->wType == TIME_BYTES) {
|
|
lpmmt->u.cb = PositionData.ByteCount;
|
|
}
|
|
|
|
// default is samples.
|
|
else {
|
|
lpmmt->wType = TIME_SAMPLES;
|
|
lpmmt->u.sample = PositionData.SampleCount;
|
|
}
|
|
}
|
|
|
|
return mErr;*/ return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//FIXME: Params are MS-specific
|
|
MMRESULT soundSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
|
|
ULONG Ioctl)
|
|
{
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//FIXME: Params are MS-specific
|
|
MMRESULT soundGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
|
|
ULONG Ioctl)
|
|
{
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
|
|
/* ============================
|
|
* EXPORT
|
|
* functions start here
|
|
* ============================
|
|
*/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
APIENTRY DWORD wodMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
|
|
{
|
|
switch (dwMessage) {
|
|
case WODM_GETNUMDEVS:
|
|
DPRINT("WODM_GETNUMDEVS");
|
|
return GetDeviceCount(WaveOutDevice);
|
|
|
|
case WODM_GETDEVCAPS:
|
|
DPRINT("WODM_GETDEVCAPS");
|
|
return GetDeviceCapabilities(dwId, WaveOutDevice, (LPBYTE)dwParam1,
|
|
(DWORD)dwParam2);
|
|
|
|
case WODM_OPEN:
|
|
DPRINT("WODM_OPEN");
|
|
return OpenWaveDevice(WaveOutDevice, dwId, dwUser, dwParam1, dwParam2);
|
|
|
|
case WODM_CLOSE:
|
|
{
|
|
MMRESULT Result;
|
|
PWAVEALLOC pTask = (PWAVEALLOC)dwUser;
|
|
DPRINT("WODM_CLOSE");
|
|
|
|
// 1. Check if the task is ready to complete
|
|
Result = ThreadCallWaveDevice(WaveThreadClose, pTask);
|
|
if (Result != MMSYSERR_NOERROR) {
|
|
return Result;
|
|
}
|
|
else
|
|
CallbackWaveDevice(pTask, WOM_CLOSE, 0L);
|
|
|
|
// 2. Close the device
|
|
if (pTask->hDev != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(pTask->hDev);
|
|
|
|
EnterCriticalSection(&CS);
|
|
pTask->hDev = INVALID_HANDLE_VALUE;
|
|
LeaveCriticalSection(&CS);
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
};
|
|
|
|
case WODM_WRITE:
|
|
{
|
|
LPWAVEHDR pWaveHdr = (LPWAVEHDR)dwParam1;
|
|
|
|
DPRINT("WODM_WRITE");
|
|
|
|
if (dwParam1 != 0)
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
if ((pWaveHdr->dwFlags & ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)))
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
pWaveHdr->dwFlags &= (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP);
|
|
|
|
if ((pWaveHdr->dwFlags & WHDR_PREPARED) == 0)
|
|
return MMSYSERR_INVALPARAM;
|
|
|
|
// Check, if the wave header is already prepared
|
|
if (!(pWaveHdr->dwFlags & WHDR_PREPARED))
|
|
return WAVERR_UNPREPARED;
|
|
|
|
// If it's already located in the queue, this op is impossible
|
|
if (pWaveHdr->dwFlags & WHDR_INQUEUE )
|
|
return ( WAVERR_STILLPLAYING );
|
|
|
|
// save WAVEALLOC pointer in the WaveHeader
|
|
pWaveHdr->reserved = dwUser;
|
|
|
|
return WriteWaveDevice(pWaveHdr, (PWAVEALLOC)dwUser);
|
|
}
|
|
|
|
|
|
case WODM_PAUSE:
|
|
DPRINT("WODM_PAUSE");
|
|
((PWAVEALLOC)dwUser)->AuxParam.State = WAVE_DD_STOP;
|
|
return ThreadCallWaveDevice(WaveThreadSetState, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_RESTART:
|
|
DPRINT("WODM_RESTART");
|
|
((PWAVEALLOC)dwUser)->AuxParam.State = WAVE_DD_PLAY;
|
|
return ThreadCallWaveDevice(WaveThreadSetState, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_RESET:
|
|
DPRINT("WODM_RESET");
|
|
((PWAVEALLOC)dwUser)->AuxParam.State = WAVE_DD_RESET;
|
|
return ThreadCallWaveDevice(WaveThreadSetState, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_BREAKLOOP:
|
|
DPRINT("WODM_BREAKLOOP");
|
|
return ThreadCallWaveDevice(WaveThreadBreakLoop, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_GETPOS:
|
|
DPRINT("WODM_GETPOS");
|
|
return GetPositionWaveDevice(((PWAVEALLOC)dwUser), (LPMMTIME)dwParam1, dwParam2);
|
|
|
|
case WODM_SETPITCH:
|
|
DPRINT("WODM_SETPITCH");
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.DataLen = sizeof(DWORD);
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PITCH;
|
|
return ThreadCallWaveDevice(WaveThreadSetData, ((PWAVEALLOC)dwUser));
|
|
|
|
case WODM_SETVOLUME:
|
|
DPRINT("WODM_SETVOLUME");
|
|
{
|
|
WAVE_DD_VOLUME Vol;
|
|
Vol.Left = LOWORD(dwParam1) << 16;
|
|
Vol.Right = HIWORD(dwParam1) << 16;
|
|
|
|
return soundSetData(WaveOutDevice, dwId, sizeof(Vol),
|
|
(PBYTE)&Vol, IOCTL_WAVE_SET_VOLUME);
|
|
}
|
|
|
|
case WODM_SETPLAYBACKRATE:
|
|
DPRINT("WODM_SETPLAYBACKRATE");
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.DataLen = sizeof(DWORD);
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PLAYBACK_RATE;
|
|
return ThreadCallWaveDevice(WaveThreadSetData, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_GETPITCH:
|
|
DPRINT("WODM_GETPITCH");
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.DataLen = sizeof(DWORD);
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PITCH;
|
|
return ThreadCallWaveDevice(WaveThreadGetData, (PWAVEALLOC)dwUser);
|
|
|
|
case WODM_GETVOLUME:
|
|
DPRINT("WODM_GETVOLUME");
|
|
{
|
|
WAVE_DD_VOLUME Vol = {};
|
|
DWORD res;
|
|
|
|
res = soundGetData(WaveOutDevice, dwId, sizeof(Vol),
|
|
(PBYTE)&Vol, IOCTL_WAVE_GET_VOLUME);
|
|
|
|
if (res == MMSYSERR_NOERROR)
|
|
*(LPDWORD)dwParam1 = (DWORD)MAKELONG(HIWORD(Vol.Left), HIWORD(Vol.Right));
|
|
|
|
return res;
|
|
}
|
|
|
|
case WODM_GETPLAYBACKRATE:
|
|
DPRINT("WODM_GETPLAYBACKRATE");
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.DataLen = sizeof(DWORD);
|
|
((PWAVEALLOC)dwUser)->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PLAYBACK_RATE;
|
|
return ThreadCallWaveDevice(WaveThreadGetData, (PWAVEALLOC)dwUser);
|
|
|
|
default:
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
// This point of execution should never be reached
|
|
return MMSYSERR_NOTSUPPORTED;
|
|
}
|
|
|
|
|
|
/*
|
|
* @unimplemented
|
|
*/
|
|
APIENTRY DWORD widMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
|
|
{
|
|
DPRINT("widMessage\n");
|
|
|
|
switch (dwMessage) {
|
|
case WIDM_GETNUMDEVS:
|
|
return GetDeviceCount(WaveInDevice);
|
|
default :
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
}
|
|
|