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.

869 lines
26 KiB

  1. /****************************************************************************
  2. *
  3. * wavein.c
  4. *
  5. * WDM Audio support for Wave Input devices
  6. *
  7. * Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  8. *
  9. * History
  10. * 5-12-97 - Noel Cross (NoelC)
  11. *
  12. ***************************************************************************/
  13. #include "wdmdrv.h"
  14. #ifndef UNDER_NT
  15. #pragma alloc_text(FIXCODE, waveCallback)
  16. #endif
  17. /****************************************************************************
  18. This function conforms to the standard Wave input driver message proc
  19. (widMessage), which is documented in mmddk.d.
  20. ****************************************************************************/
  21. DWORD FAR PASCAL _loadds widMessage
  22. (
  23. UINT id,
  24. UINT msg,
  25. DWORD_PTR dwUser,
  26. DWORD_PTR dwParam1,
  27. DWORD_PTR dwParam2
  28. )
  29. {
  30. LPDEVICEINFO pInClient;
  31. LPDEVICEINFO pDeviceInfo;
  32. LPWAVEHDR lpWaveHdr;
  33. MMRESULT mmr;
  34. switch (msg)
  35. {
  36. case WIDM_INIT:
  37. DPF(DL_TRACE|FA_WAVE, ("WIDM_INIT") );
  38. return(wdmaudAddRemoveDevNode(WaveInDevice, (LPCWSTR)dwParam2, TRUE));
  39. case DRVM_EXIT:
  40. DPF(DL_TRACE|FA_WAVE, ("DRVM_EXIT WaveIn") );
  41. return(wdmaudAddRemoveDevNode(WaveInDevice, (LPCWSTR)dwParam2, FALSE));
  42. case WIDM_GETNUMDEVS:
  43. DPF(DL_TRACE|FA_WAVE, ("WIDM_GETNUMDEVS") );
  44. return wdmaudGetNumDevs(WaveInDevice, (LPCWSTR)dwParam1);
  45. case WIDM_GETDEVCAPS:
  46. DPF(DL_TRACE|FA_WAVE, ("WIDM_GETDEVCAPS") );
  47. if (pDeviceInfo = GlobalAllocDeviceInfo((LPCWSTR)dwParam2))
  48. {
  49. pDeviceInfo->DeviceType = WaveInDevice;
  50. pDeviceInfo->DeviceNumber = id;
  51. mmr = wdmaudGetDevCaps(pDeviceInfo, (MDEVICECAPSEX FAR*)dwParam1);
  52. GlobalFreeDeviceInfo(pDeviceInfo);
  53. return mmr;
  54. } else {
  55. MMRRETURN( MMSYSERR_NOMEM );
  56. }
  57. case WIDM_PREFERRED:
  58. DPF(DL_TRACE|FA_WAVE, ("WIDM_PREFERRED") );
  59. return wdmaudSetPreferredDevice(
  60. WaveInDevice,
  61. id,
  62. dwParam1,
  63. dwParam2);
  64. case WIDM_OPEN:
  65. {
  66. LPWAVEOPENDESC pwod = (LPWAVEOPENDESC)dwParam1;
  67. if( (mmr=IsValidWaveOpenDesc(pwod)) != MMSYSERR_NOERROR )
  68. {
  69. MMRRETURN( mmr );
  70. }
  71. DPF(DL_TRACE|FA_WAVE, ("WIDM_OPEN") );
  72. if (pDeviceInfo = GlobalAllocDeviceInfo((LPCWSTR)pwod->dnDevNode))
  73. {
  74. pDeviceInfo->DeviceType = WaveInDevice;
  75. pDeviceInfo->DeviceNumber = id;
  76. mmr = waveOpen(pDeviceInfo, dwUser, pwod, (DWORD)dwParam2);
  77. GlobalFreeDeviceInfo(pDeviceInfo);
  78. return mmr;
  79. } else {
  80. MMRRETURN( MMSYSERR_NOMEM );
  81. }
  82. }
  83. case WIDM_CLOSE:
  84. DPF(DL_TRACE|FA_WAVE, ("WIDM_CLOSE") );
  85. pInClient = (LPDEVICEINFO)dwUser;
  86. //
  87. // At this point, we've committed to closing down this DeviceInfo.
  88. // We mark the DeviceState as closing and hope for the best! If
  89. // someone calls WIDM_ADDBUFFER while we're in this state, we've got
  90. // problems!
  91. //
  92. if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR ) ||
  93. ( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR ) )
  94. {
  95. MMRRETURN( mmr );
  96. }
  97. mmr = wdmaudCloseDev(pInClient);
  98. if (MMSYSERR_NOERROR == mmr)
  99. {
  100. waveCallback(pInClient, WIM_CLOSE, 0L);
  101. ISVALIDDEVICEINFO(pInClient);
  102. ISVALIDDEVICESTATE(pInClient->DeviceState,FALSE);
  103. waveCleanUp(pInClient);
  104. }
  105. return mmr;
  106. case WIDM_ADDBUFFER:
  107. DPF(DL_TRACE|FA_WAVE, ("WIDM_ADDBUFFER") );
  108. lpWaveHdr = (LPWAVEHDR)dwParam1;
  109. pInClient = (LPDEVICEINFO)dwUser;
  110. //
  111. // Perform our asserts
  112. //
  113. if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR ) ||
  114. ( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR ) ||
  115. ( (mmr=IsValidWaveHeader(lpWaveHdr)) != MMSYSERR_NOERROR ) )
  116. {
  117. MMRRETURN( mmr );
  118. }
  119. // sanity check on the wavehdr
  120. DPFASSERT(lpWaveHdr != NULL);
  121. if (lpWaveHdr == NULL)
  122. MMRRETURN( MMSYSERR_INVALPARAM );
  123. // check if it's been prepared
  124. DPFASSERT(lpWaveHdr->dwFlags & WHDR_PREPARED);
  125. if (!(lpWaveHdr->dwFlags & WHDR_PREPARED))
  126. MMRRETURN( WAVERR_UNPREPARED );
  127. // if it is already in our Q, then we cannot do this
  128. DPFASSERT(!(lpWaveHdr->dwFlags & WHDR_INQUEUE));
  129. if ( lpWaveHdr->dwFlags & WHDR_INQUEUE )
  130. MMRRETURN( WAVERR_STILLPLAYING );
  131. //
  132. // Put the request at the end of our queue.
  133. //
  134. return waveWrite(pInClient, lpWaveHdr);
  135. case WIDM_STOP:
  136. DPF(DL_TRACE|FA_WAVE, ("WIDM_STOP") );
  137. pInClient = (LPDEVICEINFO)dwUser;
  138. return wdmaudSetDeviceState(pInClient,
  139. IOCTL_WDMAUD_WAVE_IN_STOP);
  140. case WIDM_START:
  141. DPF(DL_TRACE|FA_WAVE, ("WIDM_START") );
  142. pInClient = (LPDEVICEINFO)dwUser;
  143. return wdmaudSetDeviceState(pInClient,
  144. IOCTL_WDMAUD_WAVE_IN_RECORD);
  145. case WIDM_RESET:
  146. DPF(DL_TRACE|FA_WAVE, ("WIDM_RESET") );
  147. pInClient = (LPDEVICEINFO)dwUser;
  148. return wdmaudSetDeviceState(pInClient,
  149. IOCTL_WDMAUD_WAVE_IN_RESET);
  150. case WIDM_GETPOS:
  151. DPF(DL_TRACE|FA_WAVE, ("WIDM_GETPOS") );
  152. pInClient = (LPDEVICEINFO)dwUser;
  153. if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR) ||
  154. ( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR) )
  155. {
  156. MMRRETURN( mmr );
  157. }
  158. return wdmaudGetPos(pInClient,
  159. (LPMMTIME)dwParam1,
  160. (DWORD)dwParam2,
  161. WaveInDevice);
  162. #ifdef UNDER_NT
  163. case WIDM_PREPARE:
  164. DPF(DL_TRACE|FA_WAVE, ("WIDM_PREPARE") );
  165. pInClient = (LPDEVICEINFO)dwUser;
  166. if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR) ||
  167. ( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR) )
  168. {
  169. MMRRETURN( mmr );
  170. }
  171. return wdmaudPrepareWaveHeader(pInClient, (LPWAVEHDR)dwParam1);
  172. case WIDM_UNPREPARE:
  173. DPF(DL_TRACE|FA_WAVE, ("WIDM_UNPREPARE") );
  174. pInClient = (LPDEVICEINFO)dwUser;
  175. if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR) ||
  176. ( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR) )
  177. {
  178. MMRRETURN( mmr );
  179. }
  180. return wdmaudUnprepareWaveHeader(pInClient, (LPWAVEHDR)dwParam1);
  181. #endif
  182. default:
  183. MMRRETURN( MMSYSERR_NOTSUPPORTED );
  184. }
  185. //
  186. // Should not get here
  187. //
  188. DPFASSERT(0);
  189. MMRRETURN( MMSYSERR_NOTSUPPORTED );
  190. }
  191. /****************************************************************************
  192. * @doc INTERNAL
  193. *
  194. * @api void | waveCallback | This calls DriverCallback for a WAVEHDR.
  195. *
  196. * @parm LPDEVICEINFO | pWave | Pointer to wave device.
  197. *
  198. * @parm DWORD | msg | The message.
  199. *
  200. * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
  201. *
  202. * @rdesc There is no return value.
  203. ***************************************************************************/
  204. VOID FAR waveCallback
  205. (
  206. LPDEVICEINFO pWave,
  207. UINT msg,
  208. DWORD_PTR dw1
  209. )
  210. {
  211. // invoke the callback function, if it exists. dwFlags contains
  212. // wave driver specific flags in the LOWORD and generic driver
  213. // flags in the HIWORD
  214. if (pWave->dwCallback)
  215. DriverCallback(pWave->dwCallback, // user's callback DWORD
  216. HIWORD(pWave->dwFlags), // callback flags
  217. (HDRVR)pWave->DeviceHandle, // handle to the wave device
  218. msg, // the message
  219. pWave->dwInstance, // user's instance data
  220. dw1, // first DWORD
  221. 0L); // second DWORD
  222. }
  223. /****************************************************************************
  224. * @doc INTERNAL
  225. *
  226. * @api MMRESULT | waveOpen | Open wave device and set up logical device data
  227. *
  228. * @parm LPDEVICEINFO | DeviceInfo | Specifies if it's a wave input or output
  229. * device
  230. *
  231. * @parm DWORD | dwUser | Input parameter to wodMessage - pointer to
  232. * application's handle (generated by this routine)
  233. *
  234. * @parm LPWAVEOPENDESC | pwod | pointer to WAVEOPENDESC. Was dwParam1
  235. * parameter to wodMessage
  236. *
  237. * @parm DWORD | dwParam2 | Input parameter to wodMessage
  238. *
  239. * @rdesc wodMessage return code.
  240. ***************************************************************************/
  241. MMRESULT waveOpen
  242. (
  243. LPDEVICEINFO DeviceInfo,
  244. DWORD_PTR dwUser,
  245. LPWAVEOPENDESC pwod,
  246. DWORD dwParam2
  247. )
  248. {
  249. LPDEVICEINFO pClient; // pointer to client information structure
  250. MMRESULT mmr;
  251. #ifndef UNDER_NT
  252. DWORD dwCallback16;
  253. #endif
  254. //
  255. // allocate my per-client structure
  256. //
  257. pClient = GlobalAllocDeviceInfo(DeviceInfo->wstrDeviceInterface);
  258. if (NULL == pClient)
  259. {
  260. MMRRETURN( MMSYSERR_NOMEM );
  261. }
  262. pClient->DeviceState = (LPVOID) GlobalAllocPtr( GPTR, sizeof( DEVICESTATE ) );
  263. if (NULL == pClient->DeviceState)
  264. {
  265. GlobalFreeDeviceInfo( pClient );
  266. MMRRETURN( MMSYSERR_NOMEM );
  267. }
  268. //
  269. // Handle the query case and return early
  270. //
  271. if (WAVE_FORMAT_QUERY & dwParam2)
  272. {
  273. pClient->DeviceType = DeviceInfo->DeviceType;
  274. pClient->DeviceNumber = DeviceInfo->DeviceNumber;
  275. pClient->dwFlags = dwParam2;
  276. mmr = wdmaudOpenDev( pClient, (LPWAVEFORMATEX)pwod->lpFormat );
  277. if (mmr == MMSYSERR_NOTSUPPORTED)
  278. {
  279. mmr = WAVERR_BADFORMAT;
  280. }
  281. GlobalFreePtr( pClient->DeviceState );
  282. GlobalFreeDeviceInfo( pClient );
  283. return mmr;
  284. }
  285. #ifdef UNDER_NT
  286. //
  287. // Allocate memory for our critical section
  288. //
  289. pClient->DeviceState->csQueue = (LPVOID) GlobalAllocPtr( GPTR, sizeof( CRITICAL_SECTION ) );
  290. if (NULL == pClient->DeviceState->csQueue)
  291. {
  292. GlobalFreePtr( pClient->DeviceState );
  293. GlobalFreeDeviceInfo( pClient );
  294. MMRRETURN( MMSYSERR_NOMEM );
  295. }
  296. try
  297. {
  298. InitializeCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
  299. }
  300. except(EXCEPTION_EXECUTE_HANDLER)
  301. {
  302. GlobalFreePtr( pClient->DeviceState->csQueue );
  303. GlobalFreePtr( pClient->DeviceState );
  304. GlobalFreeDeviceInfo( pClient );
  305. MMRRETURN( MMSYSERR_NOMEM );
  306. }
  307. #endif
  308. //
  309. // fill out context data
  310. //
  311. pClient->DeviceNumber= DeviceInfo->DeviceNumber;
  312. pClient->DeviceType = DeviceInfo->DeviceType;
  313. pClient->dwInstance = pwod->dwInstance;
  314. pClient->dwCallback = pwod->dwCallback;
  315. pClient->dwFlags = dwParam2;
  316. #ifdef UNDER_NT
  317. pClient->DeviceHandle= (HANDLE32)pwod->hWave;
  318. #else
  319. pClient->DeviceHandle= (HANDLE32)MAKELONG(pwod->hWave,0);
  320. _asm
  321. {
  322. mov ax, offset WaveDeviceCallback
  323. mov word ptr [dwCallback16], ax
  324. mov ax, seg WaveDeviceCallback
  325. mov word ptr [dwCallback16+2], ax
  326. }
  327. pClient->dwCallback16= dwCallback16;
  328. #endif
  329. //
  330. // initialize the device state
  331. //
  332. pClient->DeviceState->lpWaveQueue = NULL;
  333. pClient->DeviceState->fRunning = FALSE;
  334. pClient->DeviceState->fExit = FALSE;
  335. if (pClient->DeviceType == WaveOutDevice)
  336. pClient->DeviceState->fPaused = FALSE;
  337. else
  338. pClient->DeviceState->fPaused = TRUE;
  339. #ifdef DEBUG
  340. pClient->DeviceState->dwSig = DEVICESTATE_SIGNATURE;
  341. #endif
  342. //
  343. // See if we can open our device
  344. //
  345. mmr = wdmaudOpenDev( pClient, (LPWAVEFORMATEX)pwod->lpFormat );
  346. if (mmr != MMSYSERR_NOERROR)
  347. {
  348. if (mmr == MMSYSERR_NOTSUPPORTED)
  349. {
  350. mmr = WAVERR_BADFORMAT;
  351. }
  352. #ifdef UNDER_NT
  353. DeleteCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
  354. GlobalFreePtr( pClient->DeviceState->csQueue );
  355. //
  356. // explicitly clear these values! We don't want to ever see these set
  357. // again!
  358. //
  359. pClient->DeviceState->csQueue=NULL;
  360. #endif
  361. GlobalFreePtr( pClient->DeviceState );
  362. pClient->DeviceState=NULL;
  363. GlobalFreeDeviceInfo( pClient );
  364. pClient=NULL;
  365. MMRRETURN( mmr );
  366. }
  367. //
  368. // Add instance to chain of devices
  369. //
  370. EnterCriticalSection(&wdmaudCritSec);
  371. pClient->Next = pWaveDeviceList;
  372. pWaveDeviceList = pClient;
  373. LeaveCriticalSection(&wdmaudCritSec);
  374. //
  375. // give the client my driver dw
  376. //
  377. {
  378. LPDEVICEINFO FAR *pUserHandle;
  379. pUserHandle = (LPDEVICEINFO FAR *)dwUser;
  380. *pUserHandle = pClient;
  381. }
  382. //
  383. // sent client his OPEN callback message
  384. //
  385. waveCallback(pClient, DeviceInfo->DeviceType == WaveOutDevice ? WOM_OPEN : WIM_OPEN, 0L);
  386. return MMSYSERR_NOERROR;
  387. }
  388. /****************************************************************************
  389. * @doc INTERNAL
  390. *
  391. * @api void | waveCleanUp | Free resources for a wave device
  392. *
  393. * @parm LPWAVEALLOC | pClient | Pointer to a WAVEALLOC structure describing
  394. * resources to be freed.
  395. *
  396. * @rdesc There is no return value.
  397. *
  398. * @comm If the pointer to the resource is NULL then the resource has not
  399. * been allocated.
  400. ***************************************************************************/
  401. VOID waveCleanUp
  402. (
  403. LPDEVICEINFO pClient
  404. )
  405. {
  406. LPDEVICEINFO FAR *ppCur ;
  407. //
  408. // remove from device chain
  409. //
  410. EnterCriticalSection(&wdmaudCritSec);
  411. for (ppCur = &pWaveDeviceList;
  412. *ppCur != NULL;
  413. ppCur = &(*ppCur)->Next)
  414. {
  415. if (*ppCur == pClient)
  416. {
  417. *ppCur = (*ppCur)->Next;
  418. break;
  419. }
  420. }
  421. LeaveCriticalSection(&wdmaudCritSec);
  422. #ifdef UNDER_NT
  423. DeleteCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
  424. GlobalFreePtr( pClient->DeviceState->csQueue );
  425. #endif
  426. #ifdef DEBUG
  427. //
  428. // In debug, let's set all the values in the DEVICESTATE structure to bad
  429. // values.
  430. //
  431. pClient->DeviceState->cSampleBits=0xDEADBEEF;
  432. pClient->DeviceState->hThread=NULL;
  433. pClient->DeviceState->dwThreadId=0xDEADBEEF;
  434. pClient->DeviceState->lpWaveQueue=NULL;
  435. pClient->DeviceState->csQueue=NULL;
  436. pClient->DeviceState->hevtQueue=NULL;
  437. pClient->DeviceState->hevtExitThread=NULL;
  438. #endif
  439. GlobalFreePtr( pClient->DeviceState );
  440. pClient->DeviceState=NULL;
  441. #ifdef DEBUG
  442. //
  443. // Now set all the values in the DEVICEINFO structure to bad values.
  444. //
  445. // pClient->Next=(LPDEVICEINFO)0xDEADBEEF;
  446. pClient->DeviceNumber=-1;
  447. pClient->DeviceType=0xDEADBEEF;
  448. pClient->DeviceHandle=NULL;
  449. pClient->dwInstance=(DWORD_PTR)NULL;
  450. pClient->dwCallback=(DWORD_PTR)NULL;
  451. pClient->dwCallback16=0xDEADBEEF;
  452. pClient->dwFlags=0xDEADBEEF;
  453. pClient->DataBuffer=NULL;
  454. pClient->HardwareCallbackEventHandle=NULL;
  455. pClient->dwCallbackType=0xDEADBEEF;
  456. pClient->dwLineID=0xDEADBEEF;
  457. pClient->dwFormat=0xDEADBEEF;
  458. // pClient->DeviceState=(LPDEVICESTATE)0xDEADBEEF;
  459. #endif
  460. GlobalFreeDeviceInfo( pClient ) ;
  461. pClient=NULL;
  462. DPF(DL_TRACE|FA_WAVE,("DeviceState gone!") );
  463. }
  464. #ifdef UNDER_NT
  465. /****************************************************************************
  466. * @doc INTERNAL
  467. *
  468. * @api MMRESULT | wdmaudPrepareWaveHeader |
  469. *
  470. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical wave
  471. * device.
  472. *
  473. * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
  474. *
  475. * @rdesc A MMSYS... type return code for the application.
  476. *
  477. ***************************************************************************/
  478. MMRESULT wdmaudPrepareWaveHeader
  479. (
  480. LPDEVICEINFO DeviceInfo,
  481. LPWAVEHDR pHdr
  482. )
  483. {
  484. PWAVEPREPAREDATA pWavePrepareData;
  485. DPFASSERT(pHdr);
  486. pHdr->lpNext = NULL;
  487. pHdr->reserved = (DWORD_PTR)NULL;
  488. //
  489. // Allocate memory for the prepared header instance data
  490. //
  491. pWavePrepareData = (PWAVEPREPAREDATA) GlobalAllocPtr( GPTR, sizeof(*pWavePrepareData));
  492. if (pWavePrepareData == NULL)
  493. {
  494. MMRRETURN( MMSYSERR_NOMEM );
  495. }
  496. //
  497. // Allocate memory for our overlapped structure
  498. //
  499. pWavePrepareData->pOverlapped =
  500. (LPOVERLAPPED)HeapAlloc( GetProcessHeap(), 0, sizeof( OVERLAPPED ));
  501. if (NULL == pWavePrepareData->pOverlapped)
  502. {
  503. GlobalFreePtr( pWavePrepareData );
  504. MMRRETURN( MMSYSERR_NOMEM );
  505. }
  506. RtlZeroMemory( pWavePrepareData->pOverlapped, sizeof( OVERLAPPED ) );
  507. //
  508. // Initialize the event once per preparation
  509. //
  510. if (NULL == (pWavePrepareData->pOverlapped->hEvent =
  511. CreateEvent( NULL, FALSE, FALSE, NULL )))
  512. {
  513. HeapFree( GetProcessHeap(), 0, pWavePrepareData->pOverlapped);
  514. GlobalFreePtr( pWavePrepareData );
  515. MMRRETURN( MMSYSERR_NOMEM );
  516. }
  517. #ifdef DEBUG
  518. pWavePrepareData->dwSig=WAVEPREPAREDATA_SIGNATURE;
  519. #endif
  520. //
  521. // This next line adds this info to the main header. Only after this point
  522. // will the info be used.
  523. //
  524. pHdr->reserved = (DWORD_PTR)pWavePrepareData;
  525. // Still have WinMM prepare this header
  526. return( MMSYSERR_NOTSUPPORTED );
  527. }
  528. /****************************************************************************
  529. * @doc INTERNAL
  530. *
  531. * @api MMRESULT | wdmaudUnprepareWaveHeader |
  532. *
  533. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical wave
  534. * device.
  535. *
  536. * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
  537. *
  538. * @rdesc A MMSYS... type return code for the application.
  539. *
  540. ***************************************************************************/
  541. MMRESULT wdmaudUnprepareWaveHeader
  542. (
  543. LPDEVICEINFO DeviceInfo,
  544. LPWAVEHDR pHdr
  545. )
  546. {
  547. MMRESULT mmr;
  548. PWAVEPREPAREDATA pWavePrepareData;
  549. if( ((mmr=IsValidWaveHeader(pHdr)) !=MMSYSERR_NOERROR ) ||
  550. ((mmr=IsValidPrepareWaveHeader((PWAVEPREPAREDATA)(pHdr->reserved))) != MMSYSERR_NOERROR ) )
  551. {
  552. MMRRETURN( mmr );
  553. }
  554. pWavePrepareData = (PWAVEPREPAREDATA)pHdr->reserved;
  555. //
  556. // This next line removes the WaveHeader from the list. It is no longer
  557. // valid after this point!
  558. //
  559. pHdr->reserved = (DWORD_PTR)NULL;
  560. CloseHandle( pWavePrepareData->pOverlapped->hEvent );
  561. //
  562. // When you free something, you should make sure that you trash it before
  563. // the free. But, in this case, the only thing we use in the pOverlapped
  564. // structure is the hEvent!
  565. //
  566. pWavePrepareData->pOverlapped->hEvent=NULL;
  567. HeapFree( GetProcessHeap(), 0, pWavePrepareData->pOverlapped);
  568. #ifdef DEBUG
  569. pWavePrepareData->pOverlapped=NULL;
  570. pWavePrepareData->dwSig=0;
  571. #endif
  572. GlobalFreePtr( pWavePrepareData );
  573. // Still have WinMM prepare this header
  574. return( MMSYSERR_NOTSUPPORTED );
  575. }
  576. #endif
  577. /****************************************************************************
  578. * @doc INTERNAL
  579. *
  580. * @api MMRESULT | waveWrite | This routine adds the header
  581. * to the queue and then submits the buffer to the device
  582. *
  583. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical wave
  584. * device.
  585. *
  586. * @parm LPWAVEHDR | pHdr | Pointer to a wave buffer
  587. *
  588. * @rdesc A MMSYS... type return code for the application.
  589. *
  590. * @comm The buffer flags are set and the buffer is passed to the auxiliary
  591. * device task for processing.
  592. ***************************************************************************/
  593. MMRESULT waveWrite
  594. (
  595. LPDEVICEINFO DeviceInfo,
  596. LPWAVEHDR pHdr
  597. )
  598. {
  599. MMRESULT mmr;
  600. LPWAVEHDR pTemp;
  601. //
  602. // Mark this buffer because kmixer doesn't handle the dwFlags
  603. //
  604. pHdr->dwFlags |= WHDR_INQUEUE;
  605. pHdr->dwFlags &= ~WHDR_DONE;
  606. #ifndef UNDER_NT
  607. //
  608. // Store the context for this write in the header so that
  609. // we know which client to send this back to on completion.
  610. //
  611. pHdr->reserved = (DWORD)DeviceInfo;
  612. #endif
  613. CRITENTER ;
  614. DPF(DL_MAX|FA_WAVE, ("(ECS)") ); // Enter critical section
  615. if (!DeviceInfo->DeviceState->lpWaveQueue)
  616. {
  617. DeviceInfo->DeviceState->lpWaveQueue = pHdr;
  618. pTemp = NULL;
  619. #ifdef UNDER_NT
  620. if( (DeviceInfo->DeviceState->hevtQueue) &&
  621. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTHREE) &&
  622. (DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTWO) )
  623. {
  624. //
  625. // If we get here, waveThread is waiting on hevtQueue because lpWaveQueue
  626. // was empty and the completion thread exists == hevtQueue exists.
  627. // So,we want to signal the thread to wake up so we can have this
  628. // header serviced. Note: the difference between this call and the
  629. // call made in wdmaudDestroyCompletionThread is that we don't set
  630. // fExit to TRUE before making the call.
  631. //
  632. DPF(DL_MAX|FA_WAVE, ("Setting DeviceInfo->hevtQueue"));
  633. SetEvent( DeviceInfo->DeviceState->hevtQueue );
  634. }
  635. #endif
  636. }
  637. else
  638. {
  639. for (pTemp = DeviceInfo->DeviceState->lpWaveQueue;
  640. pTemp->lpNext != NULL;
  641. pTemp = pTemp->lpNext);
  642. pTemp->lpNext = pHdr;
  643. }
  644. DPF(DL_MAX|FA_WAVE, ("(LCS)") ); // Leave critical section
  645. CRITLEAVE ;
  646. //
  647. // Call the 16 or 32-bit routine to send the buffer down
  648. // to the kernel
  649. //
  650. mmr = wdmaudSubmitWaveHeader(DeviceInfo, pHdr);
  651. if (mmr != MMSYSERR_NOERROR)
  652. {
  653. // Unlink...
  654. if (pTemp)
  655. {
  656. pTemp->lpNext = NULL;
  657. } else {
  658. DeviceInfo->DeviceState->lpWaveQueue = NULL;
  659. }
  660. pHdr->dwFlags &= ~WHDR_INQUEUE;
  661. DPF(DL_WARNING|FA_WAVE,("wdmaudSubmitWaveHeader failed mmr=%08X", mmr) );
  662. }
  663. else
  664. {
  665. //
  666. // Kick start the device if it has been shutdown because of
  667. // starvation. Also this allows waveOut to start when the
  668. // first waveheader is submitted to the device.
  669. //
  670. if (!DeviceInfo->DeviceState->fRunning && !DeviceInfo->DeviceState->fPaused)
  671. {
  672. mmr = wdmaudSetDeviceState(DeviceInfo, (DeviceInfo->DeviceType == WaveOutDevice) ?
  673. IOCTL_WDMAUD_WAVE_OUT_PLAY :
  674. IOCTL_WDMAUD_WAVE_IN_RECORD);
  675. if (mmr != MMSYSERR_NOERROR)
  676. {
  677. MMRESULT mmrError;
  678. mmrError = wdmaudSetDeviceState(DeviceInfo, (DeviceInfo->DeviceType == WaveOutDevice) ?
  679. IOCTL_WDMAUD_WAVE_OUT_RESET :
  680. IOCTL_WDMAUD_WAVE_IN_RESET);
  681. if (mmrError != MMSYSERR_NOERROR)
  682. {
  683. DPF(DL_WARNING|FA_WAVE, ("Couldn't reset device after error putting into run state"));
  684. }
  685. }
  686. }
  687. else
  688. {
  689. DPF(DL_MAX|FA_WAVE, ("DeviceInfo = x%08lx, fRunning = %d, fPaused = %d",
  690. DeviceInfo,
  691. DeviceInfo->DeviceState->fRunning,
  692. DeviceInfo->DeviceState->fPaused) );
  693. }
  694. }
  695. MMRRETURN( mmr );
  696. }
  697. /****************************************************************************
  698. * @doc INTERNAL
  699. *
  700. * @api VOID | waveCompleteHeader |
  701. *
  702. * @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical wave
  703. * device.
  704. *
  705. * @comm The buffer flags are set and the buffer is passed to the auxiliary
  706. * device task for processing.
  707. ***************************************************************************/
  708. VOID waveCompleteHeader
  709. (
  710. LPDEVICEINFO DeviceInfo
  711. )
  712. {
  713. LPWAVEHDR pHdr;
  714. MMRESULT mmr;
  715. // NOTE: This routine is called from within the csQueue critical section!!!
  716. //
  717. // Only remove headers from the front of the queue so that order is maintained.
  718. // Note that pHdr is the head, The DeviceInfo structure's DeviceState's
  719. // lpWaveQueue pointer then gets updated to the next location.
  720. //
  721. //
  722. // Never use bad data when handling this Completion!
  723. //
  724. if( (pHdr = DeviceInfo->DeviceState->lpWaveQueue) &&
  725. ( (mmr=IsValidWaveHeader(pHdr)) == MMSYSERR_NOERROR ) )
  726. {
  727. DeviceInfo->DeviceState->lpWaveQueue = DeviceInfo->DeviceState->lpWaveQueue->lpNext;
  728. #ifdef UNDER_NT
  729. //
  730. // Free temporary DeviceInfo for the asynchronous i/o
  731. //
  732. {
  733. PWAVEPREPAREDATA pWavePrepareData;
  734. pWavePrepareData = (PWAVEPREPAREDATA)pHdr->reserved;
  735. //
  736. // Never attempt to free garbage!
  737. //
  738. if( (mmr=IsValidPrepareWaveHeader(pWavePrepareData)) == MMSYSERR_NOERROR )
  739. GlobalFreePtr( pWavePrepareData->pdi );
  740. }
  741. // Invoke the callback function..
  742. DPF(DL_TRACE|FA_WAVE, ("WaveHdr being returned: pHdr = 0x%08lx dwBytesRecorded = 0x%08lx",
  743. pHdr, pHdr->dwBytesRecorded) );
  744. pHdr->lpNext = NULL ;
  745. pHdr->dwFlags &= ~WHDR_INQUEUE ;
  746. pHdr->dwFlags |= WHDR_DONE ;
  747. // NOTE: This callback is within the csQueue critical section !!!
  748. waveCallback(DeviceInfo,
  749. DeviceInfo->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
  750. (DWORD_PTR)pHdr);
  751. DPF(DL_TRACE|FA_WAVE, ("Done") );
  752. #else
  753. pHdr->dwFlags &= ~WHDR_INQUEUE;
  754. pHdr->dwFlags |= WHDR_DONE;
  755. pHdr->lpNext = NULL;
  756. waveCallback((LPDEVICEINFO)pHdr->reserved,
  757. DeviceInfo->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
  758. (DWORD)pHdr);
  759. #endif
  760. }
  761. }