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 + -
显示快捷键?