Windows NT 4.0 source code leak
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.

1330 lines
37 KiB

4 years ago
  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 dwInstance, DWORD dwParam1, DWORD 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) NULL,
  113. (DWORD) (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) &mciaviWaveOutFunc,
  208. (DWORD) (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. len -= ((cksize + 1) & ~1) + 8;
  687. SKIP_BYTES((cksize + 1) & ~1);
  688. if (StreamFromFOURCC(ckid) != (UINT)npMCI->nAudioStream)
  689. continue;
  690. *pfPlayedAudio = TRUE;
  691. while (cksize) {
  692. dwBytesThisChunk = cksize;
  693. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  694. if (!npMCI->dwUsedThisAB) {
  695. if (!WaitForFreeAudioBuffer(npMCI, pfHurryUp))
  696. /* We had to stop waiting--the stop flag was probably set. */
  697. goto exit;
  698. }
  699. if (dwBytesThisChunk > npMCI->dwABSize - npMCI->dwUsedThisAB) {
  700. // DPF(("Audio Record is too big!\n"));
  701. dwBytesThisChunk = npMCI->dwABSize - npMCI->dwUsedThisAB;
  702. }
  703. hmemcpy((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  704. lpData, dwBytesThisChunk);
  705. cksize -= dwBytesThisChunk;
  706. lpData += dwBytesThisChunk;
  707. npMCI->dwUsedThisAB += dwBytesThisChunk;
  708. if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
  709. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  710. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  711. }
  712. }
  713. }
  714. if ((*pfPlayedAudio == FALSE) && (npMCI->dwUsedThisAB)) {
  715. // this is interleaved. therefore if we have some audio waiting,
  716. // and there was no audio in this record, it's because we've
  717. // used up all the audio -> so play remaining audio or
  718. // it will never be queued.
  719. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  720. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  721. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  722. }
  723. /* Use the number of full audio buffers to decide if we're behind. */
  724. if (npMCI->wABFull >= npMCI->wABOptimal) {
  725. *pfHurryUp = FALSE;
  726. }
  727. exit:
  728. npMCI->lp = lpSave;
  729. return fRet;
  730. }
  731. /* For "preload audio" or "random access audio" modes, do what needs
  732. ** to be done to keep our buffers full.
  733. */
  734. BOOL NEAR PASCAL KeepPlayingAudio(NPMCIGRAPHIC npMCI)
  735. {
  736. LPWAVEHDR lpWaveHdr;
  737. DWORD dwBytesTotal = 0L;
  738. LONG lNewAudioPos;
  739. ////BOOL fFirstTime = TRUE;
  740. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  741. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  742. PlayMore:
  743. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  744. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  745. lNewAudioPos = npMCI->dwAudioPos - npMCI->dwABSize;
  746. if (lNewAudioPos < 0)
  747. lNewAudioPos = 0;
  748. dwBytesTotal = npMCI->dwAudioPos - lNewAudioPos;
  749. } else {
  750. lNewAudioPos = npMCI->dwAudioPos + npMCI->dwABSize;
  751. if (lNewAudioPos > (LONG) npMCI->dwAudioLength)
  752. lNewAudioPos = npMCI->dwAudioLength;
  753. dwBytesTotal = lNewAudioPos - npMCI->dwAudioPos;
  754. }
  755. if (dwBytesTotal == 0) {
  756. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED) {
  757. DOUT("no more audio to play, restarting wave device\n");
  758. waveOutRestart(npMCI->hWave);
  759. ICDrawStart(npMCI->hicDraw);
  760. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  761. npMCI->nAudioBehind = 0;
  762. }
  763. return TRUE;
  764. }
  765. /* If all of the audio buffers are full, we have nothing to do */
  766. if (npMCI->wABFull == npMCI->wABs)
  767. return TRUE;
  768. #if 0
  769. //!!!! Should we be yielding at all in here?
  770. //!!! NO NO! not if updating!!!!
  771. if (!fFirstTime) {
  772. aviTaskYield();
  773. }
  774. fFirstTime = FALSE;
  775. #endif
  776. if (npMCI->dwFlags & MCIAVI_REVERSE)
  777. npMCI->dwAudioPos = lNewAudioPos;
  778. #ifdef USEAVIFILE
  779. if (npMCI->pf) {
  780. LONG lPos;
  781. LONG lLength;
  782. lPos = npMCI->dwAudioPos / SH(npMCI->nAudioStream).dwSampleSize;
  783. lLength = dwBytesTotal / SH(npMCI->nAudioStream).dwSampleSize;
  784. AVIStreamRead(SI(npMCI->nAudioStream)->ps,
  785. lPos, lLength,
  786. lpWaveHdr->lpData,
  787. npMCI->dwABSize,
  788. NULL, NULL);
  789. }
  790. else
  791. #endif
  792. {
  793. if (!ReadSomeAudio(npMCI, lpWaveHdr->lpData,
  794. npMCI->dwAudioPos,
  795. &dwBytesTotal))
  796. return FALSE;
  797. if (dwBytesTotal == 0)
  798. return TRUE;
  799. }
  800. if (!(npMCI->dwFlags & MCIAVI_REVERSE))
  801. npMCI->dwAudioPos += dwBytesTotal;
  802. lpWaveHdr->dwBufferLength = dwBytesTotal;
  803. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  804. ReverseWaveBuffer(npMCI, lpWaveHdr);
  805. }
  806. if (!PlaySomeAudio(npMCI, lpWaveHdr))
  807. return FALSE;
  808. // return TRUE;
  809. goto PlayMore;
  810. }
  811. #ifdef USENONINTFROMCD
  812. /* Play the current chunk's audio */
  813. BOOL NEAR PASCAL HandleAudioChunk(NPMCIGRAPHIC npMCI)
  814. {
  815. LPWAVEHDR lpWaveHdr;
  816. FOURCC ckid;
  817. DWORD cksize;
  818. BYTE _huge *lpData;
  819. BOOL fRet = TRUE;
  820. BOOL fSilence;
  821. DWORD dwBytesTotal = 0L;
  822. DWORD dwBytesThisChunk;
  823. DWORD dwBytesThisBuffer;
  824. BOOL fHurryUp;
  825. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_CDROM);
  826. while ((DWORD) (npMCI->lp - npMCI->lpBuffer)
  827. < npMCI->dwThisRecordSize - 3 * sizeof(DWORD)) {
  828. /* Look at the next chunk */
  829. ckid = GET_DWORD();
  830. cksize = GET_DWORD();
  831. lpData = npMCI->lp;
  832. SKIP_BYTES(cksize + (cksize & 1));
  833. fSilence = (TWOCCFromFOURCC(ckid) == cktypeWAVEsilence);
  834. if (fSilence) {
  835. if (cksize != sizeof(DWORD)) {
  836. DPF(("Wave silence chunk of bad length!\n"));
  837. fRet = FALSE;
  838. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  839. goto exit;
  840. }
  841. dwBytesThisChunk = PEEK_DWORD();
  842. } else {
  843. dwBytesThisChunk = cksize;
  844. }
  845. while (dwBytesThisChunk > 0) {
  846. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  847. if (!WaitForFreeAudioBuffer(npMCI, &fHurryUp))
  848. /* We had to stop waiting--the stop flag was probably set. */
  849. goto exit;
  850. dwBytesThisBuffer = min(dwBytesThisChunk,
  851. npMCI->dwABSize - npMCI->dwUsedThisAB);
  852. if (!fSilence) {
  853. /* Move the data into the buffer */
  854. hmemcpy((BYTE _huge *) lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  855. lpData,
  856. dwBytesThisBuffer);
  857. lpData += dwBytesThisBuffer;
  858. } else {
  859. /* Fill the buffer with silence */
  860. /* This isn't right for 16-bit! */
  861. #ifndef _WIN32
  862. #pragma message("WAVE silence chunks don't work right now.")
  863. #endif
  864. // fmemfill((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  865. // dwBytesThisBuffer, 0x80);
  866. }
  867. dwBytesThisChunk -= dwBytesThisBuffer;
  868. npMCI->dwUsedThisAB += dwBytesThisBuffer;
  869. // if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
  870. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  871. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  872. // }
  873. }
  874. }
  875. exit:
  876. return fRet;
  877. }
  878. #endif
  879. /******************************************************************************
  880. *****************************************************************************/
  881. // We need to talk to a worker thread for another AVI device
  882. extern DWORD mciaviTaskRequest(NPMCIGRAPHIC npMCI, UINT message,
  883. DWORD dwFlags, LPARAM lParam,
  884. DWORD dwCallback, BOOL bDelayedComplete);
  885. /***************************************************************************
  886. *
  887. * @doc INTERNAL MCIAVI
  888. *
  889. * @api BOOL | StealWaveDevice | steal the audio device from another
  890. * instance of MCIAVI.
  891. *
  892. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  893. *
  894. ***************************************************************************/
  895. BOOL FAR PASCAL StealWaveDevice(NPMCIGRAPHIC npMCI)
  896. {
  897. #ifdef STEALWAVE
  898. NPMCIGRAPHIC np;
  899. Assert(npMCI->hWave == NULL);
  900. #if defined(_WIN32) && defined(DEBUG)
  901. if (mmGetProfileInt(szIni, TEXT("NoStealing"), 0)) {
  902. return(FALSE);
  903. }
  904. #endif
  905. DPF2(("StealWaveDevice '%ls' hTask=%04X\n", (LPSTR)npMCI->szFilename, npMCI->hTask));
  906. #if 0
  907. if (npMCI->dwFlags & MCIAVI_SEEKING) {
  908. DPF0(("Do we really want to get a wave device for seeking?\n"));
  909. }
  910. #endif
  911. EnterList();
  912. //
  913. // walk the list of open MCIAVI instances and find one that
  914. // could give up the wave device
  915. //
  916. for (np=npMCIList; np; np = np->npMCINext) {
  917. if (np->hWave) {
  918. DWORD dwRetRequest;
  919. DPF2(("**** Stealing the wave device from '%ls' (hTask=%4X).\n", (LPSTR)np->szFilename, np->hTask));
  920. // Requesting the current wave device owner to release ownership.
  921. // By sending the request directly to the worker thread we avoid
  922. // some of the problems we might have if we had to talk to the
  923. // winproc thread. This operation is synchronous. We do not
  924. // want the request to complete until the wave device has been
  925. // released. If we sent to the window, then the winproc thread
  926. // would have to send a synchronous request to its worker. This
  927. // is too tedious, and we do not have (at time of writing) the
  928. // mechanisms for supporting this way of working.
  929. LeaveList();
  930. dwRetRequest = mciaviTaskRequest(np, AVI_WAVESTEAL, 0, (LPARAM) 0, 0, FALSE);
  931. if (dwRetRequest == 0) {
  932. return TRUE;
  933. } else {
  934. return(FALSE);
  935. }
  936. }
  937. }
  938. DPF2(("StealWaveDevice can't find a local device to steal\n"));
  939. #ifdef REMOTESTEAL
  940. // Read the registry key of the task with the wave device.
  941. // If it fails we do not bother to try and
  942. // recover. It only means that the sound will not follow the
  943. // active video
  944. {
  945. TCHAR achName[100];
  946. DWORD dwRet;
  947. DWORD dwType;
  948. HWND hwndRemote;
  949. DWORD cbData = sizeof(hwndRemote);
  950. lstrcpy(achName, KEYNAME);
  951. lstrcat(achName, szWaveOwner);
  952. if (hkey || (ERROR_SUCCESS == (dwRet = RegOpenKeyEx(ROOTKEY, achName,
  953. 0, KEY_ALL_ACCESS, &hkey)))) {
  954. dwRet = RegQueryValueEx(hkey, szRemoteWaveHwnd, 0, &dwType,
  955. (LPBYTE)&hwndRemote, &cbData);
  956. if (dwRet == ERROR_SUCCESS) {
  957. DPF2(("Posting WM_AUDIO_OFF to hwnd %x\n", hwndRemote));
  958. PostMessage(hwndRemote, WM_AUDIO_OFF, (WPARAM)npMCI->hwndDefault, 0);
  959. } else {
  960. // Could not read wave owner stuff from registry
  961. }
  962. } else {
  963. // No wave owner stored in registry
  964. }
  965. }
  966. #endif // REMOTESTEAL
  967. LeaveList();
  968. #endif // STEALWAVE
  969. return FALSE;
  970. }
  971. /***************************************************************************
  972. *
  973. * @doc INTERNAL MCIAVI
  974. *
  975. * @api BOOL | GiveWaveDevice | give away the audio device
  976. * instance of MCIAVI.
  977. *
  978. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  979. *
  980. ***************************************************************************/
  981. BOOL FAR PASCAL GiveWaveDevice(NPMCIGRAPHIC npMCI)
  982. {
  983. #ifdef STEALWAVE
  984. extern NPMCIGRAPHIC npMCIList; // in graphic.c
  985. NPMCIGRAPHIC np;
  986. Assert(npMCI->hWave == NULL);
  987. DPF2(("GiveWaveDevice '%ls' hTask=%04X\n", (LPTSTR)npMCI->szFilename, npMCI->hTask));
  988. if (hwndLostAudio) {
  989. BOOL fRet = FALSE;
  990. if (IsWindow(hwndLostAudio)) {
  991. DPF3(("Posting AUDIO_ON message to %x\n", hwndLostAudio));
  992. fRet = PostMessage(hwndLostAudio, WM_AUDIO_ON, 0, 0);
  993. } else {
  994. DPF3(("Lost audio window %x is no longer valid\n", hwndLostAudio));
  995. }
  996. hwndLostAudio = 0;
  997. if (fRet) return TRUE;
  998. }
  999. EnterList();
  1000. //
  1001. // walk the list of open MCIAVI instances and find one that
  1002. // wants a wave device. Then hint to that task that it can
  1003. // try and grab the wave device back.
  1004. // MORE inter process stuff required.
  1005. //
  1006. for (np=npMCIList; np; np = np->npMCINext) {
  1007. if ((np->dwFlags & MCIAVI_LOSTAUDIO)
  1008. && (!TestNTFlags(npMCI, NTF_CLOSING))
  1009. )
  1010. {
  1011. DPF2(("**** Giving wave device to '%ls' hTask=%04X \n", (LPSTR)np->szFilename, np->hTask));
  1012. Assert(np!=npMCI);
  1013. LeaveList();
  1014. mciaviTaskRequest(np, AVI_WAVERETURN, 0, (LPARAM) 0, 0, FALSE);
  1015. return TRUE;
  1016. }
  1017. }
  1018. LeaveList();
  1019. #endif // STEALWAVE
  1020. return FALSE;
  1021. }
  1022. #ifndef _WIN32
  1023. #pragma alloc_text(FIX, mciaviWaveOutFunc)
  1024. #pragma optimize("", off)
  1025. #endif
  1026. void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg,
  1027. DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
  1028. {
  1029. NPMCIGRAPHIC npMCI;
  1030. LPWAVEHDR lpwh;
  1031. #ifndef _WIN32
  1032. _asm _emit 0x66 ; pushad
  1033. _asm _emit 0x60
  1034. #endif
  1035. npMCI = (NPMCIGRAPHIC)(UINT)dwInstance;
  1036. lpwh = (LPWAVEHDR) dwParam1;
  1037. switch(wMsg) {
  1038. case MM_WOM_DONE:
  1039. #ifdef _WIN32
  1040. InterlockedDecrement(&npMCI->wABFull);
  1041. #else
  1042. npMCI->wABFull--;
  1043. #endif
  1044. npMCI->dwAudioPlayed += lpwh->dwBufferLength;
  1045. #ifdef USE_PERFORMANCE_TIMING
  1046. GETTIME(npMCI->dwTimingStart);
  1047. #else
  1048. npMCI->dwTimingStart = timeGetTime();
  1049. #endif
  1050. break;
  1051. }
  1052. #ifndef _WIN32
  1053. _asm _emit 0x66 ; popad
  1054. _asm _emit 0x61
  1055. #endif
  1056. }
  1057. #ifndef _WIN32
  1058. #pragma optimize("", off)
  1059. #endif