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.

1335 lines
37 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1991-1992. All rights reserved.
  3. Title: avisound.c - Code for playing audio in AVI files.
  4. *****************************************************************************/
  5. #include "graphic.h"
  6. #define AUDIO_PANIC 10
  7. static UINT nAudioPanic;
  8. //
  9. // redefine StreamFromFOURCC to only handle 0-9 streams!
  10. //
  11. #undef StreamFromFOURCC
  12. #define StreamFromFOURCC(fcc) (UINT)(HIBYTE(LOWORD(fcc)) - (BYTE)'0')
  13. void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg,
  14. DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
  15. #ifndef _WIN32
  16. #define GetDS() (HGLOBAL)HIWORD((DWORD)(LPVOID)&ghModule)
  17. #endif //WIN16
  18. #ifdef REMOTESTEAL
  19. #if 0 // COMMENTARY
  20. Wave devices can only be used by one task at a time. When there are
  21. multiple processes involved we need to have some way of passing the
  22. wave device around between processes. Because each process executes
  23. asynchronously we choose an asynchronous method of passing the wave
  24. device.
  25. When we start playing an attempt is made to open the wave device. If
  26. successful we write our playback window handle to a known (volatile)
  27. area of the registry.
  28. When we stop playing and release the wave device we clear the registry.
  29. If we cannot open a wave device, we inspect the registry to see if
  30. another process has it open. If YES, then we post a WM_AUDIO_OFF message
  31. to the registered window handle, passing our playback window handle as
  32. a parameter. We then continue to play silently.
  33. Receiving WM_AUDIO_OFF:
  34. if we are playing with a wave device we stop temporarily, post a
  35. message to the task wanting the wave device along with our window
  36. handle (so that the wave device can be returned to us).
  37. When we have finished with the wave device we check hwndLostAudio to
  38. see if there is a window we should tell to pick up the wave device.
  39. If so, we post WM_AUDIO_ON to that window.
  40. #endif// COMMENTARY
  41. // hwndLostAudio is set to the window handle of the device from which we
  42. // stole the audio device. It is passed as a parameter on the
  43. // WM_AUDIO_ON message to tell us to whom we should return the
  44. // wave device when we have finished with it.
  45. // hwndWantAudio contains transitory state. It is set on receipt of a
  46. // WM_AUDIO_OFF message to tell us the window that wants to grab the
  47. // wave device. If we are playing, we temporarily stop which causes
  48. // the wave device to be released. Immediately the wave device is
  49. // released we post a message to hwndWantAudio and reset the variable.
  50. // If we receive a WM_AUDIO_OFF message while we are not playing (which
  51. // can happen due to asynchronous execution) hwndWantAudio is not set.
  52. HWND hwndLostAudio=0; // Window handle of the window who gave up audio
  53. HWND hwndWantAudio=0; // Window handle of the window which wants the audio
  54. HKEY hkey = 0; // Handle to area of registry for inter process steal
  55. #define REMOTEWAVEHWND TEXT("RemoteWaveWindow")
  56. #define WAVEOWNER TEXT("WaveOwner")
  57. TCHAR szRemoteWaveHwnd[] = REMOTEWAVEHWND;
  58. TCHAR szWaveOwner[] = WAVEOWNER;
  59. #include <profile.key>
  60. #endif
  61. /******************************************************************************
  62. *****************************************************************************/
  63. /***************************************************************************
  64. *
  65. * @doc INTERNAL MCIAVI
  66. *
  67. * @api BOOL | SetUpAudio | set up wave device and associated data
  68. *
  69. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  70. *
  71. * @parm BOOL | fPlaying |
  72. *
  73. ***************************************************************************/
  74. DWORD FAR PASCAL SetUpAudio(NPMCIGRAPHIC npMCI, BOOL fPlaying)
  75. {
  76. UINT w;
  77. DWORD dw;
  78. LPWAVEHDR lpWaveHdr;
  79. STREAMINFO *psi;
  80. if (npMCI->nAudioStreams == 0) {
  81. npMCI->wABs = 0;
  82. npMCI->wABOptimal = 0;
  83. return 0L;
  84. }
  85. nAudioPanic = mmGetProfileInt(szIni, TEXT("AudioPanic"), AUDIO_PANIC);
  86. psi = SI(npMCI->nAudioStream);
  87. Assert(psi->sh.fccType == streamtypeAUDIO);
  88. Assert(psi->cbFormat);
  89. Assert(psi->lpFormat);
  90. if (!npMCI->pWF) {
  91. npMCI->pWF = (NPWAVEFORMAT)LocalAlloc(LPTR, (UINT)psi->cbFormat);
  92. if (!npMCI->pWF) {
  93. return MCIERR_OUT_OF_MEMORY;
  94. }
  95. }
  96. hmemcpy(npMCI->pWF,psi->lpFormat,psi->cbFormat);
  97. npMCI->wEarlyAudio = (UINT)psi->sh.dwInitialFrames;
  98. DPF1(("Setting up audio... wEarlyAudio==%d\n", npMCI->wEarlyAudio));
  99. npMCI->dwAudioLength = psi->sh.dwLength * psi->sh.dwSampleSize;
  100. if (npMCI->dwAudioLength < 1000L) {
  101. DPF(("AudioLength is bogus"));
  102. npMCI->dwAudioLength = muldiv32((npMCI->pWF->nAvgBytesPerSec + 100) *
  103. npMCI->lFrames,npMCI->dwMicroSecPerFrame,1000000L);
  104. }
  105. if (!fPlaying) {
  106. // We are not actually playing. Check to see if we will be able
  107. // to handle the format of the wave data.
  108. if (IsNTWOW()) {
  109. /* See if we can cope with this wave format. */
  110. w = waveOutOpen(&npMCI->hWave, (UINT)WAVE_MAPPER,
  111. (const LPWAVEFORMATEX) npMCI->pWF,
  112. (DWORD_PTR) NULL,
  113. (DWORD_PTR) (LPMCIGRAPHIC) npMCI,
  114. (DWORD) WAVE_FORMAT_QUERY);
  115. if (WAVERR_BADFORMAT == w)
  116. return(MCIERR_WAVE_OUTPUTSUNSUITABLE); // Try 16 bit codec
  117. else
  118. return(0); // We might be able to cope with this format
  119. }
  120. }
  121. //
  122. // choose the audio playback method depending on how we are going to
  123. // receive audio data from the file.
  124. //
  125. switch (npMCI->wPlaybackAlg) {
  126. case MCIAVI_ALG_HARDDISK:
  127. case MCIAVI_ALG_AUDIOONLY:
  128. if (!npMCI->pf && !npMCI->hmmioAudio) {
  129. MMIOINFO mmioInfo;
  130. _fmemset(&mmioInfo, 0, sizeof(MMIOINFO));
  131. mmioInfo.htask = (HANDLE) npMCI->hCallingTask; //ntmmsystem bug, should be threadid which is dword
  132. npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo,
  133. MMIO_READ | MMIO_DENYWRITE);
  134. if (npMCI->hmmioAudio == NULL)
  135. npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo,
  136. MMIO_READ);
  137. if (!npMCI->hmmioAudio) {
  138. Assert(0);
  139. return MCIERR_DRIVER_INTERNAL;
  140. }
  141. }
  142. // !!! We use four 1/2 second buffers. This is arbitrary.
  143. npMCI->wABs = 4;
  144. npMCI->wABOptimal = 0;
  145. npMCI->dwABSize = npMCI->pWF->nAvgBytesPerSec / 2;
  146. break;
  147. case MCIAVI_ALG_CDROM:
  148. //!!!! we need to tune this!!!!
  149. // !!! We use four 1/4 second buffers. This is arbitrary.
  150. npMCI->wABs = mmGetProfileInt(szIni, TEXT("CDAudioBuffers"), 4);
  151. npMCI->wABOptimal = 0;
  152. npMCI->dwABSize = npMCI->pWF->nAvgBytesPerSec /
  153. mmGetProfileInt(szIni, TEXT("CDAudioBufSize"), 4);
  154. break;
  155. case MCIAVI_ALG_INTERLEAVED:
  156. #define BUFMOD 4096 // had better be a power of 2!
  157. /* Fix up some values based on the header information */
  158. dw = muldiv32(npMCI->dwMicroSecPerFrame,
  159. npMCI->pWF->nAvgBytesPerSec,1000000L);
  160. npMCI->dwABSize = (dw + BUFMOD - 1) & ~(BUFMOD - 1L);
  161. npMCI->wABs = npMCI->wEarlyAudio + 2 + (WORD) npMCI->dwBufferedVideo;
  162. /* Soundblaster hack: waveoutdone only accurate to 2K. */
  163. //!!!!!!!!!! is this right.
  164. if (npMCI->dwMicroSecPerFrame) {
  165. npMCI->wABOptimal = npMCI->wABs -
  166. (UINT) (muldiv32(BUFMOD, 1, muldiv32(npMCI->dwMicroSecPerFrame,
  167. npMCI->pWF->nAvgBytesPerSec,1000000L)));
  168. } else {
  169. npMCI->wABOptimal = 0;
  170. }
  171. //!!! hack so we can do burst reading, up to 1sec
  172. //npMCI->wABs += (int)muldiv32(1000000l, 1, npMCI->dwMicroSecPerFrame);
  173. // !!!!!!
  174. // !!!!!!
  175. npMCI->wABOptimal = 0;
  176. npMCI->wABs = (UINT) muldivru32(npMCI->wABs, dw, npMCI->dwABSize) + 1;
  177. DPF2(("Using %u audio buffers of %lu bytes, of which %u should be full.\n", npMCI->wABs, npMCI->dwABSize, npMCI->wABOptimal));
  178. break;
  179. default:
  180. Assert(0);
  181. return 0L;
  182. }
  183. npMCI->dwABSize -= npMCI->dwABSize % npMCI->pWF->nBlockAlign;
  184. if (!fPlaying) {
  185. return 0L;
  186. }
  187. /* This code adjusts the wave format block to play
  188. ** the audio at the correct speed to match the frame rate.
  189. */
  190. npMCI->pWF->nSamplesPerSec = muldiv32(npMCI->pWF->nSamplesPerSec,
  191. npMCI->dwMicroSecPerFrame,
  192. npMCI->dwPlayMicroSecPerFrame);
  193. npMCI->pWF->nAvgBytesPerSec = muldiv32(npMCI->pWF->nAvgBytesPerSec,
  194. npMCI->dwMicroSecPerFrame,
  195. npMCI->dwPlayMicroSecPerFrame);
  196. if (npMCI->pWF->wFormatTag == WAVE_FORMAT_PCM) {
  197. /* Make sure this is exactly right... */
  198. npMCI->pWF->nAvgBytesPerSec =
  199. npMCI->pWF->nSamplesPerSec * npMCI->pWF->nBlockAlign;
  200. }
  201. /* Kill any currently playing sound */
  202. sndPlaySound(NULL, 0);
  203. DPF2(("Opening wave device....\n"));
  204. /* Try to open a wave device. */
  205. w = waveOutOpen(&npMCI->hWave, (UINT)WAVE_MAPPER,
  206. (const LPWAVEFORMATEX) npMCI->pWF,
  207. (DWORD_PTR) &mciaviWaveOutFunc,
  208. (DWORD_PTR) (LPMCIGRAPHIC) npMCI,
  209. (DWORD)CALLBACK_FUNCTION);
  210. if (w) {
  211. DPF(("Unable to open wave device.\n"));
  212. npMCI->hWave = NULL;
  213. return w == WAVERR_BADFORMAT ?
  214. MCIERR_WAVE_OUTPUTSUNSUITABLE :
  215. MCIERR_WAVE_OUTPUTSINUSE;
  216. }
  217. // We now have the wave device, so turn off the flag that says we
  218. // lost it.
  219. npMCI->dwFlags &= ~MCIAVI_LOSTAUDIO;
  220. #ifndef _WIN32 // No need to lock it on NT - although we could with Virtual mem
  221. // functions
  222. //
  223. // page lock our DS so our wave callback function can
  224. // touch it without worry. see mciaviWaveOutFunc()
  225. //
  226. GlobalPageLock(GetDS());
  227. #endif //WIN16
  228. /* Pause the wave output device, so it won't start playing
  229. ** when we're loading up the buffers.
  230. */
  231. if (waveOutPause(npMCI->hWave) != 0) {
  232. DPF(("Error from waveOutPause!\n"));
  233. return MCIERR_DRIVER_INTERNAL;
  234. }
  235. if (npMCI->dwFlags & MCIAVI_VOLUMESET) {
  236. InternalSetVolume(npMCI, npMCI->dwVolume);
  237. } else {
  238. // must be done on worker thread
  239. InternalGetVolume(npMCI);
  240. }
  241. #ifdef DEBUG
  242. Assert(!(npMCI->lpAudio));
  243. #endif
  244. npMCI->lpAudio = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  245. npMCI->wABs * (npMCI->dwABSize + sizeof(WAVEHDR)));
  246. if (!npMCI->lpAudio) {
  247. // The wave device will be released when CleanUpAudio is called
  248. return MCIERR_OUT_OF_MEMORY;
  249. }
  250. npMCI->dwAudioPlayed = 0L;
  251. npMCI->wNextAB = 0;
  252. npMCI->dwUsedThisAB = 0;
  253. /* Allocate and prepare our buffers */
  254. for (w = 0; w < npMCI->wABs; w++) {
  255. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
  256. lpWaveHdr->lpData = (HPSTR) npMCI->lpAudio +
  257. npMCI->wABs * sizeof(WAVEHDR) +
  258. w * npMCI->dwABSize;
  259. lpWaveHdr->dwBufferLength = npMCI->dwABSize;
  260. lpWaveHdr->dwBytesRecorded = 0L;
  261. lpWaveHdr->dwUser = 0L;
  262. lpWaveHdr->dwFlags = 0L;
  263. lpWaveHdr->dwLoops = 0L;
  264. lpWaveHdr->lpNext = 0L;
  265. lpWaveHdr->reserved = 0;
  266. }
  267. for (w = 0; w < npMCI->wABs; w++) {
  268. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
  269. if (waveOutPrepareHeader(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR))
  270. != 0) {
  271. return MCIERR_OUT_OF_MEMORY;
  272. }
  273. lpWaveHdr->dwFlags |= WHDR_DONE;
  274. }
  275. #ifdef REMOTESTEAL
  276. // Set a registry key so that other processes know who has the
  277. // wave device... if it fails we do not bother to try and
  278. // recover. It only means that the sound will not follow the
  279. // active video
  280. {
  281. TCHAR achName[100];
  282. DWORD dwRet;
  283. DWORD dwDisposition;
  284. lstrcpy(achName, KEYNAME);
  285. lstrcat(achName, szWaveOwner);
  286. EnterList();
  287. if (hkey || (ERROR_SUCCESS == (dwRet = RegCreateKeyEx(ROOTKEY, achName, 0,
  288. TEXT("VFW"), REG_OPTION_VOLATILE, KEY_ALL_ACCESS,
  289. NULL, &hkey, &dwDisposition)))) {
  290. // Write both out process id and the handle of the event
  291. // that needs to be signalled. Any remote process out there
  292. // that want to steal our wave device will duplicate the handle
  293. // to the event, for which our process id is required.
  294. DWORD pid = GetCurrentProcessId();
  295. RegSetValueEx(hkey, szRemoteWaveHwnd, 0, REG_DWORD,
  296. (CONST BYTE *)&npMCI->hwndDefault, sizeof(npMCI->hwndDefault));
  297. }
  298. LeaveList();
  299. }
  300. #endif
  301. return 0L;
  302. }
  303. DWORD FAR PASCAL CleanUpAudio(NPMCIGRAPHIC npMCI)
  304. {
  305. UINT w;
  306. /* Clear flags relating to playing audio */
  307. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED | MCIAVI_LOSEAUDIO);
  308. if (npMCI->lpAudio) {
  309. waveOutRestart(npMCI->hWave); // just in case we are paused
  310. waveOutReset(npMCI->hWave);
  311. for (w = 0; w < npMCI->wABs; w++) {
  312. LPWAVEHDR lpWaveHdr;
  313. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio
  314. + (w * sizeof(WAVEHDR)));
  315. #ifndef _WIN32
  316. //don't touch prepared data
  317. lpWaveHdr->lpData = npMCI->lpAudio
  318. + npMCI->wABs * sizeof(WAVEHDR)
  319. + w * npMCI->dwABSize;
  320. lpWaveHdr->dwBufferLength = npMCI->dwABSize;
  321. #endif
  322. /* Do we need to check for an error from this? */
  323. waveOutUnprepareHeader(npMCI->hWave, lpWaveHdr,
  324. sizeof(WAVEHDR));
  325. }
  326. GlobalFreePtr(npMCI->lpAudio);
  327. npMCI->lpAudio = NULL;
  328. Assert(npMCI->wABFull == 0);
  329. }
  330. DPF2(("Closing wave device.\n"));
  331. #ifdef REMOTESTEAL
  332. EnterList()
  333. if (hkey) {
  334. RegDeleteValue(hkey, szRemoteWaveHwnd);
  335. }
  336. LeaveList()
  337. #endif
  338. waveOutClose(npMCI->hWave);
  339. npMCI->hWave = 0;
  340. #ifdef REMOTESTEAL
  341. // If we are being asked to give the audio to someone else...
  342. // tell them to pick it up, and tell them that we want it back.
  343. // We do this here rather than in GiveWaveDevice as GiveWaveDevice
  344. // may not be called.
  345. if (hwndWantAudio) {
  346. if (IsWindow(hwndWantAudio)) {
  347. PostMessage(hwndWantAudio, WM_AUDIO_ON, (WPARAM)npMCI->hwndDefault, 0);
  348. }
  349. hwndWantAudio = 0;
  350. }
  351. #endif // REMOTESTEAL
  352. #ifndef _WIN32
  353. GlobalPageUnlock(GetDS());
  354. #endif //WIN16
  355. return 0L;
  356. }
  357. BOOL NEAR PASCAL WaitForFreeAudioBuffer(NPMCIGRAPHIC npMCI, BOOL FAR *lpfHurry)
  358. {
  359. LPWAVEHDR lpWaveHdr;
  360. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio
  361. + (npMCI->wNextAB * sizeof(WAVEHDR)));
  362. /* Use the number of full audio buffers to decide if we're behind. */
  363. if (npMCI->wABFull < npMCI->wABOptimal) {
  364. *lpfHurry = TRUE;
  365. }
  366. /* If all of the audio buffers are full, we have to wait. */
  367. if (npMCI->wABFull == npMCI->wABs) {
  368. DWORD time = timeGetTime();
  369. #define AUDIO_WAIT_TIMEOUT 2000
  370. DOUT2("waiting for audio buffer.");
  371. // we better not wait if the device is not playing!
  372. Assert(!(npMCI->dwFlags & MCIAVI_WAVEPAUSED));
  373. #ifdef XDEBUG
  374. GetAsyncKeyState(VK_ESCAPE);
  375. GetAsyncKeyState(VK_F2);
  376. GetAsyncKeyState(VK_F3);
  377. GetAsyncKeyState(VK_F4);
  378. #endif
  379. while (npMCI->wABFull == npMCI->wABs) {
  380. if (npMCI->dwFlags & MCIAVI_STOP)
  381. return FALSE;
  382. aviTaskCheckRequests(npMCI);
  383. //
  384. // the "Fahrenheit VA Audio Wave Driver" may get confused
  385. // if you call waveOutPause() and waveOutRestart() alot
  386. // and it will stay paused no matter what you do, it has
  387. // all our buffers and it still does not make any sound
  388. // you can call waveOutRestart() until you are blue in
  389. // the face, it will do nothing.
  390. //
  391. // so this is why this routine can time out, after waiting
  392. // 2 seconds or so we just toss all the audio in the buffers
  393. // and start over.
  394. //
  395. if (timeGetTime() - time > AUDIO_WAIT_TIMEOUT) {
  396. DOUT("Gave up waiting, reseting wave device\n");
  397. gfUseGetPosition = 0;
  398. // Can no longer rely on waveOutGetPosition returning
  399. // the right value.
  400. waveOutReset(npMCI->hWave);
  401. break;
  402. }
  403. #ifdef XDEBUG
  404. if (GetAsyncKeyState(VK_ESCAPE) & 0x0001) {
  405. DPF(("STOPPED WAITING! wABFull = %d, wABs = %d\n", npMCI->wABFull,npMCI->wABs));
  406. return FALSE;
  407. }
  408. if (GetAsyncKeyState(VK_F2) & 0x0001) {
  409. DOUT("Trying waveOutRestart\n");
  410. waveOutRestart(npMCI->hWave);
  411. }
  412. if (GetAsyncKeyState(VK_F3) & 0x0001) {
  413. DOUT("Trying waveOutReset\n");
  414. gfUseGetPosition = 0;
  415. // Can no longer rely on waveOutGetPosition returning
  416. // the right value.
  417. waveOutReset(npMCI->hWave);
  418. }
  419. if (GetAsyncKeyState(VK_F4) & 0x0001) {
  420. int i,n;
  421. for (i=n=0; i<(int)npMCI->wABs; i++) {
  422. if (((LPWAVEHDR)npMCI->lpAudio)[i].dwFlags & WHDR_DONE) {
  423. DPF(("Buffer #%d is done!\n", i));
  424. n++;
  425. }
  426. else {
  427. DPF(("Buffer #%d is not done\n", i));
  428. }
  429. }
  430. if (n > 0)
  431. DPF(("%d buffers are done but our callback did not get called!\n", n));
  432. }
  433. #endif
  434. }
  435. DOUT2("done\n");
  436. }
  437. /* Debugging check that wave has finished playing--should never happen */
  438. Assert(lpWaveHdr->dwFlags & WHDR_DONE);
  439. #ifndef _WIN32
  440. // don't touch prepared data
  441. lpWaveHdr->lpData = npMCI->lpAudio +
  442. npMCI->wABs * sizeof(WAVEHDR) +
  443. npMCI->wNextAB * npMCI->dwABSize;
  444. #endif
  445. return TRUE;
  446. }
  447. #ifndef _WIN32
  448. #pragma optimize("", off)
  449. #endif
  450. BOOL NEAR PASCAL ReadSomeAudio(NPMCIGRAPHIC npMCI, BYTE _huge * lpAudio,
  451. DWORD dwStart, DWORD FAR * pdwLength)
  452. {
  453. DWORD dwIndex = 0;
  454. DWORD ckidAudio;
  455. DWORD dwAudioPos = 0L;
  456. AVIINDEXENTRY far * lpIndexEntry;
  457. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  458. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  459. Assert(npMCI->hpIndex);
  460. /*
  461. ** Figure out what type of chunk we're looking for,
  462. */
  463. ckidAudio = MAKEAVICKID(cktypeWAVEbytes, npMCI->nAudioStream);
  464. lpIndexEntry = (AVIINDEXENTRY FAR *) npMCI->hpIndex;
  465. for (dwIndex = 0; dwIndex < npMCI->macIndex;
  466. dwIndex++, ++((AVIINDEXENTRY _huge *) lpIndexEntry)) {
  467. if (lpIndexEntry->ckid != ckidAudio)
  468. continue;
  469. if (dwAudioPos + lpIndexEntry->dwChunkLength > dwStart) {
  470. DWORD dwLengthNow;
  471. DWORD dwSeekTo;
  472. dwLengthNow = lpIndexEntry->dwChunkLength;
  473. dwSeekTo = lpIndexEntry->dwChunkOffset + 8;
  474. if (dwAudioPos + dwLengthNow > dwStart + *pdwLength) {
  475. /* Attempted optimization: If we've already read some
  476. ** data, and we can't read the next whole chunk, let's
  477. ** leave it for later.
  478. */
  479. if (dwAudioPos > dwStart && (!(npMCI->dwFlags & MCIAVI_REVERSE)))
  480. break;
  481. dwLengthNow = dwStart + *pdwLength - dwAudioPos;
  482. }
  483. if (dwAudioPos < dwStart) {
  484. dwLengthNow -= (dwStart - dwAudioPos);
  485. dwSeekTo += (dwStart - dwAudioPos);
  486. }
  487. mmioSeek(npMCI->hmmioAudio, dwSeekTo, SEEK_SET);
  488. if (mmioRead(npMCI->hmmioAudio, lpAudio, dwLengthNow)
  489. != (LONG) dwLengthNow) {
  490. DPF(("Error reading audio data (%lx bytes at %lx)\n", dwLengthNow, dwSeekTo));
  491. return FALSE;
  492. }
  493. lpAudio += dwLengthNow;
  494. }
  495. dwAudioPos += lpIndexEntry->dwChunkLength;
  496. if (dwAudioPos >= dwStart + *pdwLength)
  497. return TRUE;
  498. }
  499. if (dwAudioPos < dwStart)
  500. *pdwLength = 0; // return FALSE?
  501. else
  502. *pdwLength = dwAudioPos - dwStart;
  503. return TRUE;
  504. }
  505. #ifndef _WIN32
  506. #pragma optimize("", on)
  507. #endif
  508. BOOL NEAR PASCAL ReverseWaveBuffer(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  509. {
  510. DWORD dwLeft = lpWaveHdr->dwBufferLength;
  511. BYTE _huge *hp1;
  512. BYTE _huge *hp2;
  513. DWORD dwBlock = npMCI->pWF->nBlockAlign;
  514. BYTE bTemp;
  515. DWORD dw;
  516. Assert(npMCI->dwFlags & MCIAVI_REVERSE);
  517. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  518. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  519. /* This routine doesn't like it when the data doesn't end on a
  520. ** block boundary, so make it so. This should never happen.
  521. */
  522. Assert((dwLeft % dwBlock) == 0);
  523. dwLeft -= dwLeft % dwBlock;
  524. hp1 = lpWaveHdr->lpData;
  525. hp2 = ((HPSTR) lpWaveHdr->lpData) + (dwLeft - dwBlock);
  526. while ((LONG) dwLeft > (LONG) dwBlock) {
  527. for (dw = 0; dw < dwBlock; dw++) {
  528. bTemp = *hp1;
  529. *hp1++ = *hp2;
  530. *hp2++ = bTemp;
  531. }
  532. hp2 -= dwBlock * 2;
  533. dwLeft -= dwBlock * 2;
  534. }
  535. return TRUE;
  536. }
  537. void FAR PASCAL BuildVolumeTable(NPMCIGRAPHIC npMCI)
  538. {
  539. int vol;
  540. int i;
  541. if (!npMCI->pWF || npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM)
  542. return;
  543. if (((NPPCMWAVEFORMAT) npMCI->pWF)->wBitsPerSample != 8)
  544. return;
  545. vol = (LOWORD(npMCI->dwVolume) + HIWORD(npMCI->dwVolume)) / 2;
  546. vol = (int) (((LONG) vol * 256) / 500);
  547. if (!npMCI->pVolumeTable)
  548. npMCI->pVolumeTable = (void *)LocalAlloc(LPTR, 256);
  549. if (!npMCI->pVolumeTable)
  550. return;
  551. for (i = 0; i < 256; i++) {
  552. npMCI->pVolumeTable[i] = (BYTE) min(255, max(0,
  553. (int) ((((LONG) (i - 128) * vol) / 256) + 128)));
  554. }
  555. }
  556. BOOL NEAR PASCAL AdjustVolume(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  557. {
  558. DWORD dwLeft = lpWaveHdr->dwBufferLength;
  559. BYTE FAR *pb;
  560. if (npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM)
  561. return FALSE;
  562. if (!npMCI->pVolumeTable)
  563. return FALSE;
  564. if (((NPPCMWAVEFORMAT)npMCI->pWF)->wBitsPerSample != 8)
  565. return FALSE;
  566. pb = lpWaveHdr->lpData;
  567. #ifndef _WIN32
  568. if (OFFSETOF(pb) + dwLeft > 64l*1024) {
  569. while (dwLeft--) {
  570. *pb = npMCI->pVolumeTable[*pb];
  571. ((BYTE _huge *)pb)++;
  572. }
  573. }
  574. else {
  575. while ((int)dwLeft--)
  576. *pb++ = npMCI->pVolumeTable[*pb];
  577. }
  578. #else
  579. while ((int)dwLeft--)
  580. *pb++ = npMCI->pVolumeTable[*pb];
  581. #endif
  582. return TRUE;
  583. }
  584. BOOL NEAR PASCAL PlaySomeAudio(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  585. {
  586. if (npMCI->pVolumeTable)
  587. AdjustVolume(npMCI, lpWaveHdr);
  588. lpWaveHdr->dwFlags &= ~WHDR_DONE;
  589. /* If we're playing and we've used all of our audio buffers, pause the
  590. ** wave device until we can fill more of them up.
  591. **
  592. ** we need to be carefull not to do this on the last frame!!!
  593. */
  594. if ((npMCI->wTaskState == TASKPLAYING) &&
  595. !(npMCI->dwFlags & MCIAVI_WAVEPAUSED) &&
  596. (npMCI->wABFull == 0 || npMCI->nAudioBehind > nAudioPanic)) {
  597. if (npMCI->wABFull > 0) {
  598. DPF(("Audio panic stop\n"));
  599. } else {
  600. DPF(("Audio queue empty; pausing wave device\n"));
  601. }
  602. //
  603. // some audio cards dont like starving it confuses them
  604. // it is kind of rude any way. we are going to cause a audio break
  605. // anyway so if we lose a little bit of audio (a few frames or so)
  606. // no one will even notice (any worse than the audio break)
  607. //
  608. if (npMCI->wABFull <= 1) {
  609. DOUT("Trying audio hack!\n");
  610. gfUseGetPosition = 0;
  611. // Can no longer rely on waveOutGetPosition returning
  612. // the right value.
  613. waveOutReset(npMCI->hWave);
  614. }
  615. ++npMCI->dwAudioBreaks;
  616. waveOutPause(npMCI->hWave);
  617. ICDrawStop(npMCI->hicDraw);
  618. npMCI->dwFlags |= MCIAVI_WAVEPAUSED;
  619. }
  620. if (waveOutWrite(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR)) != 0) {
  621. DPF(("Error from waveOutWrite!\n"));
  622. npMCI->dwTaskError = MCIERR_AVI_AUDIOERROR;
  623. // if this fails, you can end up looping indefinitely in
  624. // PlayRecordAudio in the while(cksize) loop - cksize is never
  625. // decremented because the current audio buffer stays full.
  626. // Need to throw this stuff away or we lock up.
  627. npMCI->dwUsedThisAB = 0;
  628. return FALSE;
  629. } else {
  630. #ifdef _WIN32
  631. InterlockedIncrement(&npMCI->wABFull);
  632. #else
  633. ++npMCI->wABFull;
  634. #endif
  635. /* Use the next wave buffer next time */
  636. ++npMCI->wNextAB;
  637. if (npMCI->wNextAB == npMCI->wABs)
  638. npMCI->wNextAB = 0;
  639. npMCI->dwUsedThisAB = 0;
  640. }
  641. if (npMCI->wABFull < min(npMCI->wABOptimal, npMCI->wABFull/2))
  642. npMCI->nAudioBehind++;
  643. else
  644. npMCI->nAudioBehind=0;
  645. /* If we paused the wave device to let ourselves catch up, and
  646. ** we've caught up enough, restart the device.
  647. */
  648. if ((npMCI->dwFlags & MCIAVI_WAVEPAUSED) &&
  649. npMCI->wTaskState == TASKPLAYING &&
  650. npMCI->wABFull == npMCI->wABs) {
  651. DPF2(("restarting wave device\n"));
  652. waveOutRestart(npMCI->hWave);
  653. ICDrawStart(npMCI->hicDraw);
  654. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  655. npMCI->nAudioBehind = 0;
  656. }
  657. return TRUE;
  658. }
  659. /* Play the current record's audio */
  660. BOOL NEAR PASCAL PlayRecordAudio(NPMCIGRAPHIC npMCI, BOOL FAR *pfHurryUp,
  661. BOOL FAR *pfPlayedAudio)
  662. {
  663. LPWAVEHDR lpWaveHdr;
  664. FOURCC ckid;
  665. DWORD cksize;
  666. LPSTR lpSave;
  667. BYTE _huge *lpData;
  668. BOOL fRet = TRUE;
  669. ////BOOL fSilence;
  670. LONG len;
  671. DWORD dwBytesThisChunk;
  672. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED);
  673. lpSave = npMCI->lp;
  674. *pfPlayedAudio = FALSE;
  675. /* Remember!
  676. **
  677. ** In the new file format, things shouldn't necessarily need to
  678. ** be ordered with the wave stuff always first.
  679. */
  680. len = (LONG)npMCI->dwThisRecordSize;
  681. while (len > 3 * sizeof(DWORD)) {
  682. /* Look at the next chunk */
  683. ckid = GET_DWORD();
  684. cksize = GET_DWORD();
  685. lpData = npMCI->lp;
  686. if ((DWORD) cksize > (DWORD) len) {
  687. DPF(("Chunk obviously too big!"));
  688. break;
  689. }
  690. len -= ((cksize + 1) & ~1) + 8;
  691. SKIP_BYTES((cksize + 1) & ~1);
  692. if (StreamFromFOURCC(ckid) != (UINT)npMCI->nAudioStream)
  693. continue;
  694. *pfPlayedAudio = TRUE;
  695. while (cksize) {
  696. dwBytesThisChunk = cksize;
  697. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  698. if (!npMCI->dwUsedThisAB) {
  699. if (!WaitForFreeAudioBuffer(npMCI, pfHurryUp))
  700. /* We had to stop waiting--the stop flag was probably set. */
  701. goto exit;
  702. }
  703. if (dwBytesThisChunk > npMCI->dwABSize - npMCI->dwUsedThisAB) {
  704. // DPF(("Audio Record is too big!\n"));
  705. dwBytesThisChunk = npMCI->dwABSize - npMCI->dwUsedThisAB;
  706. }
  707. hmemcpy((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  708. lpData, dwBytesThisChunk);
  709. cksize -= dwBytesThisChunk;
  710. lpData += dwBytesThisChunk;
  711. npMCI->dwUsedThisAB += dwBytesThisChunk;
  712. if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
  713. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  714. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  715. }
  716. }
  717. }
  718. if ((*pfPlayedAudio == FALSE) && (npMCI->dwUsedThisAB)) {
  719. // this is interleaved. therefore if we have some audio waiting,
  720. // and there was no audio in this record, it's because we've
  721. // used up all the audio -> so play remaining audio or
  722. // it will never be queued.
  723. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  724. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  725. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  726. }
  727. /* Use the number of full audio buffers to decide if we're behind. */
  728. if (npMCI->wABFull >= npMCI->wABOptimal) {
  729. *pfHurryUp = FALSE;
  730. }
  731. exit:
  732. npMCI->lp = lpSave;
  733. return fRet;
  734. }
  735. /* For "preload audio" or "random access audio" modes, do what needs
  736. ** to be done to keep our buffers full.
  737. */
  738. BOOL NEAR PASCAL KeepPlayingAudio(NPMCIGRAPHIC npMCI)
  739. {
  740. LPWAVEHDR lpWaveHdr;
  741. DWORD dwBytesTotal = 0L;
  742. LONG lNewAudioPos;
  743. ////BOOL fFirstTime = TRUE;
  744. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  745. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  746. PlayMore:
  747. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  748. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  749. lNewAudioPos = npMCI->dwAudioPos - npMCI->dwABSize;
  750. if (lNewAudioPos < 0)
  751. lNewAudioPos = 0;
  752. dwBytesTotal = npMCI->dwAudioPos - lNewAudioPos;
  753. } else {
  754. lNewAudioPos = npMCI->dwAudioPos + npMCI->dwABSize;
  755. if (lNewAudioPos > (LONG) npMCI->dwAudioLength)
  756. lNewAudioPos = npMCI->dwAudioLength;
  757. dwBytesTotal = lNewAudioPos - npMCI->dwAudioPos;
  758. }
  759. if (dwBytesTotal == 0) {
  760. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED) {
  761. DOUT("no more audio to play, restarting wave device\n");
  762. waveOutRestart(npMCI->hWave);
  763. ICDrawStart(npMCI->hicDraw);
  764. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  765. npMCI->nAudioBehind = 0;
  766. }
  767. return TRUE;
  768. }
  769. /* If all of the audio buffers are full, we have nothing to do */
  770. if (npMCI->wABFull == npMCI->wABs)
  771. return TRUE;
  772. #if 0
  773. //!!!! Should we be yielding at all in here?
  774. //!!! NO NO! not if updating!!!!
  775. if (!fFirstTime) {
  776. aviTaskYield();
  777. }
  778. fFirstTime = FALSE;
  779. #endif
  780. if (npMCI->dwFlags & MCIAVI_REVERSE)
  781. npMCI->dwAudioPos = lNewAudioPos;
  782. #ifdef USEAVIFILE
  783. if (npMCI->pf) {
  784. LONG lPos;
  785. LONG lLength;
  786. lPos = npMCI->dwAudioPos / SH(npMCI->nAudioStream).dwSampleSize;
  787. lLength = dwBytesTotal / SH(npMCI->nAudioStream).dwSampleSize;
  788. AVIStreamRead(SI(npMCI->nAudioStream)->ps,
  789. lPos, lLength,
  790. lpWaveHdr->lpData,
  791. npMCI->dwABSize,
  792. NULL, NULL);
  793. }
  794. else
  795. #endif
  796. {
  797. if (!ReadSomeAudio(npMCI, lpWaveHdr->lpData,
  798. npMCI->dwAudioPos,
  799. &dwBytesTotal))
  800. return FALSE;
  801. if (dwBytesTotal == 0)
  802. return TRUE;
  803. }
  804. if (!(npMCI->dwFlags & MCIAVI_REVERSE))
  805. npMCI->dwAudioPos += dwBytesTotal;
  806. lpWaveHdr->dwBufferLength = dwBytesTotal;
  807. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  808. ReverseWaveBuffer(npMCI, lpWaveHdr);
  809. }
  810. if (!PlaySomeAudio(npMCI, lpWaveHdr))
  811. return FALSE;
  812. // return TRUE;
  813. goto PlayMore;
  814. }
  815. #ifdef USENONINTFROMCD
  816. /* Play the current chunk's audio */
  817. BOOL NEAR PASCAL HandleAudioChunk(NPMCIGRAPHIC npMCI)
  818. {
  819. LPWAVEHDR lpWaveHdr;
  820. FOURCC ckid;
  821. DWORD cksize;
  822. BYTE _huge *lpData;
  823. BOOL fRet = TRUE;
  824. BOOL fSilence;
  825. DWORD dwBytesTotal = 0L;
  826. DWORD dwBytesThisChunk;
  827. DWORD dwBytesThisBuffer;
  828. BOOL fHurryUp;
  829. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_CDROM);
  830. while ((DWORD) (npMCI->lp - npMCI->lpBuffer)
  831. < npMCI->dwThisRecordSize - 3 * sizeof(DWORD)) {
  832. /* Look at the next chunk */
  833. ckid = GET_DWORD();
  834. cksize = GET_DWORD();
  835. lpData = npMCI->lp;
  836. SKIP_BYTES(cksize + (cksize & 1));
  837. fSilence = (TWOCCFromFOURCC(ckid) == cktypeWAVEsilence);
  838. if (fSilence) {
  839. if (cksize != sizeof(DWORD)) {
  840. DPF(("Wave silence chunk of bad length!\n"));
  841. fRet = FALSE;
  842. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  843. goto exit;
  844. }
  845. dwBytesThisChunk = PEEK_DWORD();
  846. } else {
  847. dwBytesThisChunk = cksize;
  848. }
  849. while (dwBytesThisChunk > 0) {
  850. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  851. if (!WaitForFreeAudioBuffer(npMCI, &fHurryUp))
  852. /* We had to stop waiting--the stop flag was probably set. */
  853. goto exit;
  854. dwBytesThisBuffer = min(dwBytesThisChunk,
  855. npMCI->dwABSize - npMCI->dwUsedThisAB);
  856. if (!fSilence) {
  857. /* Move the data into the buffer */
  858. hmemcpy((BYTE _huge *) lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  859. lpData,
  860. dwBytesThisBuffer);
  861. lpData += dwBytesThisBuffer;
  862. } else {
  863. /* Fill the buffer with silence */
  864. /* This isn't right for 16-bit! */
  865. #ifndef _WIN32
  866. #pragma message("WAVE silence chunks don't work right now.")
  867. #endif
  868. // fmemfill((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  869. // dwBytesThisBuffer, 0x80);
  870. }
  871. dwBytesThisChunk -= dwBytesThisBuffer;
  872. npMCI->dwUsedThisAB += dwBytesThisBuffer;
  873. // if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
  874. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  875. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  876. // }
  877. }
  878. }
  879. exit:
  880. return fRet;
  881. }
  882. #endif
  883. /******************************************************************************
  884. *****************************************************************************/
  885. // We need to talk to a worker thread for another AVI device
  886. extern DWORD mciaviTaskRequest(NPMCIGRAPHIC npMCI, UINT message,
  887. DWORD dwFlags, LPARAM lParam,
  888. DWORD dwCallback, BOOL bDelayedComplete);
  889. /***************************************************************************
  890. *
  891. * @doc INTERNAL MCIAVI
  892. *
  893. * @api BOOL | StealWaveDevice | steal the audio device from another
  894. * instance of MCIAVI.
  895. *
  896. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  897. *
  898. ***************************************************************************/
  899. BOOL FAR PASCAL StealWaveDevice(NPMCIGRAPHIC npMCI)
  900. {
  901. #ifdef STEALWAVE
  902. NPMCIGRAPHIC np;
  903. Assert(npMCI->hWave == NULL);
  904. #if defined(_WIN32) && defined(DEBUG)
  905. if (mmGetProfileInt(szIni, TEXT("NoStealing"), 0)) {
  906. return(FALSE);
  907. }
  908. #endif
  909. DPF2(("StealWaveDevice '%ls' hTask=%04X\n", (LPSTR)npMCI->szFilename, npMCI->hTask));
  910. #if 0
  911. if (npMCI->dwFlags & MCIAVI_SEEKING) {
  912. DPF0(("Do we really want to get a wave device for seeking?\n"));
  913. }
  914. #endif
  915. EnterList();
  916. //
  917. // walk the list of open MCIAVI instances and find one that
  918. // could give up the wave device
  919. //
  920. for (np=npMCIList; np; np = np->npMCINext) {
  921. if (np->hWave) {
  922. DWORD dwRetRequest;
  923. DPF2(("**** Stealing the wave device from '%ls' (hTask=%4X).\n", (LPSTR)np->szFilename, np->hTask));
  924. // Requesting the current wave device owner to release ownership.
  925. // By sending the request directly to the worker thread we avoid
  926. // some of the problems we might have if we had to talk to the
  927. // winproc thread. This operation is synchronous. We do not
  928. // want the request to complete until the wave device has been
  929. // released. If we sent to the window, then the winproc thread
  930. // would have to send a synchronous request to its worker. This
  931. // is too tedious, and we do not have (at time of writing) the
  932. // mechanisms for supporting this way of working.
  933. LeaveList();
  934. dwRetRequest = mciaviTaskRequest(np, AVI_WAVESTEAL, 0, (LPARAM) 0, 0, FALSE);
  935. if (dwRetRequest == 0) {
  936. return TRUE;
  937. } else {
  938. return(FALSE);
  939. }
  940. }
  941. }
  942. DPF2(("StealWaveDevice can't find a local device to steal\n"));
  943. #ifdef REMOTESTEAL
  944. // Read the registry key of the task with the wave device.
  945. // If it fails we do not bother to try and
  946. // recover. It only means that the sound will not follow the
  947. // active video
  948. {
  949. TCHAR achName[100];
  950. DWORD dwRet;
  951. DWORD dwType;
  952. HWND hwndRemote;
  953. DWORD cbData = sizeof(hwndRemote);
  954. lstrcpy(achName, KEYNAME);
  955. lstrcat(achName, szWaveOwner);
  956. if (hkey || (ERROR_SUCCESS == (dwRet = RegOpenKeyEx(ROOTKEY, achName,
  957. 0, KEY_ALL_ACCESS, &hkey)))) {
  958. dwRet = RegQueryValueEx(hkey, szRemoteWaveHwnd, 0, &dwType,
  959. (LPBYTE)&hwndRemote, &cbData);
  960. if (dwRet == ERROR_SUCCESS) {
  961. DPF2(("Posting WM_AUDIO_OFF to hwnd %x\n", hwndRemote));
  962. PostMessage(hwndRemote, WM_AUDIO_OFF, (WPARAM)npMCI->hwndDefault, 0);
  963. } else {
  964. // Could not read wave owner stuff from registry
  965. }
  966. } else {
  967. // No wave owner stored in registry
  968. }
  969. }
  970. #endif // REMOTESTEAL
  971. LeaveList();
  972. #endif // STEALWAVE
  973. return FALSE;
  974. }
  975. /***************************************************************************
  976. *
  977. * @doc INTERNAL MCIAVI
  978. *
  979. * @api BOOL | GiveWaveDevice | give away the audio device
  980. * instance of MCIAVI.
  981. *
  982. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  983. *
  984. ***************************************************************************/
  985. BOOL FAR PASCAL GiveWaveDevice(NPMCIGRAPHIC npMCI)
  986. {
  987. #ifdef STEALWAVE
  988. extern NPMCIGRAPHIC npMCIList; // in graphic.c
  989. NPMCIGRAPHIC np;
  990. Assert(npMCI->hWave == NULL);
  991. DPF2(("GiveWaveDevice '%ls' hTask=%04X\n", (LPTSTR)npMCI->szFilename, npMCI->hTask));
  992. if (hwndLostAudio) {
  993. BOOL fRet = FALSE;
  994. if (IsWindow(hwndLostAudio)) {
  995. DPF3(("Posting AUDIO_ON message to %x\n", hwndLostAudio));
  996. fRet = PostMessage(hwndLostAudio, WM_AUDIO_ON, 0, 0);
  997. } else {
  998. DPF3(("Lost audio window %x is no longer valid\n", hwndLostAudio));
  999. }
  1000. hwndLostAudio = 0;
  1001. if (fRet) return TRUE;
  1002. }
  1003. EnterList();
  1004. //
  1005. // walk the list of open MCIAVI instances and find one that
  1006. // wants a wave device. Then hint to that task that it can
  1007. // try and grab the wave device back.
  1008. // MORE inter process stuff required.
  1009. //
  1010. for (np=npMCIList; np; np = np->npMCINext) {
  1011. if ((np->dwFlags & MCIAVI_LOSTAUDIO)
  1012. && (!TestNTFlags(npMCI, NTF_CLOSING))
  1013. )
  1014. {
  1015. DPF2(("**** Giving wave device to '%ls' hTask=%04X \n", (LPSTR)np->szFilename, np->hTask));
  1016. Assert(np!=npMCI);
  1017. LeaveList();
  1018. mciaviTaskRequest(np, AVI_WAVERETURN, 0, (LPARAM) 0, 0, FALSE);
  1019. return TRUE;
  1020. }
  1021. }
  1022. LeaveList();
  1023. #endif // STEALWAVE
  1024. return FALSE;
  1025. }
  1026. #ifndef _WIN32
  1027. #pragma alloc_text(FIX, mciaviWaveOutFunc)
  1028. #pragma optimize("", off)
  1029. #endif
  1030. void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg,
  1031. DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
  1032. {
  1033. NPMCIGRAPHIC npMCI;
  1034. LPWAVEHDR lpwh;
  1035. #ifndef _WIN32
  1036. _asm _emit 0x66 ; pushad
  1037. _asm _emit 0x60
  1038. #endif
  1039. npMCI = (NPMCIGRAPHIC) dwInstance;
  1040. lpwh = (LPWAVEHDR) dwParam1;
  1041. switch(wMsg) {
  1042. case MM_WOM_DONE:
  1043. #ifdef _WIN32
  1044. InterlockedDecrement(&npMCI->wABFull);
  1045. #else
  1046. npMCI->wABFull--;
  1047. #endif
  1048. npMCI->dwAudioPlayed += lpwh->dwBufferLength;
  1049. #ifdef USE_PERFORMANCE_TIMING
  1050. GETTIME(npMCI->dwTimingStart);
  1051. #else
  1052. npMCI->dwTimingStart = timeGetTime();
  1053. #endif
  1054. break;
  1055. }
  1056. #ifndef _WIN32
  1057. _asm _emit 0x66 ; popad
  1058. _asm _emit 0x61
  1059. #endif
  1060. }
  1061. #ifndef _WIN32
  1062. #pragma optimize("", off)
  1063. #endif