📄 wave.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>
#define WHDR_COMPLETE 0x80000000
#define MAX_BUFFER_SIZE 8192
#define MAX_WAVE_BYTES 5*MAX_BUFFER_SIZE
PWAVEALLOC WaveLists;
static MMRESULT waveReadWrite(PWAVEALLOC pClient);
void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
static MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
/* ============================
* 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;
if ((DeviceType == WaveOutDevice) || (DeviceType == WaveInDevice))
{
Result = DeviceIoControl(DeviceHandle, IOCTL_WAVE_GET_CAPABILITIES,
NULL, 0, (LPVOID)pCaps, Size,
&BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
}
else if ((DeviceType == MidiInDevice) || (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 DWORD waveThread(LPVOID lpParameter)
{
PWAVEALLOC pClient = (PWAVEALLOC)lpParameter;
BOOL Terminate = FALSE;
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
SetEvent(pClient->AuxEvent2);
WaitForSingleObject(pClient->AuxEvent1, INFINITE);
for (;;)
{
switch (pClient->AuxFunction)
{
case WaveThreadAddBuffer:
{
LPWAVEHDR *pHdrSearching;
if (pClient->DeviceType == WaveInDevice)
pClient->AuxParam.pHdr->dwBytesRecorded = 0;
pHdrSearching = &pClient->DeviceQueue;
pClient->AuxParam.pHdr->lpNext = NULL;
while (*pHdrSearching)
{
pHdrSearching = &(*pHdrSearching)->lpNext;
}
if (pClient->NextBuffer == NULL)
{
pClient->BufferPosition = 0;
pClient->NextBuffer = pClient->AuxParam.pHdr;
}
*pHdrSearching = pClient->AuxParam.pHdr;
pClient->AuxReturnCode = waveReadWrite(pClient);
}
break;
case WaveThreadSetState:
pClient->AuxReturnCode = waveSetState(pClient, pClient->AuxParam.State);
if (pClient->AuxParam.State == WAVE_DD_RESET)
{
PWAVEHDR pHdr;
pClient->LoopHead = NULL;
pClient->AuxReturnCode = MMSYSERR_NOERROR;
for (pHdr = pClient->DeviceQueue; pHdr != NULL; pHdr = pHdr->lpNext)
{
pHdr->dwFlags |= WHDR_COMPLETE;
}
pClient->BufferPosition = 0;
pClient->NextBuffer = NULL;
}
else
{
if (pClient->DeviceType == WaveInDevice && pClient->AuxReturnCode == MMSYSERR_NOERROR)
{
if (pClient->AuxParam.State == WAVE_DD_STOP)
{
if (pClient->DeviceQueue)
{
while (!(pClient->DeviceQueue->dwFlags & WHDR_COMPLETE) &&
pClient->BytesOutstanding != 0)
{
waveSetState(pClient, WAVE_DD_RECORD);
pClient->AuxReturnCode = waveSetState(pClient, WAVE_DD_STOP);
if (pClient->AuxReturnCode != MMSYSERR_NOERROR)
break;
}
if (pClient->AuxReturnCode == MMSYSERR_NOERROR)
{
pClient->DeviceQueue->dwFlags |= WHDR_COMPLETE;
if (pClient->NextBuffer == pClient->DeviceQueue)
{
pClient->NextBuffer = pClient->DeviceQueue->lpNext;
pClient->BufferPosition = 0;
}
}
}
}
else
{
if (pClient->AuxParam.State == WAVE_DD_RECORD)
pClient->AuxReturnCode = waveReadWrite(pClient);
}
}
}
break;
case WaveThreadGetData:
{
OVERLAPPED Overlap;
DWORD BytesReturned;
// FIXME
// Assert(hDev != NULL);
memset(&Overlap, 0, sizeof(Overlap));
Overlap.hEvent = pClient->Event;
if (!DeviceIoControl(pClient->hDev, pClient->AuxParam.GetSetData.Function, NULL, 0,
pClient->AuxParam.GetSetData.pData, pClient->AuxParam.GetSetData.DataLen,
&BytesReturned, &Overlap))
{
DWORD cbTransfer;
if (GetLastError() != ERROR_IO_PENDING)
pClient->AuxReturnCode = TranslateStatus();
else
{
if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer, TRUE))
pClient->AuxReturnCode = TranslateStatus();
}
}
else
{
while (SetEvent(pClient->Event) && WaitForSingleObjectEx(pClient->Event, 0, TRUE) ==
WAIT_IO_COMPLETION) {}
pClient->AuxReturnCode = MMSYSERR_NOERROR;
}
}
break;
case WaveThreadSetData:
{
OVERLAPPED Overlap;
DWORD BytesReturned;
memset((PVOID)&Overlap, 0, sizeof(Overlap));
Overlap.hEvent = pClient->Event;
if (!DeviceIoControl(pClient->hDev, pClient->AuxParam.GetSetData.Function,
pClient->AuxParam.GetSetData.pData, pClient->AuxParam.GetSetData.DataLen,
NULL, 0, &BytesReturned, &Overlap))
{
DWORD cbTransfer;
if (GetLastError() == ERROR_IO_PENDING)
{
if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer, TRUE))
pClient->AuxReturnCode = TranslateStatus();
}
else
pClient->AuxReturnCode = TranslateStatus();
}
else
{
while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
pClient->AuxReturnCode = MMSYSERR_NOERROR;
}
}
break;
case WaveThreadBreakLoop:
pClient->AuxReturnCode = MMSYSERR_NOERROR;
if (pClient->LoopHead)
pClient->LoopCount = 0;
break;
case WaveThreadClose:
if (pClient->DeviceQueue != NULL)
pClient->AuxReturnCode = WAVERR_STILLPLAYING;
else
pClient->AuxReturnCode = MMSYSERR_NOERROR;
break;
case WaveThreadTerminate:
Terminate = TRUE;
break;
default:
DPRINT("WaveThread Error");
break;
}
pClient->AuxFunction = WaveThreadInvalid;
while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE))
{
PWAVEHDR pHdr;
PWAVEALLOC pWav;
pHdr = pClient->DeviceQueue;
pClient->DeviceQueue = pHdr->lpNext;
pHdr->dwFlags &= ~WHDR_COMPLETE;
pHdr->dwFlags &= ~WHDR_INQUEUE;
pHdr->lpNext = NULL;
pHdr->dwFlags |= WHDR_DONE;
pWav = (PWAVEALLOC)pHdr->reserved;
if (pWav->dwCallback)
{
DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags), (HDRVR)pWav->hWave,
pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
pWav->dwInstance, (DWORD)pHdr, 0L);
}
}
waveReadWrite(pClient);
if (Terminate) return 1;
SetEvent(pClient->AuxEvent2);
while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) == WAIT_IO_COMPLETION)
{
while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE))
{
PWAVEHDR pHdr;
PWAVEALLOC pWav;
pHdr = pClient->DeviceQueue;
pClient->DeviceQueue = pHdr->lpNext;
pHdr->dwFlags &= ~WHDR_COMPLETE;
pHdr->dwFlags &= ~WHDR_INQUEUE;
pHdr->lpNext = NULL;
pHdr->dwFlags |= WHDR_DONE;
pWav = (PWAVEALLOC)pHdr->reserved;
if (pWav->dwCallback)
{
DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags), (HDRVR)pWav->hWave,
pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
pWav->dwInstance, (DWORD)pHdr, 0L);
}
}
waveReadWrite(pClient);
}
}
return MMSYSERR_NOERROR;
}
static MMRESULT waveReadWrite(PWAVEALLOC pClient)
{
DWORD dwSize;
BOOL Result = FALSE;
while (pClient->NextBuffer)
{
PWAVEHDR pHdr;
pHdr = pClient->NextBuffer;
//FIXME
//assert(!(pHdr->dwFlags & (WHDR_DONE | WHDR_COMPLETE)));
//assert(pClient->DeviceQueue != NULL);
dwSize = pHdr->dwBufferLength - pClient->BufferPosition;
if (dwSize > MAX_BUFFER_SIZE)
dwSize = MAX_BUFFER_SIZE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -