Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1937 lines
62 KiB

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