|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.