Annotation of ntddk/src/mmedia/mmdrv/wavedd.c, revision 1.1

1.1     ! root        1: /****************************************************************************
        !             2:  *
        !             3:  *   wavedd.c
        !             4:  *
        !             5:  *   Multimedia kernel driver support component (mmdrv)
        !             6:  *
        !             7:  *   Copyright (c) 1991 Microsoft Corporation.  All Rights Reserved.
        !             8:  *
        !             9:  *   Driver for wave input and output devices
        !            10:  *
        !            11:  *   -- Wave driver entry points (wodMessage, widMessage)
        !            12:  *   -- Auxiliary task (necessary for receiving Apcs and generating
        !            13:  *      callbacks ASYNCRHONOUSLY)
        !            14:  *   -- Interface to kernel driver (via DeviceIoControl)
        !            15:  *
        !            16:  *   Note that if any error occurs then the kernel device is closed
        !            17:  *   and all subsequent calls requiring calls to the kernel device
        !            18:  *   return error until the device is closed by the application.
        !            19:  *
        !            20:  *   History
        !            21:  *      01-Feb-1992 - Robin Speed (RobinSp) wrote it
        !            22:  *      04-Feb-1992 - SteveDav reviewed it
        !            23:  *      08-Feb-1992 - RobinSp - Redesign to chop up caller's data.
        !            24:  *                          Also does loops so we can remove them from the
        !            25:  *                          kernel driver.
        !            26:  *
        !            27:  ***************************************************************************/
        !            28: 
        !            29: #include "mmdrv.h"
        !            30: #include <ntddwave.h>
        !            31: 
        !            32: /*****************************************************************************
        !            33: 
        !            34:     internal declarations
        !            35: 
        !            36:  ****************************************************************************/
        !            37: 
        !            38: #define D1 dprintf1
        !            39: #define D2 dprintf2
        !            40: #define D3 dprintf3
        !            41: 
        !            42: // Stack size for our auxiliary task
        !            43: 
        !            44: #define WAVE_STACK_SIZE 300
        !            45: 
        !            46: typedef enum {
        !            47:     WaveThreadInvalid,
        !            48:     WaveThreadAddBuffer,
        !            49:     WaveThreadSetState,
        !            50:     WaveThreadSetData,
        !            51:     WaveThreadGetData,
        !            52:     WaveThreadBreakLoop,
        !            53:     WaveThreadClose,
        !            54:     WaveThreadTerminate
        !            55: } WAVETHREADFUNCTION;
        !            56: 
        !            57: 
        !            58: #define MAX_BUFFER_SIZE           8192  // Largest buffer we send to device
        !            59: #define MAX_WAVE_BYTES          5*8192  // Max bytes we have queued on was 22000
        !            60: 
        !            61: //
        !            62: // Structure to hide our overlapped structure in so we can get some
        !            63: // context on IO completion
        !            64: //
        !            65: 
        !            66: typedef struct {
        !            67:     OVERLAPPED Ovl;
        !            68:     LPWAVEHDR WaveHdr;
        !            69: } WAVEOVL, *PWAVEOVL;
        !            70: 
        !            71: // per allocation structure for wave
        !            72: typedef struct tag_WAVEALLOC {
        !            73:     struct tag_WAVEALLOC *Next;         // Chaining
        !            74:     UINT                DeviceNumber;   // Which device
        !            75:     UINT                DeviceType;     // WaveInput or WaveOutput
        !            76:     DWORD               dwCallback;     // client's callback
        !            77:     DWORD               dwInstance;     // client's instance data
        !            78:     DWORD               dwFlags;        // Open flags
        !            79:     HWAVE               hWave;          // handle for stream
        !            80: 
        !            81:     HANDLE              hDev;           // Wave device handle
        !            82:     LPWAVEHDR           DeviceQueue;    // Buffers queued by application
        !            83:     LPWAVEHDR           NextBuffer;     // Next buffer to send to device
        !            84:     DWORD               BufferPosition; // How far we're into a large buffer
        !            85:     DWORD               BytesOutstanding;
        !            86:                                         // Bytes being processed by device
        !            87:     LPWAVEHDR           LoopHead;       // Start of loop if any
        !            88:     DWORD               LoopCount;      // Number more loops to go
        !            89: 
        !            90:     WAVEOVL             DummyWaveOvl;   // For break loop
        !            91:                                                                                 //
        !            92:     HANDLE              Event;          // Event for driver syncrhonization
        !            93:                                         // and notification of auxiliary
        !            94:                                         // task operation completion.
        !            95:     WAVETHREADFUNCTION  AuxFunction;    // Function for thread to perform
        !            96:     union {
        !            97:         LPWAVEHDR       pHdr;           // Buffer to pass in aux task
        !            98:         ULONG           State;          // State to set
        !            99:         struct {
        !           100:             ULONG       Function;       // IOCTL to use
        !           101:             PBYTE       pData;          // Data to set or get
        !           102:             ULONG       DataLen;        // Length of data
        !           103:         } GetSetData;
        !           104: 
        !           105:     } AuxParam;
        !           106:                                         // 0 means terminate task.
        !           107:     HANDLE              AuxEvent1;      // Aux thread waits on this
        !           108:     HANDLE              AuxEvent2;      // Caller of Aux thread waits on this
        !           109:     HANDLE              ThreadHandle;   // Handle for thread termination ONLY
        !           110:     MMRESULT            AuxReturnCode;  // Return code from Aux task
        !           111: }WAVEALLOC, *PWAVEALLOC;
        !           112: 
        !           113: PWAVEALLOC WaveHandleList;              // Our chain of wave handles
        !           114: 
        !           115: 
        !           116: //
        !           117: // extra flag to track buffer completion
        !           118: //
        !           119: 
        !           120: #define WHDR_COMPLETE 0x80000000
        !           121: 
        !           122: /*****************************************************************************
        !           123: 
        !           124:     internal function prototypes
        !           125: 
        !           126:  ****************************************************************************/
        !           127: 
        !           128: STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
        !           129:                             DWORD dwSize);
        !           130: STATIC DWORD    waveThread(LPVOID lpParameter);
        !           131: STATIC void     waveCleanUp(PWAVEALLOC pClient);
        !           132: STATIC MMRESULT waveThreadCall(WAVETHREADFUNCTION Function, PWAVEALLOC pClient);
        !           133: STATIC MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
        !           134: STATIC MMRESULT waveWrite(LPWAVEHDR pHdr, PWAVEALLOC pClient);
        !           135: STATIC void     waveBlockFinished(LPWAVEHDR lpHdr, DWORD MsgId);
        !           136: STATIC void     waveCallback(PWAVEALLOC pWave, DWORD msg, DWORD dw1);
        !           137: STATIC void     waveCompleteBuffers(PWAVEALLOC pClient);
        !           138: STATIC void     waveFreeQ(PWAVEALLOC pClient);
        !           139: STATIC void     waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
        !           140: 
        !           141: /* Attempt to pre-touch up to MIN(iSize,PRETOUCHLIMIT) bytes on from pb.
        !           142:    If AllowFault then keep going to fault the stuff in.
        !           143:    Otherwise stop as soon as you notice the clock ticking
        !           144: */
        !           145: //PreTouch(BYTE * pb, int iSize, BOOL AllowFault)
        !           146: //{
        !           147: //    DWORD dwTicks = GetTickCount();
        !           148: //    int pages = 0;
        !           149: //    static int Headway[100];
        !           150: //    static int c = 0;
        !           151: //    static int TotalTouches = 0;
        !           152: //    static int TimesThrough = 0;   // number of times this code has run.
        !           153: //
        !           154: //    if (iSize > PRETOUCHLIMIT) {
        !           155: //        iSize = PRETOUCHLIMIT;
        !           156: //    }
        !           157: //
        !           158: //    ++TimesThrough;
        !           159: //
        !           160: //    // pre-touch the pages but get out if it's taking too long
        !           161: //    // (which probably means we took a page fault.
        !           162: //    // Touch at least 2 pages as we may want 2 pages per DMA 1/2 buffer.
        !           163: //    while (iSize>0) {
        !           164: //        volatile BYTE b;
        !           165: //        b = *pb;
        !           166: //        pb += 4096;    // move to next page.  Are they ALWAYS 4096?
        !           167: //        iSize -= 4096; // and count it off
        !           168: //        ++pages;
        !           169: //        ++TotalTouches;
        !           170: //        if (dwTicks<GetTickCount() && pages>1 && !AllowFault) break;
        !           171: //    }
        !           172: //    Headway[c] = pages;
        !           173: //    ++c;
        !           174: //
        !           175: //    if (c==100){
        !           176: //        for (c=0; c<=99; c += 10){
        !           177: //            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]));
        !           178: //        }
        !           179: //        dprintf((" "));
        !           180: //        c = 0;
        !           181: //    }
        !           182: //}
        !           183: 
        !           184: 
        !           185: /****************************************************************************
        !           186:  * @doc INTERNAL
        !           187:  *
        !           188:  * @api VOID | TerminateWave | Free all wave resources
        !           189:  *
        !           190:  * @rdesc None
        !           191:  ***************************************************************************/
        !           192: VOID TerminateWave(VOID)
        !           193: {
        !           194: #ifdef TERMINATE
        !           195: 
        !           196:     //
        !           197:     // This is all wrong - we need to find out how to terminate threads !
        !           198:     //
        !           199: 
        !           200:     PWAVEALLOC pClient;
        !           201: 
        !           202:     //
        !           203:     // Remove all our threads and their resources
        !           204:     //
        !           205: 
        !           206:     for (pClient = WaveHandleList; pClient != NULL; pClient = pClient->Next) {
        !           207:         if (pClient->ThreadHandle) {
        !           208:             //
        !           209:             // Kill our thread.  But be careful !  It may
        !           210:             // already have gone away - so don't wait for
        !           211:             // it to set its event, just wait for it
        !           212:             // to finish
        !           213:             //
        !           214: 
        !           215:             //
        !           216:             // Set the function code
        !           217:             //
        !           218:             pClient->AuxFunction = WaveThreadTerminate;
        !           219: 
        !           220:             //
        !           221:             // Kick off the thread
        !           222:             //
        !           223:             SetEvent(pClient->AuxEvent1);
        !           224: 
        !           225:             //
        !           226:             // We created our threads with mmTaskCreate so it's
        !           227:             // safe to wait on them
        !           228:             //
        !           229:             WaitForSingleObject(pClient->ThreadHandle, INFINITE);
        !           230:         }
        !           231:         waveCleanUp(pClient);
        !           232:     }
        !           233: #endif
        !           234: }
        !           235: 
        !           236: /****************************************************************************
        !           237:  * @doc INTERNAL
        !           238:  *
        !           239:  * @api void | waveGetDevCaps | Get the device capabilities.
        !           240:  *
        !           241:  * @parm DWORD | id | Device id
        !           242:  *
        !           243:  * @parm UINT | DeviceType | type of device
        !           244:  *
        !           245:  * @parm LPBYTE | lpCaps | Far pointer to a WAVEOUTCAPS structure to
        !           246:  *      receive the information.
        !           247:  *
        !           248:  * @parm DWORD | dwSize | Size of the WAVEOUTCAPS structure.
        !           249:  *
        !           250:  * @rdesc MMSYS.. return code.
        !           251:  ***************************************************************************/
        !           252: STATIC MMRESULT waveGetDevCaps(DWORD id, UINT DeviceType,
        !           253:                             LPBYTE lpCaps, DWORD dwSize)
        !           254: {
        !           255:     return sndGetData(DeviceType, id, dwSize, lpCaps,
        !           256:                       IOCTL_WAVE_GET_CAPABILITIES);
        !           257: }
        !           258: 
        !           259: /****************************************************************************
        !           260:  * @doc INTERNAL
        !           261:  *
        !           262:  * @api DWORD | waveGetPos | Get the stream position in samples.
        !           263:  *
        !           264:  * @parm PWAVEALLOC | pClient | Client handle.
        !           265:  *
        !           266:  * @parm LPMMTIME | lpmmt | Far pointer to an MMTIME structure.
        !           267:  *
        !           268:  * @parm DWORD | dwSize | Size of the MMTIME structure.
        !           269:  *
        !           270:  * @rdesc MMSYS... return value.
        !           271:  ***************************************************************************/
        !           272: MMRESULT waveGetPos(PWAVEALLOC pClient, LPMMTIME lpmmt, DWORD dwSize)
        !           273: {
        !           274:     WAVE_DD_POSITION PositionData;
        !           275:     MMRESULT mErr;
        !           276: 
        !           277:     if (dwSize < sizeof(MMTIME))
        !           278:         return MMSYSERR_ERROR;
        !           279: 
        !           280:     //
        !           281:     // Get the current position from the driver
        !           282:     //
        !           283:     mErr = sndGetHandleData(pClient->hDev,
        !           284:                             sizeof(PositionData),
        !           285:                             &PositionData,
        !           286:                             IOCTL_WAVE_GET_POSITION,
        !           287:                             pClient->Event);
        !           288: 
        !           289:     if (mErr == MMSYSERR_NOERROR) {
        !           290:         if (lpmmt->wType == TIME_BYTES) {
        !           291:             lpmmt->u.cb = PositionData.ByteCount;
        !           292:         }
        !           293: 
        !           294:         // default is samples.
        !           295:         else {
        !           296:             lpmmt->wType = TIME_SAMPLES;
        !           297:             lpmmt->u.sample = PositionData.SampleCount;
        !           298:         }
        !           299:     }
        !           300: 
        !           301:     return mErr;
        !           302: }
        !           303: 
        !           304: /****************************************************************************
        !           305:  * @doc INTERNAL
        !           306:  *
        !           307:  * @api MMRESULT | waveOpen | Open wave device and set up logical device data
        !           308:  *    and auxilary task for issuing requests and servicing Apc's
        !           309:  *
        !           310:  * @parm WAVEDEVTYPE | DeviceType | Whether it's a wave input or output device
        !           311:  *
        !           312:  * @parm DWORD | id | The device logical id
        !           313:  *
        !           314:  * @parm DWORD | msg | Input parameter to wodMessage
        !           315:  *
        !           316:  * @parm DWORD | dwUser | Input parameter to wodMessage - pointer to
        !           317:  *   application's handle (generated by this routine)
        !           318:  *
        !           319:  * @parm DWORD | dwParam1 | Input parameter to wodMessage
        !           320:  *
        !           321:  * @parm DWORD | dwParam2 | Input parameter to wodMessage
        !           322:  *
        !           323:  * @rdesc wodMessage return code.
        !           324:  ***************************************************************************/
        !           325: 
        !           326: STATIC MMRESULT waveOpen(UINT  DeviceType,
        !           327:                          DWORD id,
        !           328:                          DWORD dwUser,
        !           329:                          DWORD dwParam1,
        !           330:                          DWORD dwParam2)
        !           331: {
        !           332:     PWAVEALLOC     pClient;  // pointer to client information structure
        !           333:     MMRESULT mRet;
        !           334:     BOOL Result;
        !           335:     DWORD BytesReturned;
        !           336:         LPPCMWAVEFORMAT Format;
        !           337: 
        !           338:     // dwParam1 contains a pointer to a WAVEOPENDESC
        !           339:     // dwParam2 contains wave driver specific flags in the LOWORD
        !           340:     // and generic driver flags in the HIWORD
        !           341: 
        !           342:     //
        !           343:     // If it's only a query to check if the device supports our format
        !           344:     // we :
        !           345:     //     Open the device
        !           346:     //     Test the format
        !           347:     //     Close the device
        !           348:     //
        !           349: 
        !           350:     if (dwParam2 & WAVE_FORMAT_QUERY) {
        !           351:         HANDLE hDev;
        !           352: 
        !           353:         //
        !           354:         // See if we can open our device
        !           355:         // Only open for read (this should always work for our devices
        !           356:         // unless there are system problems).
        !           357:         //
        !           358: 
        !           359:         mRet = sndOpenDev(DeviceType,
        !           360:                            id,
        !           361:                            &hDev,
        !           362:                            GENERIC_READ);
        !           363: 
        !           364:         if (mRet != MMSYSERR_NOERROR) {
        !           365:             return mRet;
        !           366:         }
        !           367: 
        !           368:         //
        !           369:         // Check the format
        !           370:         //
        !           371:                 Format = (LPPCMWAVEFORMAT)((LPWAVEOPENDESC)dwParam1)->lpFormat;
        !           372:         Result = DeviceIoControl(
        !           373:                         hDev,
        !           374:                         IOCTL_WAVE_QUERY_FORMAT,
        !           375:                         (PVOID)Format,
        !           376:                         sizeof(PCMWAVEFORMAT) +
        !           377:                                                 (Format->wf.wFormatTag == WAVE_FORMAT_PCM ? 0 :
        !           378:                                                                        *(LPWORD)(Format + 1)),
        !           379:                                                      // Input buffer size
        !           380:                         NULL,                        // Output buffer
        !           381:                         0,                           // Output buffer size
        !           382:                         &BytesReturned,
        !           383:                         NULL);
        !           384: 
        !           385: 
        !           386:         //
        !           387:         // Only a query so close the device
        !           388:         //
        !           389: 
        !           390:         CloseHandle(hDev);
        !           391: 
        !           392:         return Result ? MMSYSERR_NOERROR :
        !           393:                GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT :
        !           394:                                                 sndTranslateStatus();
        !           395:     }
        !           396: 
        !           397:     //
        !           398:     // See if we've got this device already in our list (in
        !           399:     // which case we have a thread and events for it already made)
        !           400:     //
        !           401: 
        !           402:     EnterCriticalSection(&mmDrvCritSec);
        !           403: 
        !           404:     for (pClient = WaveHandleList;
        !           405:          pClient != NULL;
        !           406:          pClient = pClient->Next) {
        !           407:         if (pClient->DeviceNumber == id &&
        !           408:             pClient->DeviceType == DeviceType) {
        !           409:             //
        !           410:             // We already have a thread and resources for this device
        !           411:             //
        !           412: 
        !           413:             if (pClient->hDev != INVALID_HANDLE_VALUE) {
        !           414:                 //
        !           415:                 // Someone else is using it!
        !           416:                 //
        !           417: 
        !           418:                 LeaveCriticalSection(&mmDrvCritSec);
        !           419:                 return MMSYSERR_ALLOCATED;
        !           420:             }
        !           421:             break;
        !           422:         }
        !           423:     }
        !           424: 
        !           425:     //
        !           426:     // allocate my per-client structure and zero it (LPTR).
        !           427:     //
        !           428: 
        !           429:     if (pClient == NULL) {
        !           430:         pClient = (PWAVEALLOC)HeapAlloc(hHeap, 0, sizeof(WAVEALLOC));
        !           431:         if (pClient == NULL) {
        !           432:             LeaveCriticalSection(&mmDrvCritSec);
        !           433:             return MMSYSERR_NOMEM;
        !           434:         }
        !           435: 
        !           436:         dprintf2(("Creating new device resource for device id %d, type %s",
        !           437:                  id,
        !           438:                  DeviceType == WaveInDevice ? "Wave Input" : "Wave Output"));
        !           439: 
        !           440:         memset((PVOID)pClient, 0, sizeof(WAVEALLOC));
        !           441: 
        !           442:         //
        !           443:         // Add it to the list
        !           444:         //
        !           445:         pClient->DeviceNumber = id;
        !           446:         pClient->DeviceType = DeviceType;
        !           447:         pClient->Next = WaveHandleList;
        !           448:         WaveHandleList = pClient;
        !           449:     }
        !           450: 
        !           451: 
        !           452:     //
        !           453:     // and fill it with info
        !           454:     //
        !           455: 
        !           456:     pClient->dwCallback  = ((LPWAVEOPENDESC)dwParam1)->dwCallback;
        !           457:     pClient->dwInstance  = ((LPWAVEOPENDESC)dwParam1)->dwInstance;
        !           458:     pClient->hWave       = ((LPWAVEOPENDESC)dwParam1)->hWave;
        !           459:     pClient->dwFlags     = dwParam2;
        !           460: 
        !           461:     // pClient->hDev is initialized by sndOpenDev
        !           462: 
        !           463:     pClient->DeviceQueue = NULL;
        !           464:     pClient->NextBuffer  = NULL;
        !           465:     pClient->BufferPosition = 0;
        !           466:     pClient->BytesOutstanding = 0;
        !           467:     pClient->LoopHead    = NULL;
        !           468:     pClient->LoopCount   = 0;
        !           469: 
        !           470:     //
        !           471:     // See if we can open our device
        !           472:     // We could get ERROR_BUSY if someone else is has the device open
        !           473:     // for writing.
        !           474:     //
        !           475: 
        !           476:     mRet = sndOpenDev(DeviceType,
        !           477:                        id,
        !           478:                        &pClient->hDev,
        !           479:                        (GENERIC_READ | GENERIC_WRITE));
        !           480: 
        !           481:     if (mRet != MMSYSERR_NOERROR) {
        !           482: 
        !           483:                 WinAssert(pClient->hDev == INVALID_HANDLE_VALUE);
        !           484:         LeaveCriticalSection(&mmDrvCritSec);
        !           485:         return mRet;
        !           486:     }
        !           487: 
        !           488: 
        !           489:     //
        !           490:     // make sure we can handle the format and set it.
        !           491:     //
        !           492: 
        !           493:     Result = DeviceIoControl(
        !           494:                  pClient->hDev,
        !           495:                  IOCTL_WAVE_SET_FORMAT,
        !           496:                         (PVOID)((LPWAVEOPENDESC)dwParam1)->lpFormat,
        !           497: /* BUGBUG NOT GENERAL */sizeof(PCMWAVEFORMAT),       // Input buffer size
        !           498:                         NULL,                        // Output buffer
        !           499:                         0,                           // Output buffer size
        !           500:                         &BytesReturned,
        !           501:                         NULL);
        !           502: 
        !           503: 
        !           504:     if (!Result) {
        !           505:         CloseHandle(pClient->hDev);
        !           506:         pClient->hDev = INVALID_HANDLE_VALUE;
        !           507:         LeaveCriticalSection(&mmDrvCritSec);
        !           508:         return GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT :
        !           509:                                                 sndTranslateStatus();
        !           510:     }
        !           511: 
        !           512:     LeaveCriticalSection(&mmDrvCritSec);
        !           513: 
        !           514:     //
        !           515:     // Create our event for synchronization with the kernel driver
        !           516:     //
        !           517: 
        !           518:     if (!pClient->Event) {
        !           519:         pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           520:         if (pClient->Event == NULL) {
        !           521:             waveCleanUp(pClient);
        !           522:             return MMSYSERR_NOMEM;
        !           523:         }
        !           524:         //
        !           525:         // Create our event for our thread to wait on
        !           526:         //
        !           527: 
        !           528:         pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           529:         if (!pClient->AuxEvent1) {
        !           530:             waveCleanUp(pClient);
        !           531:             return MMSYSERR_NOMEM;
        !           532:         }
        !           533:         //
        !           534:         // Create our event for waiting for the auxiliary thread
        !           535:         //
        !           536: 
        !           537:         pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           538:         if (!pClient->AuxEvent2) {
        !           539:             waveCleanUp(pClient);
        !           540:             return MMSYSERR_NOMEM;
        !           541:         }
        !           542: 
        !           543:         //
        !           544:         // Create our auxiliary thread for sending buffers to the driver
        !           545:         // and collecting Apcs
        !           546:         //
        !           547: 
        !           548:         mRet = mmTaskCreate((LPTASKCALLBACK)waveThread,
        !           549:                             &pClient->ThreadHandle,
        !           550:                             (DWORD)pClient);
        !           551: 
        !           552:         if (mRet != MMSYSERR_NOERROR) {
        !           553:             waveCleanUp(pClient);
        !           554:             return MMSYSERR_NOMEM;
        !           555:         }
        !           556: 
        !           557:         //
        !           558:         // Make sure the thread has really started
        !           559:         //
        !           560: 
        !           561:         WaitForSingleObject(pClient->AuxEvent2, INFINITE);
        !           562:     }
        !           563: 
        !           564:     //
        !           565:     // give the client my driver dw
        !           566:     //
        !           567:     {
        !           568:         PWAVEALLOC *pUserHandle;
        !           569:         pUserHandle = (PWAVEALLOC *)dwUser;
        !           570:         *pUserHandle = pClient;
        !           571:     }
        !           572: 
        !           573:     //
        !           574:     // sent client his OPEN callback message
        !           575:     //
        !           576:     waveCallback(pClient, DeviceType == WaveOutDevice ? WOM_OPEN : WIM_OPEN, 0L);
        !           577: 
        !           578:     return MMSYSERR_NOERROR;
        !           579: }
        !           580: 
        !           581: /****************************************************************************
        !           582:  * @doc INTERNAL
        !           583:  *
        !           584:  * @api void | waveCleanUp | Free resources for a wave device
        !           585:  *
        !           586:  * @parm PWAVEALLOC | pClient | Pointer to a WAVEALLOC structure describing
        !           587:  *      resources to be freed.
        !           588:  *
        !           589:  * @rdesc There is no return value.
        !           590:  *
        !           591:  * @comm If the pointer to the resource is NULL then the resource has not
        !           592:  *     been allocated.
        !           593:  ***************************************************************************/
        !           594: STATIC void waveCleanUp(PWAVEALLOC pClient)
        !           595: {
        !           596:     EnterCriticalSection(&mmDrvCritSec);
        !           597:     if (pClient->hDev != INVALID_HANDLE_VALUE) {
        !           598:         CloseHandle(pClient->hDev);
        !           599:         pClient->hDev = INVALID_HANDLE_VALUE;
        !           600:     }
        !           601:     if (pClient->AuxEvent1) {
        !           602:         CloseHandle(pClient->AuxEvent1);
        !           603:         pClient->AuxEvent1 = NULL;
        !           604:     }
        !           605:     if (pClient->AuxEvent2) {
        !           606:         CloseHandle(pClient->AuxEvent2);
        !           607:         pClient->AuxEvent2 = NULL;
        !           608:     }
        !           609:     if (pClient->Event) {
        !           610:         CloseHandle(pClient->Event);
        !           611:         pClient->Event = NULL;
        !           612:     }
        !           613:     LeaveCriticalSection(&mmDrvCritSec);
        !           614: }
        !           615: 
        !           616: 
        !           617: /****************************************************************************
        !           618:  * @doc INTERNAL
        !           619:  *
        !           620:  * @api MMRESULT | waveWrite | Pass a new buffer to the Auxiliary thread for
        !           621:  *       a wave device.
        !           622:  *
        !           623:  * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
        !           624:  *
        !           625:  * @parm PWAVEALLOC | pClient | The data associated with the logical wave
        !           626:  *     device.
        !           627:  *
        !           628:  * @rdesc A MMSYS... type return code for the application.
        !           629:  *
        !           630:  * @comm The buffer flags are set and the buffer is passed to the auxiliary
        !           631:  *     device task for processing.
        !           632:  ***************************************************************************/
        !           633: STATIC MMRESULT waveWrite(LPWAVEHDR pHdr, PWAVEALLOC pClient)
        !           634: {
        !           635:     //
        !           636:     // Put the request at the end of our queue.
        !           637:     //
        !           638:     pHdr->dwFlags |= WHDR_INQUEUE;
        !           639:     pHdr->dwFlags &= ~WHDR_DONE;
        !           640:     pClient->AuxParam.pHdr = pHdr;
        !           641:     return waveThreadCall(WaveThreadAddBuffer, pClient);
        !           642: }
        !           643: 
        !           644: /****************************************************************************
        !           645:  * @doc INTERNAL
        !           646:  *
        !           647:  * @api MMRESULT | waveSetState | Set a wave device to a given state
        !           648:  *     This function is executed on the Auxiliary thread to synchronize
        !           649:  *     correctly.
        !           650:  *
        !           651:  * @parm PWAVEALLOC | pClient | The data associated with the logical wave
        !           652:  *     output device.
        !           653:  *
        !           654:  * @parm ULONG | State | The new state
        !           655:  *
        !           656:  * @rdesc A MMSYS... type return code for the application.
        !           657:  ***************************************************************************/
        !           658: STATIC MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State)
        !           659: {
        !           660:     return sndSetHandleData(pClient->hDev,
        !           661:                             sizeof(State),
        !           662:                             &State,
        !           663:                             IOCTL_WAVE_SET_STATE,
        !           664:                             pClient->Event);
        !           665: }
        !           666: 
        !           667: /****************************************************************************
        !           668:  * @doc INTERNAL
        !           669:  *
        !           670:  * @api void | waveBlockFinished | This function sets the done bit and invokes
        !           671:  *     the callback function if there is one.
        !           672:  *
        !           673:  * @parm LPWAVEHDR | lpHdr | Far pointer to the header.
        !           674:  *
        !           675:  * @rdesc There is no return value.
        !           676:  ***************************************************************************/
        !           677: STATIC void waveBlockFinished(LPWAVEHDR lpHdr, DWORD MsgId)
        !           678: {
        !           679:     PWAVEALLOC pWav;
        !           680: 
        !           681:     D3(("blkfin: lpHdr = %x", lpHdr));
        !           682:     // Clear our private flag
        !           683:     lpHdr->dwFlags &= ~WHDR_COMPLETE;
        !           684: 
        !           685:     // We are giving the block back to the application.  The header is no
        !           686:     // longer in our queue, so we reset the WHDR_INQUEUE bit.  Also, we
        !           687:     // clear our driver specific bit and cauterize the lpNext pointer.
        !           688:     lpHdr->dwFlags &= ~WHDR_INQUEUE;
        !           689:     lpHdr->lpNext = NULL;
        !           690: 
        !           691:     pWav = (PWAVEALLOC)(lpHdr->reserved);
        !           692: 
        !           693:     // set the 'done' bit - note that some people poll this bit.
        !           694:     lpHdr->dwFlags |= WHDR_DONE;
        !           695: 
        !           696:     // invoke the callback function
        !           697:     waveCallback(pWav, MsgId, (DWORD)lpHdr);
        !           698: }
        !           699: 
        !           700: 
        !           701: /****************************************************************************
        !           702:  * @doc INTERNAL
        !           703:  *
        !           704:  * @api MMRESULT | waveThreadCall | Set the function for the thread to perform
        !           705:  *     and 'call' the thread using the event pair mechanism.
        !           706:  *
        !           707:  * @parm WAVETHREADFUNCTION | Function | The function to perform
        !           708:  *
        !           709:  * @parm PWAVEALLOC | Our logical device data
        !           710:  *
        !           711:  * @rdesc An MMSYS... type return value suitable for returning to the
        !           712:  *      application
        !           713:  *
        !           714:  * @comm The AuxParam field in the device data is the 'input' to
        !           715:  *      the function processing loop in WaveThread().
        !           716:  ***************************************************************************/
        !           717: STATIC MMRESULT waveThreadCall(WAVETHREADFUNCTION Function, PWAVEALLOC pClient)
        !           718: {
        !           719:     //
        !           720:     // Trap any failures
        !           721:     //
        !           722:     WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
        !           723: 
        !           724:     //
        !           725:     // Set the function code
        !           726:     //
        !           727:     pClient->AuxFunction = Function;
        !           728: 
        !           729:     //
        !           730:     // Kick off the thread
        !           731:     //
        !           732:     SetEvent(pClient->AuxEvent1);
        !           733: 
        !           734:     //
        !           735:     // Wait for it to complete
        !           736:     //
        !           737:     WaitForSingleObject(pClient->AuxEvent2, INFINITE);
        !           738: 
        !           739:     //
        !           740:     // Return the return code that our task set.
        !           741:     //
        !           742:     return pClient->AuxReturnCode;
        !           743: }
        !           744: 
        !           745: /****************************************************************************
        !           746:  * @doc INTERNAL
        !           747:  *
        !           748:  * @api MMRESULT | wavePartialApc | Called when a partial buffer is complete.
        !           749:  *
        !           750:  * @parm DWORD | BytesTransferred | Not relevant to us
        !           751:  *
        !           752:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
        !           753:  *
        !           754:  * @rdesc None
        !           755:  *
        !           756:  * @comm The IO status block is freed and the BytesOutstanding count
        !           757:  *       used to limit the buffers we have locked down is updated (we
        !           758:  *       know here that parital buffers are all the same size).
        !           759:  *       Also the byte count for a recording buffer is updated.
        !           760:  ***************************************************************************/
        !           761: STATIC void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
        !           762: {
        !           763:     LPWAVEHDR pHdr;
        !           764:     PWAVEALLOC pClient;
        !           765: 
        !           766:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
        !           767:     D3(("wavePartialOvl: pHdr = %x", pHdr));
        !           768: 
        !           769:     pClient = (PWAVEALLOC)pHdr->reserved;
        !           770: 
        !           771:     //
        !           772:     // We can't trust the IO system to return our buffers in the right
        !           773:     // order so we set a flag in the buffer but only complete buffers
        !           774:     // at the FRONT of the queue which have the flag set.  In fact
        !           775:     // we don't process the stuff here - leave that for when we
        !           776:     // exit the wait because calling the client's callback can
        !           777:     // do nasty things inside and Apc routine
        !           778:     //
        !           779: 
        !           780:     WinAssert(pHdr->dwFlags & WHDR_INQUEUE);
        !           781:     WinAssert(!(pHdr->dwFlags & WHDR_COMPLETE));
        !           782: 
        !           783:     //
        !           784:     // Recalculate how many bytes are outstanding on the device
        !           785:     //
        !           786: 
        !           787:     pClient->BytesOutstanding -= MAX_BUFFER_SIZE;
        !           788: 
        !           789:     //
        !           790:     // Work out how much was recorded if we're a recording device
        !           791:     //
        !           792: 
        !           793:     if (pClient->DeviceType == WaveInDevice) {
        !           794:         pHdr->dwBytesRecorded += BytesTransferred;
        !           795:     }
        !           796: 
        !           797:     //
        !           798:     // Free our Iosb
        !           799:     //
        !           800: 
        !           801:     HeapFree(hHeap, 0, (LPSTR)pOverlapped);
        !           802: 
        !           803: }
        !           804: 
        !           805: 
        !           806: 
        !           807: /****************************************************************************
        !           808:  * @doc INTERNAL
        !           809:  *
        !           810:  * @api void | waveOvl | Called when a (user) buffer is complete.
        !           811:  *
        !           812:  * @parm DWORD | BytesTransferred | Not relevant to us
        !           813:  *
        !           814:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
        !           815:  *
        !           816:  * @parm PIO_STATUS_BLOCK | The Io status block we used
        !           817:  *
        !           818:  * @rdesc None
        !           819:  *
        !           820:  * @comm The IO status block is freed and the BytesOutstanding count
        !           821:  *       used to limit the buffers we have locked down is updated (we
        !           822:  *       know here that parital buffers are all the same size so we
        !           823:  *       can compute the size of the 'last' buffer for a given user buffer).
        !           824:  *       Also the byte count for a recording buffer is updated.
        !           825:  *       The user buffer is marked as 'DONE'.
        !           826:  ***************************************************************************/
        !           827: STATIC void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
        !           828: {
        !           829:     PWAVEHDR pHdr;
        !           830:     PWAVEALLOC pClient;
        !           831: 
        !           832:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
        !           833:     D3(("waveOvl: pHdr = %x", pHdr));
        !           834:     pClient = (PWAVEALLOC)pHdr->reserved;
        !           835: 
        !           836:     //
        !           837:     // We can't trust the IO system to return our buffers in the right
        !           838:     // order so we set a flag in the buffer but only complete buffers
        !           839:     // at the FRONT of the queue which have the flag set.  In fact
        !           840:     // we don't process the stuff here - leave that for when we
        !           841:     // exit the wait because calling the client's callback can
        !           842:     // do nasty things inside and Apc routine
        !           843:     //
        !           844: 
        !           845:     WinAssert(pHdr->dwFlags & WHDR_INQUEUE);
        !           846:     WinAssert(!(pHdr->dwFlags & WHDR_COMPLETE));
        !           847: 
        !           848:     //
        !           849:     // Mark buffer as done unless we're doing more loops with it
        !           850:     //
        !           851:     pHdr->dwFlags |= WHDR_COMPLETE;
        !           852: 
        !           853:     //
        !           854:     // It's now our duty to see if there were some old loops lying
        !           855:     // around earlier in the queue which are vestiges of old loops.
        !           856:     //
        !           857: 
        !           858:     if (pHdr->dwFlags & WHDR_BEGINLOOP) {
        !           859:         PWAVEHDR pHdrSearch;
        !           860:         for (pHdrSearch = pClient->DeviceQueue ;
        !           861:              pHdrSearch != pHdr ;
        !           862:              pHdrSearch = pHdrSearch->lpNext) {
        !           863:             WinAssert(pHdrSearch != NULL);
        !           864:             pHdrSearch->dwFlags |= WHDR_COMPLETE;
        !           865:         }
        !           866:     }
        !           867:     //
        !           868:     // Recalculate how many bytes are outstanding on the device
        !           869:     //
        !           870: 
        !           871:     if (pHdr->dwBufferLength) {
        !           872:         pClient->BytesOutstanding -= (pHdr->dwBufferLength - 1) %
        !           873:                                          MAX_BUFFER_SIZE + 1;
        !           874:     }
        !           875: 
        !           876:     //
        !           877:     // Work out how much was recorded if we're a recording device
        !           878:     //
        !           879: 
        !           880:     if (pClient->DeviceType == WaveInDevice) {
        !           881:         pHdr->dwBytesRecorded += BytesTransferred;
        !           882:     }
        !           883: 
        !           884:     //
        !           885:     // Free our Iosb
        !           886:     //
        !           887: 
        !           888:     HeapFree(hHeap, 0, (LPSTR)pOverlapped);
        !           889: 
        !           890: }
        !           891: 
        !           892: /****************************************************************************
        !           893:  * @doc INTERNAL
        !           894:  *
        !           895:  * @api MMRESULT | waveLoopOvl | Called when a (user) buffer is complete.
        !           896:  *                               but the buffer was need for more loops.
        !           897:  *
        !           898:  * @parm DWORD | BytesTransferred | Not relevant to us
        !           899:  *
        !           900:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
        !           901:  *
        !           902:  * @rdesc None
        !           903:  *
        !           904:  * @comm Same as waveApc but the buffer is not marked complete.
        !           905:  ***************************************************************************/
        !           906: STATIC void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
        !           907: {
        !           908:     DWORD dwFlags;
        !           909:     PWAVEHDR pHdr;
        !           910: 
        !           911:     D3(("waveLoopOvl"));
        !           912:     pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
        !           913: 
        !           914:     //
        !           915:     // Do it this way to avoid falling into a hole if the Apcs are
        !           916:     // in the wrong order !!!
        !           917:     //
        !           918:     dwFlags = pHdr->dwFlags;
        !           919:     waveOvl(dwErrorCode, BytesTransferred, pOverlapped);
        !           920:     pHdr->dwFlags = dwFlags;
        !           921: }
        !           922: 
        !           923: /****************************************************************************
        !           924:  * @doc INTERNAL
        !           925:  *
        !           926:  * @api MMRESULT | waveBreakOvl | Used to chase out a buffer to break a loop.
        !           927:  *
        !           928:  * @parm DWORD | BytesTransferred | Not relevant to us
        !           929:  *
        !           930:  * @parm LPOVERLAPPED | pOverLapped | Overlapped structure for this callback
        !           931:  *
        !           932:  * @rdesc None
        !           933:  *
        !           934:  * @comm Mark the relevant buffer complete
        !           935:  ***************************************************************************/
        !           936: STATIC void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
        !           937: {
        !           938:     D3(("waveBreakOvl"));
        !           939:     ((PWAVEOVL)pOverlapped)->WaveHdr->dwFlags |= WHDR_COMPLETE;
        !           940: }
        !           941: 
        !           942: 
        !           943: /****************************************************************************
        !           944:  * @doc INTERNAL
        !           945:  *
        !           946:  * @api void | waveStart | Send more buffers to the device if possible
        !           947:  *
        !           948:  * @parm PWAVEALLOC | pClient | The client's handle data
        !           949:  *
        !           950:  * @rdesc There is no return code.
        !           951:  *
        !           952:  * @comm  The routine is called both when new buffers become available
        !           953:  *        or when old buffers or parital buffers are completed so
        !           954:  *        that device can accept more data.
        !           955:  *
        !           956:  *        No more that MAX_WAVE_BYTES in buffers no bigger than
        !           957:  *        MAX_BUFFER_SIZE are to be outstanding on the device at
        !           958:  *        any one time.
        !           959:  *
        !           960:  *        An additional complication is that we have to process loops
        !           961:  *        which means (among other things) that the SAME BUFFER may
        !           962:  *        appear multiple times in the driver's list (as different
        !           963:  *        requests).  There are no loops for input devices.
        !           964:  *        Loop buffers complete with Apcs which do not complete them
        !           965:  *        (except for the final loop iteration) which means that if
        !           966:  *        we decide unexpectedly to finish a loop (ie by waveOutBreakLoop)
        !           967:  *        we must 'chase' the loop out with an artificial buffer to
        !           968:  *        get our Apc going.
        !           969:  *
        !           970:  ***************************************************************************/
        !           971: STATIC MMRESULT waveStart(PWAVEALLOC pClient)
        !           972: {
        !           973:     DWORD dwSize;
        !           974:     BOOL Result;
        !           975: 
        !           976:     //
        !           977:     // See if we can fit any more data on the device
        !           978:     //
        !           979: 
        !           980:     WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
        !           981: 
        !           982:     while (pClient->NextBuffer) {
        !           983:         PWAVEHDR pHdr;
        !           984: 
        !           985:         pHdr = pClient->NextBuffer;
        !           986: 
        !           987:         WinAssert(pClient->DeviceQueue != NULL);
        !           988:                 WinAssert(!(pHdr->dwFlags & (WHDR_DONE | WHDR_COMPLETE)));
        !           989: 
        !           990:         dwSize = pHdr->dwBufferLength - pClient->BufferPosition;
        !           991:         if (dwSize > MAX_BUFFER_SIZE) {
        !           992:             dwSize = MAX_BUFFER_SIZE;
        !           993:         }
        !           994: 
        !           995:         if (dwSize + pClient->BytesOutstanding <= MAX_WAVE_BYTES) {
        !           996:             //
        !           997:             // OK - we can fit another buffer in
        !           998:             //
        !           999:             // Don't have our overlay structure on the stack for an
        !          1000:             // ASYNCHRONOUS IO !   Otherwise the IO subsystem will overwrite
        !          1001:             // somebody else's data when the operation completes
        !          1002:             //
        !          1003:             PWAVEOVL pWaveOvl;
        !          1004: 
        !          1005:             if (pClient->BufferPosition == 0) {
        !          1006:                 //
        !          1007:                 // Start of new buffer
        !          1008:                 // See if the buffer is the start of a new loop
        !          1009:                 // (Check not continuation of old one)
        !          1010:                 //
        !          1011:                 if (pClient->NextBuffer &&
        !          1012:                     (pClient->NextBuffer->dwFlags & WHDR_BEGINLOOP) &&
        !          1013:                     pClient->NextBuffer != pClient->LoopHead) {
        !          1014: 
        !          1015:                     pClient->LoopHead = pClient->NextBuffer;
        !          1016: 
        !          1017:                     pClient->LoopCount = pClient->NextBuffer->dwLoops;
        !          1018: 
        !          1019:                     //
        !          1020:                     // Loop count is number of times to play
        !          1021:                     //
        !          1022:                     if (pClient->LoopCount > 0) {
        !          1023:                         pClient->LoopCount--;
        !          1024:                     }
        !          1025:                 }
        !          1026:                 //
        !          1027:                 // See if the loop is actually finished
        !          1028:                 //
        !          1029:                 if (pClient->LoopCount == 0) {
        !          1030:                     pClient->LoopHead = NULL;
        !          1031:                 }
        !          1032: 
        !          1033:             }
        !          1034: 
        !          1035:             pWaveOvl = (PWAVEOVL)HeapAlloc(hHeap, 0, sizeof(*pWaveOvl));
        !          1036: 
        !          1037:             if (pWaveOvl == NULL) {
        !          1038:                 return MMSYSERR_NOMEM;
        !          1039:             }
        !          1040: 
        !          1041:             memset((PVOID)pWaveOvl, 0, sizeof(*pWaveOvl));
        !          1042: 
        !          1043:             pWaveOvl->WaveHdr = pHdr;
        !          1044: 
        !          1045:             if (pClient->DeviceType == WaveOutDevice) {
        !          1046:                 Result =  WriteFileEx(
        !          1047:                               pClient->hDev,
        !          1048:                                 (PBYTE)pHdr->lpData +        // Output buffer
        !          1049:                                     pClient->BufferPosition,
        !          1050:                               dwSize,
        !          1051:                               (LPOVERLAPPED)pWaveOvl,      // Overlap structure
        !          1052:                               pHdr->dwBufferLength !=
        !          1053:                                   pClient->BufferPosition + dwSize ?
        !          1054:                                   wavePartialOvl :
        !          1055:                                   NULL != pClient->LoopHead ?
        !          1056:                                       waveLoopOvl :
        !          1057:                                       waveOvl);            // Overlap callback
        !          1058:             } else {
        !          1059:                 Result =  ReadFileEx(
        !          1060:                               pClient->hDev,
        !          1061:                                 (PBYTE)pHdr->lpData +        // Output buffer
        !          1062:                                     pClient->BufferPosition,
        !          1063:                               dwSize,
        !          1064:                               (LPOVERLAPPED)pWaveOvl,      // Overlap structure
        !          1065:                               pHdr->dwBufferLength !=
        !          1066:                                   pClient->BufferPosition + dwSize ?
        !          1067:                                   wavePartialOvl :
        !          1068:                                   NULL != pClient->LoopHead ?
        !          1069:                                       waveLoopOvl :
        !          1070:                                       waveOvl);            // Overlap callback
        !          1071:             }
        !          1072: 
        !          1073:             dprintf3(("Sent %u wave bytes to device, return code %8X",
        !          1074:                      dwSize, GetLastError()));
        !          1075: 
        !          1076:             if (!Result && GetLastError() != ERROR_IO_PENDING) {
        !          1077: 
        !          1078:                         //
        !          1079:                         // Free the Iosb since we won't be getting any callbacks
        !          1080:                         //
        !          1081:                         HeapFree(hHeap, 0, (LPSTR)pWaveOvl);
        !          1082: 
        !          1083:                 //
        !          1084:                 // If the driver has not got any bytes outstanding then
        !          1085:                 // everything may grind to a halt so release everything
        !          1086:                 // here and notify 'completion' (ie mark all buffers
        !          1087:                 // complete).  This is unsatisfactory but there's no
        !          1088:                 // way of telling the application what happenend.
        !          1089:                 //
        !          1090: 
        !          1091:                 if (pClient->BytesOutstanding == 0) {
        !          1092: 
        !          1093:                     //
        !          1094:                     // This will cause acknowlegements to be made when
        !          1095:                     // waveCompleteBuffers is run
        !          1096:                     //
        !          1097:                     waveFreeQ(pClient);
        !          1098:                 }
        !          1099:                 return sndTranslateStatus();
        !          1100: 
        !          1101:             } else {
        !          1102:                 //
        !          1103:                 // We successfully queued the buffer
        !          1104:                 // Update our local data
        !          1105:                 //
        !          1106:                 pClient->BytesOutstanding += dwSize;
        !          1107:                 pClient->BufferPosition += dwSize;
        !          1108:                 if (pClient->BufferPosition == pHdr->dwBufferLength) {
        !          1109:                     //
        !          1110:                     // Finished this buffer - move on to the next
        !          1111:                     //
        !          1112:                     if (!pClient->LoopHead ||
        !          1113:                         !(pHdr->dwFlags & WHDR_ENDLOOP)) {
        !          1114:                         //
        !          1115:                         // Not end of in a loop so we can free this buffer
        !          1116:                         //
        !          1117:                         pClient->NextBuffer = pHdr->lpNext;
        !          1118: 
        !          1119:                     } else {
        !          1120:                         //
        !          1121:                         // Finished a loop
        !          1122:                         //
        !          1123:                         if (pClient->LoopCount != 0) {
        !          1124:                             pClient->LoopCount--;
        !          1125:                             pClient->NextBuffer = pClient->LoopHead;
        !          1126:                         } else {
        !          1127:                             //
        !          1128:                             // Someone's tried to kill us.  We have
        !          1129:                             // to 'chase out' the start of this loop
        !          1130:                             // so send a dummy (NULL) packet at the
        !          1131:                             // back of the driver's queue
        !          1132:                             //
        !          1133: 
        !          1134:                             pClient->DummyWaveOvl.WaveHdr = pClient->LoopHead;
        !          1135: 
        !          1136:                             Result =
        !          1137:                                 WriteFileEx(
        !          1138:                                     pClient->hDev,
        !          1139:                                     (PVOID)pHdr->lpData,
        !          1140:                                     0,
        !          1141:                                     &pClient->DummyWaveOvl.Ovl, // Static for async
        !          1142:                                     waveBreakOvl);
        !          1143: 
        !          1144:                             if (Result || GetLastError() == ERROR_IO_PENDING) {
        !          1145:                                 pClient->LoopHead = NULL; // Loop complete
        !          1146:                                 pClient->NextBuffer = pHdr->lpNext;
        !          1147:                             }
        !          1148:                         }
        !          1149:                     }
        !          1150:                     pClient->BufferPosition = 0;
        !          1151:                 }
        !          1152:             }
        !          1153:             {
        !          1154:             //    /* Before we go home, let's just touch ONE page - if there is one */
        !          1155:             //    PBYTE pb = (PBYTE)pHdr->lpData + pClient->BufferPosition;
        !          1156:             //    pb = ((DWORD)pb & 0xFFFFF000) + 0x1000;  /* find page start of next page */
        !          1157:             //
        !          1158:             //    if ( (PBYTE)pHdr->lpData + pHdr->dwBufferLength > pb )
        !          1159:             //        PreTouch( pb, 1, FALSE);
        !          1160: 
        !          1161:             //    /* Before we go home, let's just try to pre-touch that which we will soon want */
        !          1162:             //    PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
        !          1163:             //            , pHdr->dwBufferLength - pClient->BufferPosition
        !          1164:             //            , FALSE
        !          1165:             //            );
        !          1166:             }
        !          1167: 
        !          1168:         } else {
        !          1169:             //
        !          1170:             // Cannot fit any more bytes in at the moment
        !          1171:             //
        !          1172: 
        !          1173: //            /* Before we go home, let's just try to pre-touch that which we will soon want */
        !          1174: //            PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
        !          1175: //                    , pHdr->dwBufferLength - pClient->BufferPosition
        !          1176: //                    , FALSE
        !          1177: //                    );
        !          1178: 
        !          1179:             /* NOW go home! */
        !          1180:             break;
        !          1181:         }
        !          1182:     }
        !          1183:     return MMSYSERR_NOERROR;
        !          1184: }
        !          1185: 
        !          1186: 
        !          1187: /****************************************************************************
        !          1188:  * @doc INTERNAL
        !          1189:  *
        !          1190:  * @api void | waveCompleteBuffers | Buffer completion routine.  This completes
        !          1191:  *     the work of the Apc routine at below Apc priority.  This gets
        !          1192:  *     round the nasty situations arising when the user's callback
        !          1193:  *     causes more apcs to run (I strongly suspect this is a kernel
        !          1194:  *     bug).
        !          1195:  *
        !          1196:  * @parm PWAVEALLOC | pClient | The client's handle data
        !          1197:  *
        !          1198:  * @rdesc There is no return code.
        !          1199:  ***************************************************************************/
        !          1200: STATIC void waveCompleteBuffers(PWAVEALLOC pClient)
        !          1201: {
        !          1202:     //
        !          1203:     // Process buffers from the front of our queue unless we're in
        !          1204:     // a loop
        !          1205:     //
        !          1206: 
        !          1207:     while (pClient->DeviceQueue &&
        !          1208:            (pClient->DeviceQueue->dwFlags & WHDR_COMPLETE)) {
        !          1209: 
        !          1210:         PWAVEHDR pHdr;
        !          1211: 
        !          1212:         pHdr = pClient->DeviceQueue;
        !          1213:         //
        !          1214:         // Release buffer
        !          1215:         //
        !          1216:         pClient->DeviceQueue = pHdr->lpNext;
        !          1217: 
        !          1218: 
        !          1219:         //
        !          1220:         // Complete our buffer - note - this can cause another
        !          1221:         // buffer to be marked as complete if the client's
        !          1222:         // callback runs into an alertable wait.
        !          1223:         //
        !          1224: 
        !          1225:         waveBlockFinished(pHdr,
        !          1226:                           pClient->DeviceType == WaveOutDevice ?
        !          1227:                           WOM_DONE : WIM_DATA);
        !          1228:     }
        !          1229: 
        !          1230:     //
        !          1231:     // We might be able to start some more output at this point
        !          1232:     //
        !          1233: 
        !          1234:     waveStart(pClient);
        !          1235: }
        !          1236: 
        !          1237: 
        !          1238: /****************************************************************************
        !          1239:  * @doc INTERNAL
        !          1240:  *
        !          1241:  * @api void | waveFreeQ | Mark all outstanding buffers complete
        !          1242:  *
        !          1243:  * @parm PWAVEALLOC | pClient | The client's handle data
        !          1244:  *
        !          1245:  * @rdesc There is no return code.
        !          1246:  ***************************************************************************/
        !          1247: STATIC void waveFreeQ(PWAVEALLOC pClient)
        !          1248: {
        !          1249:     PWAVEHDR pHdr;
        !          1250:     for (pHdr = pClient->DeviceQueue;
        !          1251:          pHdr != NULL;
        !          1252:          pHdr = pHdr->lpNext) {
        !          1253:         pHdr->dwFlags |= WHDR_COMPLETE;
        !          1254:     }
        !          1255:         //
        !          1256:         // Tidy up next buffer
        !          1257:         //
        !          1258:         pClient->NextBuffer = NULL;
        !          1259:         pClient->BufferPosition = 0;
        !          1260: }
        !          1261: 
        !          1262: #if 0
        !          1263: typedef struct {
        !          1264:         LPBYTE Addr;
        !          1265:         DWORD  Len;
        !          1266: } PRETOUCHTHREADPARM;
        !          1267: 
        !          1268: /* asynchronous pre-toucher thread */
        !          1269: DWORD PreToucher(DWORD dw)
        !          1270: {
        !          1271:     PRETOUCHTHREADPARM * pttp;
        !          1272: 
        !          1273:     int iSize;
        !          1274:     BYTE * pb;
        !          1275: 
        !          1276:     pttp = (PRETOUCHTHREADPARM *) dw;
        !          1277:     iSize = pttp->Len;
        !          1278:     pb = pttp->Addr;
        !          1279: 
        !          1280:     LocalFree(pttp);
        !          1281: 
        !          1282:     while (iSize>0) {
        !          1283:         volatile BYTE b;
        !          1284:         b = *pb;
        !          1285:         pb += 4096;    // move to next page.  Are they ALWAYS 4096?
        !          1286:         iSize -= 4096; // and count it off
        !          1287:     }
        !          1288:     dprintf(("All pretouched!"));
        !          1289:     return 0;
        !          1290: }
        !          1291: #endif //0
        !          1292: 
        !          1293: /****************************************************************************
        !          1294:  * @doc INTERNAL
        !          1295:  *
        !          1296:  * @api DWORD | waveThread | Wave device auxiliary thread.
        !          1297:  *
        !          1298:  * @parm LPVOID | lpParameter | The thread parameter.  In our case this is a
        !          1299:  *     pointer to our wave device data.
        !          1300:  *
        !          1301:  * @rdesc Thread return code.
        !          1302:  ***************************************************************************/
        !          1303: STATIC DWORD waveThread(LPVOID lpParameter)
        !          1304: {
        !          1305:     PWAVEALLOC pClient;
        !          1306:     BOOL Terminate;
        !          1307: //  DWORD dwThread;                   // garbage
        !          1308: 
        !          1309: 
        !          1310:     Terminate = FALSE;
        !          1311: 
        !          1312:     pClient = (PWAVEALLOC)lpParameter;
        !          1313: 
        !          1314:     //
        !          1315:     // Set our thread to high priority so we don't fail to pass
        !          1316:     // new buffers to the device
        !          1317:     //
        !          1318: 
        !          1319:     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
        !          1320: 
        !          1321:     //
        !          1322:     // We start by waiting for something signalling that we've started
        !          1323:     // and waiting for something to do.
        !          1324:     //
        !          1325: 
        !          1326:     SetEvent(pClient->AuxEvent2);
        !          1327:     WaitForSingleObject(pClient->AuxEvent1, INFINITE);
        !          1328: 
        !          1329:     //
        !          1330:     // Now we're going
        !          1331:     //
        !          1332: 
        !          1333:     for (;;) {
        !          1334:         WinAssert(pClient->hDev != INVALID_HANDLE_VALUE);
        !          1335: 
        !          1336:         //
        !          1337:         // Decode function number to perform
        !          1338:         //
        !          1339: 
        !          1340:         switch (pClient->AuxFunction) {
        !          1341:         case WaveThreadAddBuffer:
        !          1342:             //
        !          1343:             // Intialize bytes recorded
        !          1344:             //
        !          1345:             if (pClient->DeviceType == WaveInDevice) {
        !          1346:                 pClient->AuxParam.pHdr->dwBytesRecorded = 0;
        !          1347:             }
        !          1348: 
        !          1349:             //
        !          1350:             // Add the buffer to our list
        !          1351:             //
        !          1352:             {
        !          1353:                 LPWAVEHDR *pHdrSearch;
        !          1354: 
        !          1355:                 pClient->AuxParam.pHdr->lpNext = NULL;
        !          1356: 
        !          1357:                 pHdrSearch = &pClient->DeviceQueue;
        !          1358:                 while (*pHdrSearch) {
        !          1359:                     pHdrSearch = &(*pHdrSearch)->lpNext;
        !          1360:                 }
        !          1361: 
        !          1362:                 *pHdrSearch = pClient->AuxParam.pHdr;
        !          1363:             }
        !          1364: //          {
        !          1365: //               PRETOUCHTHREADPARM * pttp;
        !          1366: //
        !          1367: //               pttp = LocalAlloc(LMEM_FIXED,8);
        !          1368: //
        !          1369: //               if (pttp!=NULL) {
        !          1370: //                   pttp->Addr = pClient->AuxParam.pHdr->lpData;
        !          1371: //                   pttp->Len = pClient->AuxParam.pHdr->dwBufferLength;
        !          1372: //                   CreateThread(NULL, 0, PreToucher, pttp, 0, &dwThread);
        !          1373: //               }
        !          1374: //          }
        !          1375: //          Would need to declutter the system by WAITing for dead threads at some point???
        !          1376: 
        !          1377:             //
        !          1378:             // See if we can send more to the driver
        !          1379:             //
        !          1380:             if (pClient->NextBuffer == NULL) {
        !          1381:                 pClient->NextBuffer = pClient->AuxParam.pHdr;
        !          1382:                 pClient->BufferPosition = 0;
        !          1383:             }
        !          1384: 
        !          1385: 
        !          1386: //            /* Before we waveStart, let's just try to pre-touch that which we will soon want */
        !          1387: //            {
        !          1388: //                PWAVEHDR pHdr = pClient->NextBuffer;
        !          1389: //                DWORD dwTick = GetTickCount();
        !          1390: //                PreTouch( (PBYTE)pHdr->lpData + pClient->BufferPosition
        !          1391: //                        , pHdr->dwBufferLength - pClient->BufferPosition
        !          1392: //                        , TRUE
        !          1393: //                        );
        !          1394: //                dprintf(("pre-touched out to limit. Took %d mSec", GetTickCount()-dwTick));
        !          1395: //            }
        !          1396: 
        !          1397:             pClient->AuxReturnCode = waveStart(pClient);
        !          1398:             break;
        !          1399: 
        !          1400:         case WaveThreadSetState:
        !          1401:             //
        !          1402:             // We have to make sure at least ONE buffer gets
        !          1403:             // completed if we're doing input and it's input.
        !          1404:             //
        !          1405: 
        !          1406: 
        !          1407: 
        !          1408:             //
        !          1409:             // Set Device state.  By issuing state changes on THIS
        !          1410:             // thread the calling thread can be sure that all Apc's
        !          1411:             // generated by buffer completions will complete
        !          1412:             // BEFORE this function completes.
        !          1413:             //
        !          1414: 
        !          1415:             pClient->AuxReturnCode =
        !          1416:                 waveSetState(pClient, pClient->AuxParam.State);
        !          1417: 
        !          1418: 
        !          1419:             //
        !          1420:             // Free the rest of our buffers if we're resetting
        !          1421:             //
        !          1422: 
        !          1423:             if (pClient->AuxParam.State == WAVE_DD_RESET) {
        !          1424:                 //
        !          1425:                 // Cancel any loops
        !          1426:                 //
        !          1427:                 pClient->LoopHead = NULL;
        !          1428: 
        !          1429:                 //
        !          1430:                 // This function must ALWAYS succeed
        !          1431:                 // Note that waveSetState closes the device on failure
        !          1432:                 //
        !          1433:                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
        !          1434: 
        !          1435:                 //
        !          1436:                 // Check this worked (even if the driver's OK the
        !          1437:                 // IO subsystem can fail)
        !          1438:                 //
        !          1439:                 WinAssert(pClient->BytesOutstanding == 0);
        !          1440: 
        !          1441:                 //
        !          1442:                 // Free all buffers
        !          1443:                 //
        !          1444:                 waveFreeQ(pClient);
        !          1445: 
        !          1446:             } else {
        !          1447:                 if (pClient->DeviceType == WaveInDevice &&
        !          1448:                     pClient->AuxReturnCode == MMSYSERR_NOERROR) {
        !          1449: 
        !          1450:                     if (pClient->AuxParam.State == WAVE_DD_STOP) {
        !          1451:                         //
        !          1452:                         // We're sort of stuck - we want to complete this
        !          1453:                         // buffer but we've got it tied up in the device
        !          1454:                         // We'll reset it here although this erroneously
        !          1455:                         // sets the position to 0
        !          1456:                         //
        !          1457:                         if (pClient->DeviceQueue) {
        !          1458:                             while (!(pClient->DeviceQueue->dwFlags & WHDR_COMPLETE) &&
        !          1459:                                    pClient->BytesOutstanding != 0) {
        !          1460:                                 waveSetState(pClient, WAVE_DD_RECORD);
        !          1461:                                 pClient->AuxReturnCode =
        !          1462:                                     waveSetState(pClient, WAVE_DD_STOP);
        !          1463:                                 if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
        !          1464:                                     break;
        !          1465:                                 }
        !          1466:                             }
        !          1467:                             if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
        !          1468:                                 pClient->DeviceQueue->dwFlags |= WHDR_COMPLETE;
        !          1469:                                                                 //
        !          1470:                                                                 // Tidy up next buffer
        !          1471:                                                                 //
        !          1472:                                                                 if (pClient->NextBuffer ==
        !          1473:                                                                     pClient->DeviceQueue) {
        !          1474:                                                                         pClient->NextBuffer =
        !          1475:                                                                             pClient->DeviceQueue->lpNext;
        !          1476:                                                                     pClient->BufferPosition = 0;
        !          1477:                                                             }
        !          1478:                             }
        !          1479:                         }
        !          1480:                     } else {
        !          1481:                         //
        !          1482:                         // If recording restore some buffers if necessary
        !          1483:                         //
        !          1484:                         if (pClient->AuxParam.State == WAVE_DD_RECORD) {
        !          1485:                             pClient->AuxReturnCode = waveStart(pClient);
        !          1486:                         }
        !          1487:                     }
        !          1488:                 }
        !          1489:             }
        !          1490:             break;
        !          1491: 
        !          1492:         case WaveThreadGetData:
        !          1493:             {
        !          1494:                 pClient->AuxReturnCode =
        !          1495:                     sndGetHandleData(pClient->hDev,
        !          1496:                                      pClient->AuxParam.GetSetData.DataLen,
        !          1497:                                      pClient->AuxParam.GetSetData.pData,
        !          1498:                                      pClient->AuxParam.GetSetData.Function,
        !          1499:                                      pClient->Event);
        !          1500:             }
        !          1501:             break;
        !          1502: 
        !          1503:         case WaveThreadSetData:
        !          1504:             {
        !          1505:                 pClient->AuxReturnCode =
        !          1506:                     sndSetHandleData(pClient->hDev,
        !          1507:                                      pClient->AuxParam.GetSetData.DataLen,
        !          1508:                                      pClient->AuxParam.GetSetData.pData,
        !          1509:                                      pClient->AuxParam.GetSetData.Function,
        !          1510:                                      pClient->Event);
        !          1511:             }
        !          1512:             break;
        !          1513: 
        !          1514:         case WaveThreadBreakLoop:
        !          1515:             if (pClient->LoopHead) {
        !          1516:                 //
        !          1517:                 // If we're in a loop then exit the loop at the
        !          1518:                 // end of the next iteration.
        !          1519:                 //
        !          1520: 
        !          1521:                 pClient->LoopCount = 0;
        !          1522:             }
        !          1523:             pClient->AuxReturnCode = MMSYSERR_NOERROR;
        !          1524:             break;
        !          1525: 
        !          1526:         case WaveThreadClose:
        !          1527:             //
        !          1528:             // Try to complete.
        !          1529:             // If we're completed all our buffers then we can.
        !          1530:             // otherwise we can't
        !          1531:             //
        !          1532:             if (pClient->DeviceQueue == NULL) {
        !          1533:                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
        !          1534:             } else {
        !          1535:                 pClient->AuxReturnCode = WAVERR_STILLPLAYING;
        !          1536:             }
        !          1537:             break;
        !          1538: 
        !          1539:         case WaveThreadTerminate:
        !          1540:             Terminate = TRUE;
        !          1541:             break;
        !          1542: 
        !          1543: 
        !          1544:         default:
        !          1545:             WinAssert(FALSE);   // Invalid call
        !          1546:             break;
        !          1547:         }
        !          1548:         //
        !          1549:         // Trap invalid callers
        !          1550:         //
        !          1551:         pClient->AuxFunction = WaveThreadInvalid;
        !          1552: 
        !          1553:                 //
        !          1554:                 // See if any Apcs need completing
        !          1555:                 //
        !          1556:                 waveCompleteBuffers(pClient);
        !          1557: 
        !          1558:         //
        !          1559:         // Complete ? - don't set the event here.
        !          1560:         //
        !          1561:         if (Terminate) {
        !          1562:             return 1;
        !          1563:         }
        !          1564: 
        !          1565:         //
        !          1566:         // Release the thread caller
        !          1567:         //
        !          1568:         SetEvent(pClient->AuxEvent2);
        !          1569: 
        !          1570:         //
        !          1571:         // Wait for more !
        !          1572:         //
        !          1573: 
        !          1574:         while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
        !          1575:                    WAIT_IO_COMPLETION) {
        !          1576:                 waveCompleteBuffers(pClient);
        !          1577:         }
        !          1578:     }
        !          1579: 
        !          1580:     return 1;      // Satisfy the compiler !
        !          1581: }
        !          1582: 
        !          1583: 
        !          1584: 
        !          1585: /****************************************************************************
        !          1586:  * @doc INTERNAL
        !          1587:  *
        !          1588:  * @api void | waveCallback | This calls DriverCallback for a WAVEHDR.
        !          1589:  *
        !          1590:  * @parm PWAVEALLOC | pWave | Pointer to wave device.
        !          1591:  *
        !          1592:  * @parm DWORD | msg | The message.
        !          1593:  *
        !          1594:  * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
        !          1595:  *
        !          1596:  * @rdesc There is no return value.
        !          1597:  ***************************************************************************/
        !          1598: void waveCallback(PWAVEALLOC pWave, DWORD msg, DWORD dw1)
        !          1599: {
        !          1600: 
        !          1601:     // invoke the callback function, if it exists.  dwFlags contains
        !          1602:     // wave driver specific flags in the LOWORD and generic driver
        !          1603:     // flags in the HIWORD
        !          1604: 
        !          1605:     if (pWave->dwCallback)
        !          1606:         DriverCallback(pWave->dwCallback,       // user's callback DWORD
        !          1607:                        HIWORD(pWave->dwFlags),  // callback flags
        !          1608:                        pWave->hWave,            // handle to the wave device
        !          1609:                        msg,                     // the message
        !          1610:                        pWave->dwInstance,       // user's instance data
        !          1611:                        dw1,                     // first DWORD
        !          1612:                        0L);                     // second DWORD
        !          1613: }
        !          1614: 
        !          1615: 
        !          1616: 
        !          1617: /****************************************************************************
        !          1618: 
        !          1619:     This function conforms to the standard Wave input driver message proc
        !          1620:     (widMessage), which is documented in mmddk.d.
        !          1621: 
        !          1622: ****************************************************************************/
        !          1623: DWORD APIENTRY widMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
        !          1624: {
        !          1625:     PWAVEALLOC pInClient;
        !          1626:     MMRESULT mRet;
        !          1627: 
        !          1628:     switch (msg) {
        !          1629: 
        !          1630:         case WIDM_GETNUMDEVS:
        !          1631:             D2(("WIDM_GETNUMDEVS"));
        !          1632:             return sndGetNumDevs(WaveInDevice);
        !          1633: 
        !          1634:         case WIDM_GETDEVCAPS:
        !          1635:             D2(("WIDM_GETDEVCAPS"));
        !          1636:             return waveGetDevCaps(id, WaveInDevice, (LPBYTE)dwParam1,
        !          1637:                                   (DWORD)dwParam2);
        !          1638: 
        !          1639:         case WIDM_OPEN:
        !          1640:             D2(("WIDM_OPEN"));
        !          1641:             return waveOpen(WaveInDevice, id, dwUser, dwParam1, dwParam2);
        !          1642: 
        !          1643:         case WIDM_CLOSE:
        !          1644:             D2(("WIDM_CLOSE"));
        !          1645:             pInClient = (PWAVEALLOC)dwUser;
        !          1646: 
        !          1647:             //
        !          1648:             // Call our task to see if it's ready to complete
        !          1649:             //
        !          1650:             mRet = waveThreadCall(WaveThreadClose, pInClient);
        !          1651:             if (mRet != MMSYSERR_NOERROR) {
        !          1652:                 return mRet;
        !          1653:             }
        !          1654: 
        !          1655:             waveCallback(pInClient, WIM_CLOSE, 0L);
        !          1656: 
        !          1657:             //
        !          1658:             // Close our device
        !          1659:             //
        !          1660:             if (pInClient->hDev != INVALID_HANDLE_VALUE) {
        !          1661:                 CloseHandle(pInClient->hDev);
        !          1662:                 EnterCriticalSection(&mmDrvCritSec);
        !          1663:                 pInClient->hDev = INVALID_HANDLE_VALUE;
        !          1664:                 LeaveCriticalSection(&mmDrvCritSec);
        !          1665:             }
        !          1666: 
        !          1667:             return MMSYSERR_NOERROR;
        !          1668: 
        !          1669:         case WIDM_ADDBUFFER:
        !          1670:             D2(("WIDM_ADDBUFFER"));
        !          1671:             WinAssert(dwParam1 != 0);
        !          1672:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)));
        !          1673: 
        !          1674:             ((LPWAVEHDR)dwParam1)->dwFlags &= (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED);
        !          1675: 
        !          1676:             WinAssert(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED);
        !          1677: 
        !          1678:             // check if it's been prepared
        !          1679:             if (!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED))
        !          1680:                 return WAVERR_UNPREPARED;
        !          1681: 
        !          1682:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE));
        !          1683: 
        !          1684:             // if it is already in our Q, then we cannot do this
        !          1685:             if ( ((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE )
        !          1686:                 return ( WAVERR_STILLPLAYING );
        !          1687: 
        !          1688:             // store the pointer to my WAVEALLOC structure in the wavehdr
        !          1689:             pInClient = (PWAVEALLOC)dwUser;
        !          1690:             ((LPWAVEHDR)dwParam1)->reserved = (DWORD)(LPSTR)pInClient;
        !          1691: 
        !          1692:             return waveWrite((LPWAVEHDR)dwParam1, pInClient);
        !          1693: 
        !          1694:         case WIDM_STOP:
        !          1695:             D2(("WIDM_PAUSE"));
        !          1696:             pInClient = (PWAVEALLOC)dwUser;
        !          1697:             pInClient->AuxParam.State = WAVE_DD_STOP;
        !          1698:             return waveThreadCall(WaveThreadSetState, pInClient);
        !          1699: 
        !          1700:         case WIDM_START:
        !          1701:             D2(("WIDM_RESTART"));
        !          1702:             pInClient = (PWAVEALLOC)dwUser;
        !          1703:             pInClient->AuxParam.State = WAVE_DD_RECORD;
        !          1704:             return waveThreadCall(WaveThreadSetState, pInClient);
        !          1705: 
        !          1706:         case WIDM_RESET:
        !          1707:             D2(("WIDM_RESET"));
        !          1708:             pInClient = (PWAVEALLOC)dwUser;
        !          1709:             pInClient->AuxParam.State = WAVE_DD_RESET;
        !          1710:             return waveThreadCall(WaveThreadSetState, pInClient);
        !          1711: 
        !          1712:         case WIDM_GETPOS:
        !          1713:             D2(("WIDM_GETPOS"));
        !          1714:             pInClient = (PWAVEALLOC)dwUser;
        !          1715:             return waveGetPos(pInClient, (LPMMTIME)dwParam1, dwParam2);
        !          1716: 
        !          1717:         default:
        !          1718:             return MMSYSERR_NOTSUPPORTED;
        !          1719:     }
        !          1720: 
        !          1721:     //
        !          1722:     // Should not get here
        !          1723:     //
        !          1724: 
        !          1725:     WinAssert(0);
        !          1726:     return MMSYSERR_NOTSUPPORTED;
        !          1727: }
        !          1728: 
        !          1729: /****************************************************************************
        !          1730: 
        !          1731:     This function conforms to the standard Wave output driver message proc
        !          1732:     (wodMessage), which is documented in mmddk.h.
        !          1733: 
        !          1734: ****************************************************************************/
        !          1735: DWORD APIENTRY wodMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
        !          1736: {
        !          1737:     PWAVEALLOC pOutClient;
        !          1738:     MMRESULT mRet;
        !          1739: 
        !          1740:     switch (msg) {
        !          1741:         case WODM_GETNUMDEVS:
        !          1742:             D2(("WODM_GETNUMDEVS"));
        !          1743:             return sndGetNumDevs(WaveOutDevice);
        !          1744: 
        !          1745:         case WODM_GETDEVCAPS:
        !          1746:             D2(("WODM_GETDEVCAPS"));
        !          1747:             return waveGetDevCaps(id, WaveOutDevice, (LPBYTE)dwParam1,
        !          1748:                                   (DWORD)dwParam2);
        !          1749: 
        !          1750:         case WODM_OPEN:
        !          1751:             D2(("WODM_OPEN"));
        !          1752:             return waveOpen(WaveOutDevice, id, dwUser, dwParam1, dwParam2);
        !          1753: 
        !          1754:         case WODM_CLOSE:
        !          1755:             D2(("WODM_CLOSE"));
        !          1756:             pOutClient = (PWAVEALLOC)dwUser;
        !          1757: 
        !          1758:             //
        !          1759:             // Call our task to see if it's ready to complete
        !          1760:             //
        !          1761:             mRet = waveThreadCall(WaveThreadClose, pOutClient);
        !          1762:             if (mRet != MMSYSERR_NOERROR) {
        !          1763:                 return mRet;
        !          1764:             }
        !          1765: 
        !          1766:             waveCallback(pOutClient, WOM_CLOSE, 0L);
        !          1767: 
        !          1768:             //
        !          1769:             // Close our device
        !          1770:             //
        !          1771:             if (pOutClient->hDev != INVALID_HANDLE_VALUE) {
        !          1772:                 CloseHandle(pOutClient->hDev);
        !          1773: 
        !          1774:                 EnterCriticalSection(&mmDrvCritSec);
        !          1775:                 pOutClient->hDev = INVALID_HANDLE_VALUE;
        !          1776:                 LeaveCriticalSection(&mmDrvCritSec);
        !          1777:             }
        !          1778: 
        !          1779:             return MMSYSERR_NOERROR;
        !          1780: 
        !          1781:         case WODM_WRITE:
        !          1782:             D2(("WODM_WRITE"));
        !          1783:             WinAssert(dwParam1 != 0);
        !          1784:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags &
        !          1785:                      ~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|
        !          1786:                        WHDR_BEGINLOOP|WHDR_ENDLOOP)));
        !          1787: 
        !          1788:             ((LPWAVEHDR)dwParam1)->dwFlags &=
        !          1789:                 (WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|
        !          1790:                  WHDR_BEGINLOOP|WHDR_ENDLOOP);
        !          1791: 
        !          1792:             WinAssert(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED);
        !          1793: 
        !          1794:             // check if it's been prepared
        !          1795:             if (!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_PREPARED))
        !          1796:                 return WAVERR_UNPREPARED;
        !          1797: 
        !          1798:             WinAssert(!(((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE));
        !          1799: 
        !          1800:             // if it is already in our Q, then we cannot do this
        !          1801:             if ( ((LPWAVEHDR)dwParam1)->dwFlags & WHDR_INQUEUE )
        !          1802:                 return ( WAVERR_STILLPLAYING );
        !          1803: 
        !          1804:             // store the pointer to my WAVEALLOC structure in the wavehdr
        !          1805:             pOutClient = (PWAVEALLOC)dwUser;
        !          1806:             ((LPWAVEHDR)dwParam1)->reserved = (DWORD)(LPSTR)pOutClient;
        !          1807: 
        !          1808:             return waveWrite((LPWAVEHDR)dwParam1, pOutClient);
        !          1809: 
        !          1810: 
        !          1811:         case WODM_PAUSE:
        !          1812:             D2(("WODM_PAUSE"));
        !          1813:             pOutClient = (PWAVEALLOC)dwUser;
        !          1814:             pOutClient->AuxParam.State = WAVE_DD_STOP;
        !          1815:             return waveThreadCall(WaveThreadSetState, pOutClient);
        !          1816: 
        !          1817:         case WODM_RESTART:
        !          1818:             D2(("WODM_RESTART"));
        !          1819:             pOutClient = (PWAVEALLOC)dwUser;
        !          1820:             pOutClient->AuxParam.State = WAVE_DD_PLAY;
        !          1821:             return waveThreadCall(WaveThreadSetState, pOutClient);
        !          1822: 
        !          1823:         case WODM_RESET:
        !          1824:             D2(("WODM_RESET"));
        !          1825:             pOutClient = (PWAVEALLOC)dwUser;
        !          1826:             pOutClient->AuxParam.State = WAVE_DD_RESET;
        !          1827:             return waveThreadCall(WaveThreadSetState, pOutClient);
        !          1828: 
        !          1829:         case WODM_BREAKLOOP:
        !          1830:             pOutClient = (PWAVEALLOC)dwUser;
        !          1831:             D2(("WODM_BREAKLOOP"));
        !          1832:             return waveThreadCall(WaveThreadBreakLoop, pOutClient);
        !          1833: 
        !          1834: 
        !          1835:         case WODM_GETPOS:
        !          1836:             D2(("WODM_GETPOS"));
        !          1837:             pOutClient = (PWAVEALLOC)dwUser;
        !          1838:             return waveGetPos(pOutClient, (LPMMTIME)dwParam1, dwParam2);
        !          1839: 
        !          1840:         case WODM_SETPITCH:
        !          1841:             D2(("WODM_SETPITCH"));
        !          1842:             pOutClient = (PWAVEALLOC)dwUser;
        !          1843:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1844:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1845:             pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PITCH;
        !          1846:             return waveThreadCall(WaveThreadSetData, pOutClient);
        !          1847: 
        !          1848:         case WODM_SETVOLUME:
        !          1849:             D2(("WODM_SETVOLUME"));
        !          1850:             //pOutClient = (PWAVEALLOC)dwUser;
        !          1851:             //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1852:             //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1853:             //pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_VOLUME;
        !          1854:             //return waveThreadCall(WaveThreadSetData, pOutClient);
        !          1855: 
        !          1856:             {
        !          1857:                 //
        !          1858:                 // Translate to device volume structure
        !          1859:                 //
        !          1860: 
        !          1861:                 WAVE_DD_VOLUME Volume;
        !          1862:                 Volume.Left = LOWORD(dwParam1) << 16;
        !          1863:                 Volume.Right = HIWORD(dwParam1) << 16;
        !          1864: 
        !          1865:                 return sndSetData(WaveOutDevice, id, sizeof(Volume),
        !          1866:                                   (PBYTE)&Volume, IOCTL_WAVE_SET_VOLUME);
        !          1867:             }
        !          1868: 
        !          1869: 
        !          1870:         case WODM_SETPLAYBACKRATE:
        !          1871:             D2(("WODM_SETPLAYBACKRATE"));
        !          1872:             pOutClient = (PWAVEALLOC)dwUser;
        !          1873:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1874:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1875:             pOutClient->AuxParam.GetSetData.Function =
        !          1876:                 IOCTL_WAVE_SET_PLAYBACK_RATE;
        !          1877:             return waveThreadCall(WaveThreadSetData, pOutClient);
        !          1878: 
        !          1879:         case WODM_GETPITCH:
        !          1880:             D2(("WODM_GETPITCH"));
        !          1881:             pOutClient = (PWAVEALLOC)dwUser;
        !          1882:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1883:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1884:             pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PITCH;
        !          1885:             return waveThreadCall(WaveThreadGetData, pOutClient);
        !          1886: 
        !          1887:         case WODM_GETVOLUME:
        !          1888:             D2(("WODM_GETVOLUME"));
        !          1889:             //pOutClient = (PWAVEALLOC)dwUser;
        !          1890:             //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1891:             //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1892:             //pOutClient->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_VOLUME;
        !          1893:             //return waveThreadCall(WaveThreadGetData, pOutClient);
        !          1894: 
        !          1895:             {
        !          1896:                 //
        !          1897:                 // Translate to device volume structure
        !          1898:                 //
        !          1899: 
        !          1900:                 WAVE_DD_VOLUME Volume;
        !          1901:                 DWORD rc;
        !          1902: 
        !          1903:                 rc = sndGetData(WaveOutDevice, id, sizeof(Volume),
        !          1904:                                 (PBYTE)&Volume, IOCTL_WAVE_GET_VOLUME);
        !          1905: 
        !          1906:                 if (rc == MMSYSERR_NOERROR) {
        !          1907:                     *(LPDWORD)dwParam1 =
        !          1908:                         (DWORD)MAKELONG(HIWORD(Volume.Left),
        !          1909:                                         HIWORD(Volume.Right));
        !          1910:                 }
        !          1911: 
        !          1912:                 return rc;
        !          1913:             }
        !          1914: 
        !          1915:         case WODM_GETPLAYBACKRATE:
        !          1916:             D2(("WODM_GETPLAYBACKRATE"));
        !          1917:             pOutClient = (PWAVEALLOC)dwUser;
        !          1918:             pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1919:             pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1920:             pOutClient->AuxParam.GetSetData.Function =
        !          1921:                 IOCTL_WAVE_GET_PLAYBACK_RATE;
        !          1922:             return waveThreadCall(WaveThreadGetData, pOutClient);
        !          1923: 
        !          1924:         default:
        !          1925:             return MMSYSERR_NOTSUPPORTED;
        !          1926:     }
        !          1927: 
        !          1928:     //
        !          1929:     // Should not get here
        !          1930:     //
        !          1931: 
        !          1932:     WinAssert(0);
        !          1933:     return MMSYSERR_NOTSUPPORTED;
        !          1934: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.