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.

2025 lines
65 KiB

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