|
|
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.