wavedd.c
来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 1,954 行 · 第 1/5 页
C
1,954 行
/****************************************************************************
*
* wavedd.c
*
* Multimedia kernel driver support component (esddrv)
*
* Copyright (c) 1991 - 1995 Microsoft Corporation. All Rights Reserved.
*
* Driver for wave input and output devices
*
* -- Wave driver entry points (wodMessage, widMessage)
* -- Auxiliary task (necessary for receiving Apcs and generating
* callbacks ASYNCRHONOUSLY)
* -- Interface to kernel driver (via DeviceIoControl)
*
* Note that if any error occurs then the kernel device is closed
* and all subsequent calls requiring calls to the kernel device
* return error until the device is closed by the application.
*
* History
* 01-Feb-1992 - Robin Speed (RobinSp) wrote it
* 04-Feb-1992 - SteveDav reviewed it
* 08-Feb-1992 - RobinSp - Redesign to chop up caller's data.
* Also does loops so we can remove them from the
* kernel driver.
*
***************************************************************************/
#include "esddrv.h"
#include "esd.h"
#include <winsock2.h>
#include <ntddwave.h>
/*****************************************************************************
internal declarations
****************************************************************************/
#define D1 dprintf1
#define D2 dprintf2
#define D3 dprintf3
// Stack size for our auxiliary task
typedef enum {
WaveThreadInvalid,
WaveThreadAddBuffer,
WaveThreadSetState,
WaveThreadSetData,
WaveThreadGetData,
WaveThreadBreakLoop,
WaveThreadClose,
WaveThreadTerminate
} WAVETHREADFUNCTION;
#define MAX_BUFFER_SIZE 8192 // Largest buffer we send to device
#define MAX_WAVE_BYTES 5*8192 // Max bytes we have queued on was 2200
//
// Structure to hide our overlapped structure in so we can get some
// context on IO completion
//
typedef struct {
OVERLAPPED Ovl;
LPWAVEHDR WaveHdr;
} WAVEOVL, *PWAVEOVL;
// per allocation structure for wave
typedef struct tag_WAVEALLOC {
struct tag_WAVEALLOC *Next; // Chaining
UINT DeviceNumber; // Which device
UINT DeviceType; // WaveInput or WaveOutput
DWORD dwCallback; // client's callback
DWORD dwInstance; // client's instance data
DWORD dwFlags; // Open flags
HWAVE hWave; // handle for stream
HANDLE hDev; // Wave device handle
LPWAVEHDR DeviceQueue; // Buffers queued by application
LPWAVEHDR NextBuffer; // Next buffer to send to device
DWORD BufferPosition; // How far we're into a large buffer
DWORD BytesOutstanding;
// Bytes being processed by device
DWORD dwPos; // Total number of bytes played
LPWAVEHDR LoopHead; // Start of loop if any
DWORD LoopCount; // Number more loops to go
WAVEOVL DummyWaveOvl; // For break loop
//
HANDLE Event; // Event for driver syncrhonization
// and notification of auxiliary
// task operation completion.
WAVETHREADFUNCTION AuxFunction; // Function for thread to perform
union {
LPWAVEHDR pHdr; // Buffer to pass in aux task
ULONG State; // State to set
struct {
ULONG Function; // IOCTL to use
PBYTE pData; // Data to set or get
ULONG DataLen; // Length of data
} GetSetData;
} AuxParam;
// 0 means terminate task.
HANDLE AuxEvent1; // Aux thread waits on this
HANDLE AuxEvent2; // Caller of Aux thread waits on this
HANDLE ThreadHandle; // Handle for thread termination ONLY
MMRESULT AuxReturnCode; // Return code from Aux task
}WAVEALLOC, *PWAVEALLOC;
PWAVEALLOC WaveHandleList; // Our chain of wave handles
//
// extra flag to track buffer completion
//
#define WHDR_COMPLETE 0x80000000
/*****************************************************************************
internal function prototypes
****************************************************************************/
STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
DWORD dwSize);
STATIC DWORD waveThread(LPVOID lpParameter);
STATIC void waveCleanUp(PWAVEALLOC pClient);
STATIC MMRESULT waveThreadCall(WAVETHREADFUNCTION Function, PWAVEALLOC pClient);
STATIC MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
STATIC MMRESULT waveWrite(LPWAVEHDR pHdr, PWAVEALLOC pClient);
STATIC void waveBlockFinished(LPWAVEHDR lpHdr, DWORD MsgId);
STATIC void waveCallback(PWAVEALLOC pWave, DWORD msg, DWORD dw1);
STATIC void waveCompleteBuffers(PWAVEALLOC pClient);
STATIC void waveFreeQ(PWAVEALLOC pClient);
STATIC void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
/* Attempt to pre-touch up to MIN(iSize,PRETOUCHLIMIT) bytes on from pb.
If AllowFault then keep going to fault the stuff in.
Otherwise stop as soon as you notice the clock ticking
*/
//PreTouch(BYTE * pb, int iSize, BOOL AllowFault)
//{
// DWORD dwTicks = GetTickCount();
// int pages = 0;
// static int Headway[100];
// static int c = 0;
// static int TotalTouches = 0;
// static int TimesThrough = 0; // number of times this code has run.
//
// if (iSize > PRETOUCHLIMIT) {
// iSize = PRETOUCHLIMIT;
// }
//
// ++TimesThrough;
//
// // pre-touch the pages but get out if it's taking too long
// // (which probably means we took a page fault.
// // Touch at least 2 pages as we may want 2 pages per DMA 1/2 buffer.
// while (iSize>0) {
// volatile BYTE b;
// b = *pb;
// pb += 4096; // move to next page. Are they ALWAYS 4096?
// iSize -= 4096; // and count it off
// ++pages;
// ++TotalTouches;
// if (dwTicks<GetTickCount() && pages>1 && !AllowFault) break;
// }
// Headway[c] = pages;
// ++c;
//
// if (c==100){
// for (c=0; c<=99; c += 10){
// dprintf(("%5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld %5ld",Headway[c],Headway[c+1],Headway[c+2],Headway[c+3],Headway[c+4],Headway[c+5],Headway[c+6],Headway[c+7],Headway[c+8],Headway[c+9]));
// }
// dprintf((" "));
// c = 0;
// }
//}
/****************************************************************************
* @doc INTERNAL
*
* @api VOID | TerminateWave | Free all wave resources
*
* @rdesc None
***************************************************************************/
VOID TerminateWave(VOID)
{
#ifdef TERMINATE
//
// This is all wrong - we need to find out how to terminate threads !
//
PWAVEALLOC pClient;
//
// Remove all our threads and their resources
//
for (pClient = WaveHandleList; pClient != NULL; pClient = pClient->Next) {
if (pClient->ThreadHandle) {
//
// Kill our thread. But be careful ! It may
// already have gone away - so don't wait for
// it to set its event, just wait for it
// to finish
//
//
// Set the function code
//
pClient->AuxFunction = WaveThreadTerminate;
//
// Kick off the thread
//
SetEvent(pClient->AuxEvent1);
//
// We created our threads with esdTaskCreate so it's
// safe to wait on them
//
WaitForSingleObject(pClient->ThreadHandle, INFINITE);
}
waveCleanUp(pClient);
}
#endif
}
/****************************************************************************
* @doc INTERNAL
*
* @api void | waveGetDevCaps | Get the device capabilities.
*
* @parm DWORD | id | Device id
*
* @parm UINT | DeviceType | type of device
*
* @parm LPBYTE | lpCaps | Far pointer to a WAVEOUTCAPS structure to
* receive the information.
*
* @parm DWORD | dwSize | Size of the WAVEOUTCAPS structure.
*
* @rdesc MMSYS.. return code.
***************************************************************************/
STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType,
LPBYTE lpCaps, DWORD dwSize)
{
LPWAVEOUTCAPS p = (LPWAVEOUTCAPS) lpCaps;
// fixme...
p->wMid = 0; // manf ID
p->wPid = 0; // prod ID
p->vDriverVersion = 1;
wcscpy(p->szPname, L"WinESD");
p->dwFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16 | \
WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16;
p->wChannels = 2;
// p->Reserved1 = 0;
p->dwSupport = 0; //WAVECAPS_LRVOLUME | WAVECAPS_VOLUME;
return MMSYSERR_NOERROR;
// return sndGetData(DeviceType, id, dwSize, lpCaps,
// IOCTL_WAVE_GET_CAPABILITIES);
}
/****************************************************************************
* @doc INTERNAL
*
* @api DWORD | waveGetPos | Get the stream position in samples.
*
* @parm PWAVEALLOC | pClient | Client handle.
*
* @parm LPMMTIME | lpmmt | Far pointer to an MMTIME structure.
*
* @parm DWORD | dwSize | Size of the MMTIME structure.
*
* @rdesc MMSYS... return value.
***************************************************************************/
MMRESULT waveGetPos(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
//
//FIXME:
// mErr = sndGetHandleData(pClient->hDev,
// sizeof(PositionData),
// &PositionData,
// IOCTL_WAVE_GET_POSITION,
// pClient->Event);
// mErr = MMSYSERR_NOERROR;
// PositionData.ByteCount = 0;
// PositionData.SampleCount = 0;
// if (mErr == MMSYSERR_NOERROR) {
if (lpmmt->wType == TIME_BYTES) {
lpmmt->u.cb = pClient->dwPos;
}
// default is samples.
else {
lpmmt->wType = TIME_SAMPLES;
// fixme, get real sample size...
lpmmt->u.sample = pClient->dwPos / 4;
}
// }
// return mErr;
return MMSYSERR_NOERROR;
}
/****************************************************************************
* @doc INTERNAL
*
* @api MMRESULT | waveOpen | Open wave device and set up logical device data
* and auxilary task for issuing requests and servicing Apc's
*
* @parm WAVEDEVTYPE | DeviceType | Whether it's a wave input or output device
*
* @parm DWORD | id | The device logical id
*
* @parm DWORD | msg | Input parameter to wodMessage
*
* @parm DWORD | dwUser | Input parameter to wodMessage - pointer to
* application's handle (generated by this routine)
*
* @parm DWORD | dwParam1 | Input parameter to wodMessage
*
* @parm DWORD | dwParam2 | Input parameter to wodMessage
*
* @rdesc wodMessage return code.
***************************************************************************/
STATIC MMRESULT waveOpen(UINT DeviceType,
DWORD id,
DWORD dwUser,
DWORD dwParam1,
DWORD dwParam2)
{
PWAVEALLOC pClient; // pointer to client information structure
MMRESULT mRet;
BOOL Result;
DWORD BytesReturned;
LPWAVEFORMATEX Format;
Format = (LPWAVEFORMATEX)((LPWAVEOPENDESC)dwParam1)->lpFormat;
// dwParam1 contains a pointer to a WAVEOPENDESC
// dwParam2 contains wave driver specific flags in the LOWORD
// and generic driver flags in the HIWORD
//
// If it's only a query to check if the device supports our format
// we :
// Open the device
// Test the format
// Close the device
//
if (dwParam2 & WAVE_FORMAT_QUERY) {
HANDLE hDev;
//
// See if we can open our device
// Only open for read (this should always work for our devices
// unless there are system problems).
//
// FIXME
// mRet = sndOpenDev(DeviceType,
// id,
// &hDev,
// GENERIC_READ);
// if (mRet != MMSYSERR_NOERROR) {
// return mRet;
// }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?