source: trunk/src/winmm/waveoutflash.cpp@ 21916

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 27.2 KB
Line 
1/* $Id: waveoutflash.cpp,v 1.00 2010-02-20 12:00:00 rlwalsh Exp $ */
2
3/*
4 * Wave playback class (DART for Flash10)
5 *
6 * Copyright 1998-2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 2010 Richard L Walsh (rich@e-vertise.com)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13/******************************************************************************/
14// Includes
15/******************************************************************************/
16
17#define INCL_BASE
18#define INCL_OS2MM
19#define INCL_DOSPROCESS
20#include <os2wrap.h> //Odin32 OS/2 api wrappers
21#include <os2mewrap.h> //Odin32 OS/2 MMPM/2 api wrappers
22#include <stdlib.h>
23#include <stddef.h>
24#include <string.h>
25#include <stdio.h>
26#include <stdarg.h>
27#define OS2_ONLY
28#include <win32api.h>
29#include <wprocess.h>
30#include <options.h>
31#include "misc.h"
32#include "waveoutflash.h"
33#include "initterm.h"
34
35#define DBG_LOCALLOG DBG_waveoutflash
36#include "dbglocal.h"
37
38/******************************************************************************/
39
40// number of DART buffers to allocate
41#define FLASH_BUFCNT 8
42
43// number of buffers to fill before writing when state == STOPPED or PAUSED
44#define FLASH_PREFILL 3
45
46// used to attach additional info to the MCI_MIX_BUFFERs
47typedef struct {
48 FlashWaveOut * pThis;
49 volatile LPWAVEHDR pwh;
50} MIX_EXTRA;
51
52// a deprecated but useful function implemented in kernel32\thread.cpp
53USHORT WIN32API ODIN_ThreadEnterOdinContext(void *pExceptionRegRec, BOOL fForceFSSwitch);
54
55// debug info
56void showWriteMsg(LPWAVEHDR pwh, int free, int queued, BOOL fInit);
57
58/******************************************************************************/
59// Query/Enable/Disable use of FlashWaveOut
60/******************************************************************************/
61
62static BOOL useFlashAudio = FALSE;
63
64/******************************************************************************/
65/******************************************************************************/
66
67BOOL WIN32API ODIN_IsFlashAudioEnabled()
68{
69 // Except for the first call, this is the same as 'return useFlashAudio'.
70 return ODIN_EnableFlashAudio(useFlashAudio);
71}
72
73/******************************************************************************/
74/******************************************************************************/
75
76BOOL WIN32API ODIN_EnableFlashAudio(BOOL enable)
77{
78 static int forceFlashAudio = -1;
79
80 // If the ini hasn't been checked yet, do so now.
81 // If there's an entry, it will override the default & app setting.
82 if (forceFlashAudio == -1) {
83 int i = PROFILE_GetOdinIniInt(WINMM_SECTION, KEY_FLASHAUDIO, -1);
84 if (i == -1)
85 forceFlashAudio = 0;
86 else {
87 forceFlashAudio = 1;
88 useFlashAudio = i ? TRUE : FALSE;
89 }
90 }
91
92 // If FlashAudio hasn't been forced on or off, update the setting.
93 if (!forceFlashAudio)
94 useFlashAudio = enable ? TRUE : FALSE;
95
96 return useFlashAudio;
97}
98
99/******************************************************************************/
100// FlashWaveOut implementation
101/******************************************************************************/
102
103// event sem used to serialize ownership of the audio device
104HEV FlashWaveOut::deviceSem = 0;
105
106/******************************************************************************/
107/******************************************************************************/
108
109FlashWaveOut::FlashWaveOut(LPWAVEFORMATEX pwfx, ULONG fdwOpen,
110 ULONG nCallback, ULONG dwInstance)
111 : WaveOut(pwfx, fdwOpen, nCallback, dwInstance)
112{
113 deviceId = 0;
114 waveOffs = 0;
115 dartBufInit = FALSE;
116 dartBufSize = 0;
117 dartBufCnt = FLASH_BUFCNT;
118 dartFreeCnt = FLASH_BUFCNT;
119 dartFreeNdx = 0;
120 dartPlayed = 0;
121 readyCnt = 0;
122 readyNdx = 0;
123 mixHandle = 0;
124 pmixWriteProc = 0;
125 pmixBuffers = 0;
126
127 dprintf(("FlashWaveOut - sps= %d bps= %d chan= %d",
128 SampleRate, BitsPerSample, nChannels));
129
130 return;
131}
132
133/******************************************************************************/
134/******************************************************************************/
135
136MMRESULT FlashWaveOut::open()
137{
138 APIRET rc;
139 MIX_EXTRA * pmixExtra;
140 MCI_AMP_OPEN_PARMS AmpOpenParms;
141 MCI_GENERIC_PARMS GenericParms = {0};
142 MCI_MIXSETUP_PARMS MixSetupParms;
143
144 // Wait for the device to become available.
145 if (!getDeviceSem(TRUE))
146 return MMSYSERR_NOTENABLED;
147
148 // Open the ampmix device in shared mode.
149 memset(&AmpOpenParms, 0, sizeof(AmpOpenParms));
150 AmpOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
151
152 rc = mymciSendCommand(0, MCI_OPEN,
153 MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
154 (PVOID)&AmpOpenParms, 0);
155 if (LOUSHORT(rc) != MCIERR_SUCCESS) {
156 mciError("FlashWaveOut::open - MCI_OPEN", rc);
157 return MMSYSERR_NODRIVER;
158 }
159
160 // Save the device ID
161 deviceId = AmpOpenParms.usDeviceID;
162
163 // Get exclusive rights to this device instance (not entire device).
164 rc = mymciSendCommand(deviceId, MCI_ACQUIREDEVICE,
165 MCI_WAIT | MCI_EXCLUSIVE_INSTANCE,
166 (PVOID)&GenericParms, 0);
167 if (LOUSHORT(rc) != MCIERR_SUCCESS) {
168 mciError("FlashWaveOut::open - MCI_ACQUIREDEVICE", rc);
169 return MMSYSERR_NOTENABLED;
170 }
171
172 // Setup the Amp-Mixer to play wave data.
173 memset(&MixSetupParms, 0, sizeof(MixSetupParms));
174 MixSetupParms.ulBitsPerSample = BitsPerSample;
175 MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
176 MixSetupParms.ulSamplesPerSec = SampleRate;
177 MixSetupParms.ulChannels = nChannels;
178 MixSetupParms.ulFormatMode = MCI_PLAY;
179 MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
180 MixSetupParms.pmixEvent = FlashWaveOutHandler;
181
182 rc = mymciSendCommand(deviceId, MCI_MIXSETUP,
183 MCI_WAIT | MCI_MIXSETUP_INIT,
184 (PVOID)&MixSetupParms, 0);
185 if (LOUSHORT(rc) != MCIERR_SUCCESS) {
186 mciError("FlashWaveOut::open - MCI_MIXSETUP", rc);
187 mymciSendCommand(deviceId, MCI_RELEASEDEVICE,
188 MCI_WAIT, (PVOID)&GenericParms, 0);
189 return MMSYSERR_NOTSUPPORTED;
190 }
191
192 // Save the mixer handle & the ptr to the write proc.
193 mixHandle = MixSetupParms.ulMixHandle;
194 pmixWriteProc = MixSetupParms.pmixWrite;
195
196 // Allocate mixbuffer structures - the actual buffers
197 // will be allocated the first time ::write() is called.
198 int cnt = dartBufCnt * (sizeof(MCI_MIX_BUFFER) + sizeof(MIX_EXTRA));
199 void * ptr = malloc(cnt);
200 if (!ptr) {
201 dprintf(("FlashWaveOut::open - malloc failed"));
202 mymciSendCommand(deviceId, MCI_RELEASEDEVICE,
203 MCI_WAIT, (PVOID)&GenericParms, 0);
204 return MMSYSERR_NOMEM;
205 }
206 memset(ptr, 0, cnt);
207 pmixBuffers = (MCI_MIX_BUFFER*)ptr;
208 pmixExtra = (MIX_EXTRA*)&pmixBuffers[dartBufCnt];
209
210 // Initialize the members that don't change.
211 for (int i = 0; i < dartBufCnt; i++) {
212 pmixBuffers[i].ulStructLength = sizeof(MCI_MIX_BUFFER);
213 pmixBuffers[i].ulUserParm = (ULONG)&pmixExtra[i];
214 pmixExtra[i].pThis = this;
215 }
216
217 setVolume(volume);
218 callback(WOM_OPEN, 0, 0);
219
220 return MMSYSERR_NOERROR;
221}
222
223/******************************************************************************/
224/******************************************************************************/
225
226FlashWaveOut::~FlashWaveOut()
227{
228 APIRET rc;
229 MCI_GENERIC_PARMS GenericParms = {0};
230
231 dprintf((__FUNCTION__));
232
233 State = STATE_STOPPED;
234
235 // If the device was successfully opened...
236 if (deviceId) {
237
238 // Stop playback.
239 rc = mymciSendCommand(deviceId, MCI_STOP,
240 MCI_WAIT, (PVOID)&GenericParms, 0);
241 if (LOUSHORT(rc) != MCIERR_SUCCESS)
242 mciError("~FlashWaveOut - MCI_STOP", rc);
243
244 // Free the DART buffers
245 if (dartBufInit) {
246 MCI_BUFFER_PARMS BufferParms;
247 memset(&BufferParms, 0, sizeof(BufferParms));
248 BufferParms.ulStructLength = sizeof(BufferParms);
249 BufferParms.ulNumBuffers = dartBufCnt;
250 BufferParms.ulBufferSize = dartBufSize;
251 BufferParms.pBufList = pmixBuffers;
252 rc = mymciSendCommand(deviceId, MCI_BUFFER,
253 MCI_WAIT | MCI_DEALLOCATE_MEMORY,
254 (PVOID)&BufferParms, 0);
255 if (LOUSHORT(rc) != MCIERR_SUCCESS)
256 mciError("~FlashWaveOut - MCI_BUFFER", rc);
257 }
258
259 // Close the device.
260 rc = mymciSendCommand(deviceId, MCI_CLOSE,
261 MCI_WAIT, (PVOID)&GenericParms, 0);
262 if (LOUSHORT(rc) != MCIERR_SUCCESS)
263 mciError("~FlashWaveOut - MCI_CLOSE", rc);
264
265 // Advise the Win client that the device has been closed.
266 callback(WOM_CLOSE, 0, 0);
267 }
268
269 // Free the MCI_MIX_BUFFER & MIX_EXTRA structures
270 if (pmixBuffers)
271 free(pmixBuffers);
272
273 // Signal that the device is now available for use by another instance.
274 getDeviceSem(FALSE);
275
276 dprintf(("exit\n"));
277
278 return;
279}
280
281/******************************************************************************/
282/******************************************************************************/
283
284// Flash may try to open a new instance of the audio device before it has
285// finished closing the previous instance, causing a failure. Because it
286// is opened on the primary thread but usually closed by a secondary thread,
287// a mutex sem can't be used to control access to the device. Instead, an
288// event sem is used, where: reset == "in use" & posted == "available".
289// Note: DCE_POSTONE was added in Warp 4.0 FP4 & 3.0 FP29 - the sem is
290// reset automatically & only one waiting thread is unblocked
291
292BOOL FlashWaveOut::getDeviceSem(BOOL get)
293{
294 APIRET rc;
295
296 // Create the semaphore. Unless there's been some error,
297 // this should only be called when 'get' is TRUE.
298 if (!deviceSem) {
299 dprintf(("FlashWaveOut::getDeviceSem - creating event sem in %s state",
300 (get ? "RESET" : "POSTED")));
301 rc = DosCreateEventSem(0, &deviceSem, DCE_POSTONE, !get);
302 if (rc) {
303 dprintf(("FlashWaveOut::getDeviceSem - DosCreateEventSem failed - rc= %d", rc));
304 return MMSYSERR_NOTENABLED;
305 }
306 return TRUE;
307 }
308
309 // Post the semaphore so other instances can claim the device.
310 if (!get) {
311 rc = DosPostEventSem(deviceSem);
312 if (rc) {
313 dprintf(("FlashWaveOut::getDeviceSem - DosPostEventSem failed - rc= %d", rc));
314 return FALSE;
315 }
316 return TRUE;
317 }
318
319 // Wait for the semaphore (it will reset itself). Limit the wait
320 // to 5 seconds to avoid causing more problems than we're solving.
321 dprintf(("FlashWaveOut::getDeviceSem - about to wait for event sem"));
322 rc = DosWaitEventSem(deviceSem, 5000);
323 if (rc) {
324 dprintf(("FlashWaveOut::getDeviceSem - DosWaitEventSem failed - rc= %d", rc));
325 return FALSE;
326 }
327
328 return TRUE;
329}
330
331/******************************************************************************/
332/******************************************************************************/
333
334MMRESULT FlashWaveOut::initBuffers()
335{
336 APIRET rc;
337 MCI_GENERIC_PARMS GenericParms = {0};
338 MCI_BUFFER_PARMS BufferParms;
339
340 dprintf(("$ - bufsize= %d", __FUNCTION__, dartBufSize));
341
342 // Set up the BufferParms data structure and
343 // allocate device buffers from the Amp-Mixer.
344 memset(&BufferParms, 0, sizeof(BufferParms));
345 BufferParms.ulStructLength = sizeof(BufferParms);
346 BufferParms.ulNumBuffers = dartBufCnt;
347 BufferParms.ulBufferSize = dartBufSize;
348 BufferParms.pBufList = pmixBuffers;
349
350 rc = mymciSendCommand(deviceId, MCI_BUFFER,
351 MCI_WAIT | MCI_ALLOCATE_MEMORY,
352 (PVOID)&BufferParms, 0);
353 if (LOUSHORT(rc) != MCIERR_SUCCESS) {
354 mciError("FlashWaveOut::initBuffers - MCI_BUFFER", rc);
355 mymciSendCommand(deviceId, MCI_RELEASEDEVICE,
356 MCI_WAIT, (PVOID)&GenericParms, 0);
357 return MMSYSERR_NOTSUPPORTED;
358 }
359
360 // DART may not have allocated all the buffers requested.
361 dartBufCnt = BufferParms.ulNumBuffers;
362 dartFreeCnt = dartBufCnt;
363
364 // Signal that the DART buffers have been created & initialized.
365 dartBufInit = TRUE;
366
367 return MMSYSERR_NOERROR;
368}
369
370/******************************************************************************/
371/******************************************************************************/
372
373MMRESULT FlashWaveOut::write(LPWAVEHDR pwh, UINT cbwh)
374{
375 APIRET rc;
376
377 #ifdef DEBUG
378 showWriteMsg(pwh, dartFreeCnt, queuedbuffers, dartBufInit);
379 #endif
380
381 // Allocation of DART buffers is deferred until the first write
382 // so their size can be based on the size of the Win WAVE buffers.
383 if (!dartBufInit) {
384 dartBufSize = pwh->dwBufferLength;
385 if (!dartBufSize || dartBufSize > 0x10000)
386 return MMSYSERR_INVALPARAM;
387
388 rc = initBuffers();
389 if (rc != MMSYSERR_NOERROR)
390 return rc;
391 }
392
393 // Init members used by the Win MM subsystem.
394 pwh->lpNext = 0;
395 pwh->reserved = 0;
396
397 // Add this header to the tail of the chain of unplayed buffers
398 if (!wavehdr)
399 wavehdr = pwh;
400 else {
401 LPWAVEHDR pTail = wavehdr;
402 while (pTail->lpNext) {
403 pTail = pTail->lpNext;
404 }
405 pTail->lpNext = pwh;
406 }
407 queuedbuffers++;
408
409 // Copy as many WAVE buffers to DART buffers as possible. Exit
410 // if none were copied, or we don't have enough to start playback,
411 writeBuffer();
412 if (!readyCnt || (State != STATE_PLAYING && readyCnt < FLASH_PREFILL))
413 return MMSYSERR_NOERROR;
414
415 // Change the state flag to playing.
416 LONG oldState = DosInterlockedExchange((PLONG)&State, STATE_PLAYING);
417 if (oldState != STATE_PLAYING)
418 dprintf(("state change to PLAYING from %s",
419 (oldState == STATE_STOPPED ? "STOPPED" :
420 (oldState == STATE_PAUSED ? "PAUSED " : "UNKNOWN"))));
421
422 // Write all of the DART buffers that are ready to the device.
423 USHORT selTIB = RestoreOS2FS();
424 if (readyNdx + readyCnt >= dartBufCnt) {
425 ULONG cnt = dartBufCnt - readyNdx;
426 rc = pmixWriteProc(mixHandle, &pmixBuffers[readyNdx], cnt);
427 if (LOUSHORT(rc) != MCIERR_SUCCESS)
428 mciError("FlashWaveOut::write - pmixWriteProc", rc);
429 readyNdx = 0;
430 readyCnt -= cnt;
431 }
432 if (readyCnt) {
433 rc = pmixWriteProc(mixHandle, &pmixBuffers[readyNdx], readyCnt);
434 if (LOUSHORT(rc) != MCIERR_SUCCESS)
435 mciError("FlashWaveOut::write - pmixWriteProc", rc);
436 readyNdx += readyCnt;
437 readyCnt = 0;
438 }
439 SetFS(selTIB);
440
441 return MMSYSERR_NOERROR;
442}
443
444/******************************************************************************/
445/******************************************************************************/
446
447void FlashWaveOut::writeBuffer()
448{
449 // Loop while there are both WAVE buffers & DART buffers available.
450 while (wavehdr && dartFreeCnt) {
451 MIX_EXTRA * pMX;
452
453 // Write one WAVE buffer to as many DART buffers as needed
454 // (both buffers should be the same size, so this shouldn't loop).
455 while (dartFreeCnt && waveOffs < wavehdr->dwBufferLength) {
456 int cnt = wavehdr->dwBufferLength - waveOffs;
457 if (cnt > dartBufSize)
458 cnt = dartBufSize;
459 memcpy(pmixBuffers[dartFreeNdx].pBuffer, &wavehdr->lpData[waveOffs], cnt);
460 pmixBuffers[dartFreeNdx].ulBufferLength = cnt;
461 pMX = (MIX_EXTRA*)pmixBuffers[dartFreeNdx].ulUserParm;
462 pMX->pwh = 0;
463 waveOffs += cnt;
464 readyCnt++;
465 DosInterlockedDecrement((PLONG)&dartFreeCnt);
466 if (++dartFreeNdx >= dartBufCnt)
467 dartFreeNdx = 0;
468 }
469
470 // Exit if the WAVE buffer still has data
471 // but there are no more DART buffers.
472 if (waveOffs < wavehdr->dwBufferLength)
473 return;
474
475 // Remove this wavehdr from the head of the chain and
476 // store it in the MIX_EXTRA struct associated with this
477 // DART buffer for use by the DART event callback proc.
478 waveOffs = 0;
479 pMX->pwh = wavehdr;
480 wavehdr = wavehdr->lpNext;
481 pMX->pwh->lpNext = 0;
482 queuedbuffers--;
483 }
484
485 return;
486}
487
488/******************************************************************************/
489/******************************************************************************/
490
491MMRESULT FlashWaveOut::pause()
492{
493 APIRET rc;
494 MCI_GENERIC_PARMS GenericParms = {0};
495
496 // Pause playback if current state == playing
497 if (DosInterlockedCompareExchange((PLONG)&State, STATE_PAUSED, STATE_PLAYING)
498 == STATE_PLAYING) {
499 rc = mymciSendCommand(deviceId, MCI_PAUSE,
500 MCI_WAIT, (PVOID)&GenericParms, 0);
501 if (LOUSHORT(rc) != MCIERR_SUCCESS)
502 mciError("FlashWaveOut::pause - MCI_PAUSE", rc);
503 }
504
505 return MMSYSERR_NOERROR;
506}
507
508/******************************************************************************/
509/******************************************************************************/
510
511MMRESULT FlashWaveOut::resume()
512{
513 APIRET rc;
514 MCI_GENERIC_PARMS GenericParms = {0};
515
516 dprintf2((__FUNCTION__));
517
518 // Resume playback if current state == paused
519 if (DosInterlockedCompareExchange((PLONG)&State, STATE_PLAYING, STATE_PAUSED)
520 == STATE_PAUSED) {
521 rc = mymciSendCommand(deviceId, MCI_RESUME,
522 MCI_WAIT, (PVOID)&GenericParms, 0);
523 if (LOUSHORT(rc) != MCIERR_SUCCESS)
524 mciError("FlashWaveOut::resume - MCI_RESUME", rc);
525 }
526
527 return MMSYSERR_NOERROR;
528}
529
530/******************************************************************************/
531/******************************************************************************/
532
533MMRESULT FlashWaveOut::stop()
534{
535 APIRET rc;
536 MCI_GENERIC_PARMS GenericParms = {0};
537
538 dprintf2((__FUNCTION__));
539
540 // Stop playback if current state == playing or paused
541 if (DosInterlockedExchange((PLONG)&State, STATE_STOPPED)
542 != STATE_STOPPED) {
543 rc = mymciSendCommand(deviceId, MCI_STOP,
544 MCI_WAIT, (PVOID)&GenericParms, 0);
545 if (LOUSHORT(rc) != MCIERR_SUCCESS)
546 mciError("FlashWaveOut::stop - MCI_STOP", rc);
547 }
548
549 return MMSYSERR_NOERROR;
550}
551
552/******************************************************************************/
553/******************************************************************************/
554
555MMRESULT FlashWaveOut::reset()
556{
557 APIRET rc;
558 MCI_GENERIC_PARMS GenericParms = {0};
559
560 dprintf((__FUNCTION__));
561
562 // Stop playback if current state == playing or paused
563 if (DosInterlockedExchange((PLONG)&State, STATE_STOPPED)
564 != STATE_STOPPED) {
565 rc = mymciSendCommand(deviceId, MCI_STOP,
566 MCI_WAIT, (PVOID)&GenericParms, 0);
567 if (LOUSHORT(rc) != MCIERR_SUCCESS)
568 mciError("FlashWaveOut::reset - MCI_STOP", rc);
569 }
570
571 // Handle the wavehdrs that have already been processed.
572 // Cycle thru every DART buffer, including those that should be
573 // free to ensure that every wavehdr we know about is marked as done.
574 int ndx = dartFreeNdx;
575 for (int ctr = 0; ctr < dartBufCnt; ctr++) {
576 LPWAVEHDR pwh = ((MIX_EXTRA*)pmixBuffers[ndx].ulUserParm)->pwh;
577 if (pwh) {
578 ((MIX_EXTRA*)pmixBuffers[ndx].ulUserParm)->pwh = 0;
579 pwh->lpNext = 0;
580 pwh->dwFlags |= WHDR_DONE;
581 pwh->dwFlags &= ~WHDR_INQUEUE;
582 pwh->reserved = 0;
583 callback(WOM_DONE, (ULONG)pwh, 0);
584 }
585 if (++ndx >= dartBufCnt)
586 ndx = 0;
587 }
588
589 // Handle the wavehdrs that have not been processed yet.
590 while (wavehdr) {
591 LPWAVEHDR pwh = wavehdr;
592 wavehdr = pwh->lpNext;
593 pwh->lpNext = 0;
594 pwh->dwFlags |= WHDR_DONE;
595 pwh->dwFlags &= ~WHDR_INQUEUE;
596 pwh->reserved = 0;
597 callback(WOM_DONE, (ULONG)pwh, 0);
598 }
599
600 // Reset variables to their initial state.
601 waveOffs = 0;
602 dartFreeCnt = dartBufCnt;
603 dartFreeNdx = 0;
604 dartPlayed = 0;
605 readyCnt = 0;
606 readyNdx = 0;
607
608 return MMSYSERR_NOERROR;
609}
610
611/******************************************************************************/
612/******************************************************************************/
613
614ULONG FlashWaveOut::getPosition()
615{
616 // This is the total of all bytes that have already been played.
617 // It increases whenever the DART event callback is notified of
618 // a free buffer (i.e. it is not a realtime, running byte counter).
619
620 return (ULONG)dartPlayed;
621}
622
623/******************************************************************************/
624/******************************************************************************/
625
626MMRESULT FlashWaveOut::setVolume(ULONG ulVol)
627{
628 APIRET rc;
629 ULONG ulVolR = ((ulVol >> 16) * 100) / 0xFFFF;
630 ULONG ulVolL = ((ulVol & 0xffff) * 100) / 0xFFFF;
631 MCI_SET_PARMS SetParms = {0};
632
633 dprintf2((__FUNCTION__));
634
635 volume = ulVol;
636
637// Some drivers can't set left & right volumes independently
638#ifdef GOOD_AUDIO_CARD_DRIVER
639 SetParms.ulAudio = MCI_SET_AUDIO_LEFT;
640 SetParms.ulLevel = ulVolL;
641
642 rc = mymciSendCommand(deviceId, MCI_SET,
643 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
644 &SetParms, 0);
645 if (LOUSHORT(rc) != MCIERR_SUCCESS)
646 mciError("FlashWaveOut::setVolume - MCI_SET (volume)", rc);
647
648 SetParms.ulAudio = MCI_SET_AUDIO_RIGHT;
649 SetParms.ulLevel = ulVolR;
650#else
651 SetParms.ulAudio = MCI_SET_AUDIO_ALL;
652 SetParms.ulLevel = (ulVolR + ulVolL) / 2;
653#endif
654
655 rc = mymciSendCommand(deviceId, MCI_SET,
656 MCI_WAIT | MCI_SET_AUDIO | MCI_SET_VOLUME,
657 &SetParms, 0);
658 if (LOUSHORT(rc) != MCIERR_SUCCESS)
659 mciError("FlashWaveOut::setVolume - MCI_SET (volume)", rc);
660
661 return MMSYSERR_NOERROR;
662}
663
664/******************************************************************************/
665/******************************************************************************/
666
667LONG APIENTRY FlashWaveOutHandler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
668 ULONG ulFlags)
669{
670 if (!pBuffer ||
671 !pBuffer->ulUserParm ||
672 !((MIX_EXTRA*)pBuffer->ulUserParm)->pThis) {
673 fprintf(stderr, "FlashWaveOutHandler - no object ptr - "
674 "pBuffer= %x ulStatus= %x ulFlags= %x\n",
675 pBuffer, ulStatus, ulFlags);
676 }
677 else {
678 ((MIX_EXTRA*)pBuffer->ulUserParm)->pThis->handler(ulStatus, pBuffer, ulFlags);
679 }
680
681 return TRUE;
682}
683
684/******************************************************************************/
685/******************************************************************************/
686
687void FlashWaveOut::handler(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
688{
689 if (ulFlags == MIX_STREAM_ERROR) {
690
691 // out of buffers, so pause playback
692 if (ulStatus == ERROR_DEVICE_UNDERRUN) {
693 pause();
694 dprintf(("FlashWaveOut::handler - Hardware Underrun, state= %s",
695 (State == STATE_PLAYING) ? "playing" : "stopped"));
696 }
697 else
698 dprintf(("FlashWaveOut::handler - Unknown Error= %x", ulStatus));
699 return;
700 }
701
702 // If there are fewer than FLASH_PREFILL-1 buffers in use,
703 // pause the device or else we're likely to have an underrun.
704 // Do NOT inc dartFreeCnt until we're done with this buffer.
705 // If this is the only one available, the other thread might
706 // change something we need below.
707 if (State == STATE_PLAYING && dartFreeCnt > dartBufCnt - FLASH_PREFILL)
708 pause();
709
710 // Get the wavehdr associated with this DART buffer (if any),
711 // then clear the buffer's reference to it.
712 LPWAVEHDR pwh = ((MIX_EXTRA*)pBuffer->ulUserParm)->pwh;
713 ((MIX_EXTRA*)pBuffer->ulUserParm)->pwh = 0;
714
715 // If the device is supposed to be stopped, don't update variables that
716 // are used by the other thread because ::reset() may have cleared them.
717 if (State != STATE_STOPPED) {
718 // Add the size of this buffer to the total played. A locked
719 // add operation may not be necessary but is used "just in case".
720 DosInterlockedExchangeAdd((PLONG)&dartPlayed, pBuffer->ulBufferLength);
721
722 // Now that we're done with the buffer, we can inc the free count.
723 // As above, the locked increament may be unnecessary.
724 DosInterlockedIncrement((PLONG)&dartFreeCnt);
725 }
726
727 // On the first call to this function, create a Win32 TEB (equivalent
728 // to an OS/2 TIB) for this thread. Without it, the Win callback will
729 // be called on this thread with the TEB for the primary thread (which
730 // is probably a bad idea). Note: the DART thread persists for the life
731 // of the app, so all instances of FlashWaveOut will use the same TEB.
732
733 static USHORT odinFS = 0;
734 if (!odinFS) {
735 if (ODIN_ThreadEnterOdinContext(0, TRUE))
736 odinFS = RestoreOS2FS();
737 else {
738 odinFS = (USHORT)-1;
739 dprintf(("FlashWaveOut::handler - ODIN_ThreadEnterOdinContext failed"));
740 }
741 }
742
743 // Switch to this thread's Win FS selector, then notify
744 // the Win client that it's buffer has been played.
745 if (pwh) {
746 pwh->lpNext = 0;
747 pwh->reserved = 0;
748 pwh->dwFlags &= ~WHDR_INQUEUE;
749 pwh->dwFlags |= WHDR_DONE;
750 if (odinFS != (USHORT)-1)
751 SetFS(odinFS);
752 callback(WOM_DONE, (ULONG)pwh, 0);
753 RestoreOS2FS();
754 }
755
756 return;
757}
758
759/******************************************************************************/
760// Debug messages
761/******************************************************************************/
762
763// Displays the text associated with an MCI error code.
764
765void FlashWaveOut::mciError(const char * msg, ULONG rc)
766{
767#ifdef DEBUG
768 char szError[64] = "";
769
770 mymciGetErrorString(rc, szError, sizeof(szError));
771 dprintf(("%s failed - '%s'", msg, szError));
772#endif
773
774 return;
775}
776
777/******************************************************************************/
778/******************************************************************************/
779#ifdef DEBUG
780
781// This offers a potentially incorrect count of the number of WAVE
782// buffers in use. It saves the address of the very first buffer
783// written, then counts how many writes occur before it's reused.
784// It only displays a message if the count changes.
785
786void showWriteMsg(LPWAVEHDR pwh, int free, int queued, BOOL fInit)
787{
788 static int bufctr = 0;
789 static int buflast = 0;
790 static LPWAVEHDR pwhFirst = 0;
791
792 bufctr++;
793 if (!fInit) {
794 pwhFirst = pwh;
795 }
796 else
797 if (pwhFirst == pwh) {
798 if (bufctr != buflast) {
799 dprintf(("FlashWaveOut::write - bufctr= %d free= %d queued= %d",
800 bufctr, free, queued));
801 buflast = bufctr;
802 }
803 bufctr = 0;
804 }
805
806 return;
807}
808
809#endif
810/******************************************************************************/
811/******************************************************************************/
812
Note: See TracBrowser for help on using the repository browser.