source: trunk/src/winmm/waveoutdaud.cpp@ 5376

Last change on this file since 5376 was 5376, checked in by sandervl, 24 years ago

setvolume change

File size: 13.3 KB
Line 
1/* $Id: waveoutdaud.cpp,v 1.3 2001-03-25 21:53:05 sandervl Exp $ */
2
3/*
4 * Wave playback class (DirectAudio)
5 *
6 * Copyright 2001 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13
14/****************************************************************************
15 * Includes *
16 ****************************************************************************/
17
18
19
20#define INCL_BASE
21#define INCL_OS2MM
22#include <os2wrap.h> //Odin32 OS/2 api wrappers
23#include <os2mewrap.h> //Odin32 OS/2 MMPM/2 api wrappers
24#include <stdlib.h>
25#include <string.h>
26#define OS2_ONLY
27#include <win32api.h>
28#include <wprocess.h>
29#include <audio.h>
30#include <daudio.h>
31
32#include "misc.h"
33#include "waveoutdaud.h"
34
35#define DBG_LOCALLOG DBG_waveoutdaud
36#include "dbglocal.h"
37
38DWORD WIN32API DAudioThreadHandler(LPVOID pUserData);
39
40//TODO: mulaw, alaw & adpcm
41/******************************************************************************/
42/******************************************************************************/
43DAudioWaveOut::DAudioWaveOut(LPWAVEFORMATEX pwfx, ULONG fdwOpen, ULONG nCallback, ULONG dwInstance)
44 : WaveOut(pwfx, fdwOpen, nCallback, dwInstance)
45{
46 APIRET rc;
47 ULONG action;
48 HFILE hDriver;
49 MCI_AUDIO_INIT init = {0};
50 DAUDIO_CMD cmd;
51 ULONG ParmLength = 0, DataLength;
52
53 fUnderrun = FALSE;
54 hSem = 0;
55 setVolume(volume);
56
57 rc = DosOpen("DAUDIO1$", &hDAudioDrv, &action, 0,
58 FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
59 OPEN_SHARE_DENYNONE | OPEN_FLAGS_WRITE_THROUGH,
60 NULL );
61 if(rc) {
62 dprintf(("DosOpen failed with error %d\n", rc));
63 ulError = MMSYSERR_NODRIVER;
64 goto fail;
65 }
66
67 DataLength = sizeof(init);
68
69 init.lSRate = pwfx->nSamplesPerSec;
70 init.lBitsPerSRate = pwfx->wBitsPerSample;
71 init.sChannels = pwfx->nChannels;
72 init.sMode = PCM; //todo!!
73
74 rc = DosDevIOCtl(hDAudioDrv, DAUDIO_IOCTL_CAT, DAUDIO_OPEN, NULL, 0,
75 &ParmLength, &init, DataLength, &DataLength);
76 if(rc) {
77 dprintf(("DosDevIOCtl failed with error %d\n", rc));
78 ulError = MMSYSERR_NODRIVER;
79 goto fail;
80 }
81 if(init.sReturnCode != 0) {
82 dprintf(("init.sReturnCode = %d\n", init.sReturnCode));
83 ulError = MMSYSERR_NODRIVER;
84 goto fail;
85 }
86
87 rc = DosCreateEventSem(NULL, &hSem, DC_SEM_SHARED, 0);
88 if(rc) {
89 dprintf(("DosCreateEventSem failed with error %d\n", rc));
90 ulError = MMSYSERR_NODRIVER;
91 goto fail;
92 }
93 cmd.Thread.hSemaphore = hSem;
94 rc = DosDevIOCtl(hDAudioDrv, DAUDIO_IOCTL_CAT, DAUDIO_REGISTER_THREAD, NULL, 0,
95 &ParmLength, &cmd, DataLength, &DataLength);
96 if(rc) {
97 dprintf(("DosDevIOCtl failed with error %d\n", rc));
98 ulError = MMSYSERR_NODRIVER;
99 goto fail;
100 }
101
102 hThread = CreateThread(NULL, 0x4000, (LPTHREAD_START_ROUTINE)DAudioThreadHandler,
103 (LPVOID)this, 0, &dwThreadID);
104
105 if(!ulError)
106 callback(WOM_OPEN, 0, 0);
107
108fail:
109 return;
110}
111/******************************************************************************/
112/******************************************************************************/
113DAudioWaveOut::~DAudioWaveOut()
114{
115 DAUDIO_CMD cmd;
116
117 if(!ulError)
118 callback(WOM_CLOSE, 0, 0);
119
120 if(hDAudioDrv) {
121 cmd.Thread.hSemaphore = hSem;
122 sendIOCTL(DAUDIO_DEREGISTER_THREAD, &cmd);
123 sendIOCTL(DAUDIO_CLOSE, &cmd);
124 DosClose(hDAudioDrv);
125 hDAudioDrv = 0;
126 }
127 if(hSem) {
128 DosCloseEventSem(hSem);
129 }
130}
131/******************************************************************************/
132/******************************************************************************/
133MMRESULT DAudioWaveOut::write(LPWAVEHDR pwh, UINT cbwh)
134{
135 DAUDIO_CMD cmd;
136
137 queuedbuffers++;
138 pwh->lpNext = NULL;
139 pwh->reserved = 0;
140 wmutex.enter(VMUTEX_WAIT_FOREVER);
141 if(wavehdr) {
142 WAVEHDR *chdr = wavehdr;
143 while(chdr->lpNext) {
144 chdr = chdr->lpNext;
145 }
146 chdr->lpNext = pwh;
147 }
148 else wavehdr = pwh;
149
150 wmutex.leave();
151
152 cmd.Buffer.lpBuffer = (ULONG)pwh->lpData;
153 cmd.Buffer.ulBufferLength = pwh->dwBufferLength;
154 if(sendIOCTL(DAUDIO_ADDBUFFER, &cmd)) {
155 dprintf(("Unable to add buffer!!!!!"));
156 return MMSYSERR_ERROR;
157 }
158
159 if(State == STATE_STOPPED) {//continue playback
160 restart();
161 }
162 else
163 if(fUnderrun) {
164 dprintf(("Resume playback after underrun"));
165 fUnderrun = FALSE;
166 State = STATE_PLAYING;
167
168 // Resume the playback.
169 resume();
170 }
171 return(MMSYSERR_NOERROR);
172}
173/******************************************************************************/
174/******************************************************************************/
175MMRESULT DAudioWaveOut::pause()
176{
177 DAUDIO_CMD cmd;
178
179 dprintf(("WINMM: DAudioWaveOut::pause"));
180
181 // Pause the playback.
182 sendIOCTL(DAUDIO_PAUSE, &cmd);
183
184 wmutex.enter(VMUTEX_WAIT_FOREVER);
185 if(State != STATE_PLAYING) {
186 State = STATE_PAUSED;
187 wmutex.leave();
188 return(MMSYSERR_NOERROR);
189 }
190
191 State = STATE_PAUSED;
192 wmutex.leave();
193
194 return(MMSYSERR_NOERROR);
195}
196/******************************************************************************/
197/******************************************************************************/
198MMRESULT DAudioWaveOut::resume()
199{
200 DAUDIO_CMD cmd;
201
202 return sendIOCTL(DAUDIO_RESUME, &cmd);
203}
204/******************************************************************************/
205/******************************************************************************/
206MMRESULT DAudioWaveOut::stop()
207{
208 DAUDIO_CMD cmd;
209 MMRESULT rc;
210
211 dprintf(("DAudioWaveOut::stop %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
212 if(State != STATE_PLAYING)
213 return(MMSYSERR_HANDLEBUSY);
214
215 // Stop the playback.
216 rc = sendIOCTL(DAUDIO_STOP, &cmd);
217
218 State = STATE_STOPPED;
219 fUnderrun = FALSE;
220
221 bytesPlayed = bytesCopied = bytesReturned = 0;
222
223 return rc;
224}
225/******************************************************************************/
226/******************************************************************************/
227MMRESULT DAudioWaveOut::reset()
228{
229 DAUDIO_CMD cmd;
230 LPWAVEHDR tmpwavehdr;
231
232 dprintf(("DAudioWaveOut::reset %s", (State == STATE_PLAYING) ? "playing" : "stopped"));
233 if(State != STATE_PLAYING)
234 return(MMSYSERR_HANDLEBUSY);
235
236 // Stop the playback.
237 sendIOCTL(DAUDIO_STOP, &cmd);
238
239 wmutex.enter(VMUTEX_WAIT_FOREVER);
240 while(wavehdr)
241 {
242 wavehdr->dwFlags |= WHDR_DONE;
243 wavehdr->dwFlags &= ~WHDR_INQUEUE;
244 wavehdr->reserved = 0;
245 tmpwavehdr = wavehdr;
246 wavehdr = wavehdr->lpNext;
247 tmpwavehdr->lpNext = NULL;
248 wmutex.leave();
249
250 callback(WOM_DONE, (ULONG)tmpwavehdr, 0);
251 wmutex.enter(VMUTEX_WAIT_FOREVER);
252 }
253 wavehdr = NULL;
254 State = STATE_STOPPED;
255 fUnderrun = FALSE;
256
257 bytesPlayed = bytesCopied = bytesReturned = 0;
258 queuedbuffers = 0;
259
260 wmutex.leave();
261 return(MMSYSERR_NOERROR);
262}
263/******************************************************************************/
264/******************************************************************************/
265MMRESULT DAudioWaveOut::restart()
266{
267 DAUDIO_CMD cmd;
268
269 dprintf(("DAudioWaveOut::restart"));
270 if(State == STATE_PLAYING)
271 return(MMSYSERR_NOERROR);
272
273 wmutex.enter(VMUTEX_WAIT_FOREVER);
274 State = STATE_PLAYING;
275 fUnderrun = FALSE;
276 wmutex.leave();
277
278 return sendIOCTL(DAUDIO_START, &cmd);
279}
280/******************************************************************************/
281/******************************************************************************/
282ULONG DAudioWaveOut::getPosition()
283{
284 DAUDIO_CMD cmd;
285 MMRESULT rc;
286
287 rc = sendIOCTL(DAUDIO_GETPOS, &cmd);
288 if(rc) {
289 return 0xFFFFFFFF;
290 }
291 return cmd.Pos.ulCurrentPos;
292}
293/******************************************************************************/
294/******************************************************************************/
295BOOL DAudioWaveOut::queryFormat(ULONG formatTag, ULONG nChannels, ULONG nSamplesPerSec, ULONG sampleSize)
296{
297 ULONG ParmLength = 0, DataLength;
298 MCI_AUDIO_INIT init = {0};
299 APIRET rc;
300 ULONG action;
301 HFILE hDriver;
302
303 rc = DosOpen("DAUDIO1$", &hDriver, &action, 0,
304 FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
305 OPEN_SHARE_DENYNONE | OPEN_FLAGS_WRITE_THROUGH,
306 NULL );
307 if(rc) {
308 dprintf(("DosOpen failed with error %d\n", rc));
309 return FALSE;
310 }
311
312 DataLength = sizeof(init);
313
314 init.lSRate = nSamplesPerSec;
315 init.lBitsPerSRate = sampleSize;
316 init.sChannels = nChannels;
317 init.sMode = PCM; //TODO: check formattag for ulaw/alaw/adpcm
318 rc = DosDevIOCtl(hDriver, DAUDIO_IOCTL_CAT, DAUDIO_QUERYFORMAT, NULL, 0,
319 &ParmLength, &init, DataLength, &DataLength);
320
321 if(rc) {
322 dprintf(("DosDevIOCtl failed with error %d\n", rc));
323 goto fail;
324 }
325 if(init.sReturnCode != 0) {
326 dprintf(("init.sReturnCode = %d\n", init.sReturnCode));
327 goto fail;
328 }
329
330 DosClose(hDriver);
331 return TRUE;
332
333fail:
334 DosClose(hDriver);
335 return FALSE;
336}
337/******************************************************************************/
338/******************************************************************************/
339BOOL DAudioWaveOut::isDirectAudioAvailable()
340{
341 static BOOL fAvailable = FALSE;
342 static BOOL fTested = FALSE;
343
344 APIRET rc;
345 ULONG action;
346 HFILE hDriver;
347
348 if(!fTested) {
349 rc = DosOpen("DAUDIO1$", &hDriver, &action, 0,
350 FILE_NORMAL, FILE_OPEN, OPEN_ACCESS_READWRITE |
351 OPEN_SHARE_DENYNONE | OPEN_FLAGS_WRITE_THROUGH,
352 NULL );
353 fTested = TRUE;
354 if(rc) {
355 return FALSE;
356 }
357 DosClose(hDriver);
358 fAvailable = TRUE;
359 }
360 return fAvailable;
361
362}
363/******************************************************************************/
364/******************************************************************************/
365MMRESULT DAudioWaveOut::setVolume(ULONG ulVol)
366{
367 DAUDIO_CMD cmd;
368
369 //Scale down from 0-64k-1 -> 0-100
370 cmd.Vol.VolumeR = (((ulVol & 0xFFFF0000) >> 16)*100)/0xFFFF;
371 cmd.Vol.VolumeL = ((ulVol & 0x0000FFFF) *100)/0xFFFF;
372 return sendIOCTL(DAUDIO_SETVOLUME, &cmd);
373}
374/******************************************************************************/
375/******************************************************************************/
376MMRESULT DAudioWaveOut::sendIOCTL(ULONG cmd, DAUDIO_CMD *pDataPacket)
377{
378 ULONG DataLength, ParmLength = 0;
379 APIRET rc;
380
381 DataLength = sizeof(DAUDIO_CMD);
382
383 rc = DosDevIOCtl(hDAudioDrv, DAUDIO_IOCTL_CAT, cmd, NULL, 0,
384 &ParmLength, pDataPacket, DataLength, &DataLength);
385 if(rc) {
386 dprintf(("DosDevIOCtl failed with error %d (command %d)", rc, cmd));
387 return MMSYSERR_ERROR;
388 }
389 return(MMSYSERR_NOERROR);
390
391}
392/******************************************************************************/
393//TODO: Not entirely safe. (assumption that we get called for each buffer so we
394// always notify the win32 app for each buffer that was processed)
395/******************************************************************************/
396void DAudioWaveOut::handler()
397{
398 LPWAVEHDR whdr = wavehdr;
399
400 dprintf2(("WINMM: handler buf %X done (play %d/%d, cop %d, ret %d)", whdr, bytesPlayed, getPosition(), bytesCopied, bytesReturned));
401
402 wmutex.enter();
403 queuedbuffers--;
404 whdr->dwFlags &= ~WHDR_INQUEUE;
405 whdr->dwFlags |= WHDR_DONE;
406 whdr->reserved = 0;
407 wavehdr = whdr->lpNext;
408 whdr->lpNext = NULL;
409
410 bytesReturned += whdr->dwBufferLength;
411 wmutex.leave();
412
413 callback(WOM_DONE, (ULONG)whdr, 0);
414}
415/******************************************************************************/
416/******************************************************************************/
417DWORD WIN32API DAudioThreadHandler(LPVOID pUserData)
418{
419 APIRET rc;
420 ULONG postcnt;
421 HEV hSem;
422
423 DAudioWaveOut *dwave = (DAudioWaveOut *)pUserData;
424
425 if(WaveOut::find(dwave) == FALSE) {
426 dprintf(("DAudioThreadHandler: can't find waveout stream %x!!!", pUserData));
427 return 0;
428 }
429 hSem = dwave->hSem;
430
431 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0);
432
433 while(TRUE)
434 {
435 dprintf2(("Waiting for buffer notification\n"));
436 rc = DosWaitEventSem(hSem, SEM_INDEFINITE_WAIT);
437 if(rc) {
438 dprintf(("DosWaitEventSem failed with error %d\n", rc));
439 return 0;
440 }
441
442 rc = DosResetEventSem(hSem, &postcnt);
443 if(rc) {
444 dprintf(("DosWaitEventSem failed with error %d\n", rc));
445 return 0;
446 }
447 for(int i=0;i<postcnt;i++) {
448 dwave->handler();
449 }
450 }
451
452}
453/******************************************************************************/
454/******************************************************************************/
455
Note: See TracBrowser for help on using the repository browser.