1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
21 #include <sys/ioctl.h>
32 #ifdef HAVE_MACHINE_SOUNDCARD_H
33 # include <machine/soundcard.h>
35 #ifdef HAVE_SYS_SOUNDCARD_H
36 # include <sys/soundcard.h>
39 #define SOUND_DEV "/dev/dsp"
40 #define MIXER_DEV "/dev/mixer"
43 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
45 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
48 #define MAX_WAVOUTDRV (1)
49 #define MAX_WAVINDRV (1)
50 #define MAX_MCIWAVDRV (1)
56 WAVEOPENDESC waveDesc
;
66 DWORD bufsize
; /* OpenSound '/dev/dsp' give us that size */
67 WAVEOPENDESC waveDesc
;
71 DWORD dwTotalRecorded
;
75 int nUseCount
; /* Incremented for each shared open */
76 BOOL16 fShareable
; /* TRUE if first open was shareable */
77 WORD wNotifyDeviceID
;/* MCI device ID with a pending notification */
78 HANDLE16 hCallback
; /* Callback handle for pending notification */
79 HMMIO32 hFile
; /* mmio file handle open as Element */
80 MCI_WAVE_OPEN_PARMS16 openParms
;
81 PCMWAVEFORMAT WaveFormat
;
83 BOOL16 fInput
; /* FALSE = Output, TRUE = Input */
86 static WINE_WAVEOUT WOutDev
[MAX_WAVOUTDRV
];
87 static WINE_WAVEIN WInDev
[MAX_WAVOUTDRV
];
88 static WINE_MCIWAVE MCIWavDev
[MAX_MCIWAVDRV
];
90 /**************************************************************************
91 * WAVE_NotifyClient [internal]
93 static DWORD
WAVE_NotifyClient(UINT16 wDevID
, WORD wMsg
,
94 DWORD dwParam1
, DWORD dwParam2
)
96 TRACE(mciwave
,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID
, wMsg
, dwParam1
, dwParam2
);
102 if (wDevID
> MAX_WAVOUTDRV
) return MCIERR_INTERNAL
;
104 if (WOutDev
[wDevID
].wFlags
!= DCB_NULL
&& !DriverCallback(
105 WOutDev
[wDevID
].waveDesc
.dwCallBack
,
106 WOutDev
[wDevID
].wFlags
,
107 WOutDev
[wDevID
].waveDesc
.hWave
,
109 WOutDev
[wDevID
].waveDesc
.dwInstance
,
112 WARN(mciwave
, "can't notify client !\n");
113 return MMSYSERR_NOERROR
;
120 if (wDevID
> MAX_WAVINDRV
) return MCIERR_INTERNAL
;
122 if (WInDev
[wDevID
].wFlags
!= DCB_NULL
&& !DriverCallback(
123 WInDev
[wDevID
].waveDesc
.dwCallBack
, WInDev
[wDevID
].wFlags
,
124 WInDev
[wDevID
].waveDesc
.hWave
, wMsg
,
125 WInDev
[wDevID
].waveDesc
.dwInstance
, dwParam1
, dwParam2
)) {
126 WARN(mciwave
, "can't notify client !\n");
127 return MMSYSERR_NOERROR
;
135 /**************************************************************************
136 * WAVE_mciOpen [internal]
138 static DWORD
WAVE_mciOpen(UINT16 wDevID
, DWORD dwFlags
, void* lp
, BOOL32 is32
)
140 LPPCMWAVEFORMAT lpWaveFormat
;
141 WAVEOPENDESC waveDesc
;
145 TRACE(mciwave
,"(%04X, %08lX, %p)\n", wDevID
, dwFlags
, lp
);
146 if (lp
== NULL
) return MCIERR_INTERNAL
;
148 if (is32
) dwDeviceID
= ((LPMCI_OPEN_PARMS32A
)lp
)->wDeviceID
;
149 else dwDeviceID
= ((LPMCI_OPEN_PARMS16
)lp
)->wDeviceID
;
151 if (MCIWavDev
[wDevID
].nUseCount
> 0) {
152 /* The driver already open on this channel */
153 /* If the driver was opened shareable before and this open specifies */
154 /* shareable then increment the use count */
155 if (MCIWavDev
[wDevID
].fShareable
&& (dwFlags
& MCI_OPEN_SHAREABLE
))
156 ++MCIWavDev
[wDevID
].nUseCount
;
158 return MCIERR_MUST_USE_SHAREABLE
;
160 MCIWavDev
[wDevID
].nUseCount
= 1;
161 MCIWavDev
[wDevID
].fShareable
= dwFlags
& MCI_OPEN_SHAREABLE
;
164 MCIWavDev
[wDevID
].fInput
= FALSE
;
166 TRACE(mciwave
,"wDevID=%04X\n", wDevID
);
167 TRACE(mciwave
,"before OPEN_ELEMENT\n");
168 if (dwFlags
& MCI_OPEN_ELEMENT
) {
169 LPSTR lpstrElementName
;
171 if (is32
) lpstrElementName
= ((LPMCI_WAVE_OPEN_PARMS32A
)lp
)->lpstrElementName
;
172 else lpstrElementName
= (LPSTR
)PTR_SEG_TO_LIN(((LPMCI_WAVE_OPEN_PARMS16
)lp
)->lpstrElementName
);
174 TRACE(mciwave
,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName
);
175 if (lpstrElementName
&& (strlen(lpstrElementName
) > 0)) {
176 MCIWavDev
[wDevID
].hFile
= mmioOpen32A(lpstrElementName
, NULL
,
177 MMIO_ALLOCBUF
| MMIO_READWRITE
| MMIO_EXCLUSIVE
);
178 if (MCIWavDev
[wDevID
].hFile
== 0) {
179 WARN(mciwave
, "can't find file='%s' !\n", lpstrElementName
);
180 return MCIERR_FILE_NOT_FOUND
;
184 MCIWavDev
[wDevID
].hFile
= 0;
186 TRACE(mciwave
,"hFile=%u\n", MCIWavDev
[wDevID
].hFile
);
187 memcpy(&MCIWavDev
[wDevID
].openParms
, lp
, sizeof(MCI_WAVE_OPEN_PARMS16
));
188 MCIWavDev
[wDevID
].wNotifyDeviceID
= dwDeviceID
;
189 lpWaveFormat
= &MCIWavDev
[wDevID
].WaveFormat
;
193 lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
194 lpWaveFormat->wBitsPerSample = 8;
195 lpWaveFormat->wf.nChannels = 1;
196 lpWaveFormat->wf.nSamplesPerSec = 11025;
197 lpWaveFormat->wf.nAvgBytesPerSec = 11025;
198 lpWaveFormat->wf.nBlockAlign = 1;
200 if (MCIWavDev
[wDevID
].hFile
!= 0) {
203 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &ckMainRIFF
, NULL
, 0) != 0)
204 return MCIERR_INTERNAL
;
205 TRACE(mciwave
, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
206 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
,
208 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
209 (ckMainRIFF
.fccType
!= mmioFOURCC('W', 'A', 'V', 'E')))
210 return MCIERR_INTERNAL
;
211 mmckInfo
.ckid
= mmioFOURCC('f', 'm', 't', ' ');
212 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &mmckInfo
, &ckMainRIFF
, MMIO_FINDCHUNK
) != 0)
213 return MCIERR_INTERNAL
;
214 TRACE(mciwave
, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
215 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
,
217 if (mmioRead32(MCIWavDev
[wDevID
].hFile
, (HPSTR
) lpWaveFormat
,
218 (long) sizeof(PCMWAVEFORMAT
)) != (long) sizeof(PCMWAVEFORMAT
))
219 return MCIERR_INTERNAL
;
220 mmckInfo
.ckid
= mmioFOURCC('d', 'a', 't', 'a');
221 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &mmckInfo
, &ckMainRIFF
, MMIO_FINDCHUNK
) != 0)
222 return MCIERR_INTERNAL
;
223 TRACE(mciwave
,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
224 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
,
226 TRACE(mciwave
, "nChannels=%d nSamplesPerSec=%ld\n",
227 lpWaveFormat
->wf
.nChannels
, lpWaveFormat
->wf
.nSamplesPerSec
);
228 lpWaveFormat
->wBitsPerSample
= 0;
230 lpWaveFormat
->wf
.nAvgBytesPerSec
=
231 lpWaveFormat
->wf
.nSamplesPerSec
* lpWaveFormat
->wf
.nBlockAlign
;
232 waveDesc
.lpFormat
= (LPWAVEFORMAT
)lpWaveFormat
;
235 By default the device will be opened for output, the MCI_CUE function is there to
236 change from output to input and back
239 dwRet
=wodMessage(wDevID
,WODM_OPEN
,0,(DWORD
)&waveDesc
,CALLBACK_NULL
);
243 /**************************************************************************
244 * WAVE_mciCue [internal]
247 static DWORD
WAVE_mciCue(UINT16 wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
252 This routine is far from complete. At the moment only a check is done on the
253 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
256 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
261 WAVEOPENDESC waveDesc
;
263 TRACE(mciwave
,"(%u, %08lX, %p);\n", wDevID
, dwParam
, lpParms
);
265 /* always close elements ? */
267 if (MCIWavDev
[wDevID
].hFile
!= 0) {
268 mmioClose32(MCIWavDev
[wDevID
].hFile
, 0);
269 MCIWavDev
[wDevID
].hFile
= 0;
272 dwRet
= MMSYSERR_NOERROR
; /* assume success */
273 if ((dwParam
& MCI_WAVE_INPUT
) && !MCIWavDev
[wDevID
].fInput
) {
274 /* FIXME this is just a hack WOutDev should be hidden here */
275 memcpy(&waveDesc
,&WOutDev
[wDevID
].waveDesc
,sizeof(WAVEOPENDESC
));
277 dwRet
= wodMessage(wDevID
, WODM_CLOSE
, 0, 0L, 0L);
278 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
279 dwRet
= widMessage(wDevID
, WIDM_OPEN
, 0, (DWORD
)&waveDesc
, CALLBACK_NULL
);
280 MCIWavDev
[wDevID
].fInput
= TRUE
;
282 else if (MCIWavDev
[wDevID
].fInput
) {
283 /* FIXME this is just a hack WInDev should be hidden here */
284 memcpy(&waveDesc
,&WInDev
[wDevID
].waveDesc
,sizeof(WAVEOPENDESC
));
286 dwRet
= widMessage(wDevID
, WIDM_CLOSE
, 0, 0L, 0L);
287 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
288 dwRet
= wodMessage(wDevID
, WODM_OPEN
, 0, (DWORD
)&waveDesc
, CALLBACK_NULL
);
289 MCIWavDev
[wDevID
].fInput
= FALSE
;
294 /**************************************************************************
295 * WAVE_mciClose [internal]
297 static DWORD
WAVE_mciClose(UINT16 wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
301 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwParam
, lpParms
);
302 MCIWavDev
[wDevID
].nUseCount
--;
303 if (MCIWavDev
[wDevID
].nUseCount
== 0) {
304 if (MCIWavDev
[wDevID
].hFile
!= 0) {
305 mmioClose32(MCIWavDev
[wDevID
].hFile
, 0);
306 MCIWavDev
[wDevID
].hFile
= 0;
308 if (MCIWavDev
[wDevID
].fInput
)
309 dwRet
= widMessage(wDevID
, WIDM_CLOSE
, 0, 0L, 0L);
311 dwRet
= wodMessage(wDevID
, WODM_CLOSE
, 0, 0L, 0L);
313 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
319 /**************************************************************************
320 * WAVE_mciPlay [internal]
322 static DWORD
WAVE_mciPlay(UINT16 wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
330 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
332 if (MCIWavDev
[wDevID
].fInput
) {
333 WARN(mciwave
, "cannot play on input device\n");
334 return MCIERR_NONAPPLICABLE_FUNCTION
;
337 if (MCIWavDev
[wDevID
].hFile
== 0) {
338 WARN(mciwave
, "can't find file='%08lx' !\n",
339 MCIWavDev
[wDevID
].openParms
.lpstrElementName
);
340 return MCIERR_FILE_NOT_FOUND
;
342 start
= 1; end
= 99999;
343 if (dwFlags
& MCI_FROM
) {
344 start
= lpParms
->dwFrom
;
345 TRACE(mciwave
, "MCI_FROM=%d \n", start
);
347 if (dwFlags
& MCI_TO
) {
349 TRACE(mciwave
,"MCI_TO=%d \n", end
);
352 if (dwFlags
& MCI_NOTIFY
) {
353 TRACE(mciwave
, "MCI_NOTIFY %08lX !\n", lpParms
->dwCallback
);
356 WARN(mciwave
, "Can't 'fork' process !\n");
361 TRACE(mciwave
,"process started ! return to caller...\n");
367 lpWaveHdr
= &MCIWavDev
[wDevID
].WaveHdr
;
368 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
369 lpWaveHdr
->lpData
= (LPSTR
) GlobalLock16(hData
);
370 lpWaveHdr
->dwUser
= 0L;
371 lpWaveHdr
->dwFlags
= 0L;
372 lpWaveHdr
->dwLoops
= 0L;
373 dwRet
=wodMessage(wDevID
,WODM_PREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
375 count
= mmioRead32(MCIWavDev
[wDevID
].hFile
, lpWaveHdr
->lpData
, bufsize
);
376 TRACE(mciwave
,"mmioRead bufsize=%ld count=%ld\n", bufsize
, count
);
377 if (count
< 1) break;
378 lpWaveHdr
->dwBufferLength
= count
;
379 /* lpWaveHdr->dwBytesRecorded = count; */
380 TRACE(mciwave
,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
381 lpWaveHdr
, lpWaveHdr
->dwBufferLength
, lpWaveHdr
->dwBytesRecorded
);
382 dwRet
=wodMessage(wDevID
,WODM_WRITE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
384 dwRet
= wodMessage(wDevID
,WODM_UNPREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
385 if (lpWaveHdr
->lpData
!= NULL
) {
386 GlobalUnlock16(hData
);
388 lpWaveHdr
->lpData
= NULL
;
390 if (dwFlags
& MCI_NOTIFY
) {
391 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
392 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
393 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
399 /**************************************************************************
400 * WAVE_mciRecord [internal]
402 static DWORD
WAVE_mciRecord(UINT16 wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
410 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
412 if (!MCIWavDev
[wDevID
].fInput
) {
413 WARN(mciwave
, "cannot record on output device\n");
414 return MCIERR_NONAPPLICABLE_FUNCTION
;
417 if (MCIWavDev
[wDevID
].hFile
== 0) {
418 WARN(mciwave
, "can't find file='%08lx' !\n",
419 MCIWavDev
[wDevID
].openParms
.lpstrElementName
);
420 return MCIERR_FILE_NOT_FOUND
;
422 start
= 1; end
= 99999;
423 if (dwFlags
& MCI_FROM
) {
424 start
= lpParms
->dwFrom
;
425 TRACE(mciwave
, "MCI_FROM=%d \n", start
);
427 if (dwFlags
& MCI_TO
) {
429 TRACE(mciwave
,"MCI_TO=%d \n", end
);
432 lpWaveHdr
= &MCIWavDev
[wDevID
].WaveHdr
;
433 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
434 lpWaveHdr
->lpData
= (LPSTR
)GlobalLock16(hData
);
435 lpWaveHdr
->dwBufferLength
= bufsize
;
436 lpWaveHdr
->dwUser
= 0L;
437 lpWaveHdr
->dwFlags
= 0L;
438 lpWaveHdr
->dwLoops
= 0L;
439 dwRet
=widMessage(wDevID
,WIDM_PREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
440 TRACE(mciwave
,"after WIDM_PREPARE \n");
442 lpWaveHdr
->dwBytesRecorded
= 0;
443 dwRet
= widMessage(wDevID
, WIDM_START
, 0, 0L, 0L);
444 TRACE(mciwave
, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
445 lpWaveHdr
, lpWaveHdr
->dwBytesRecorded
);
446 if (lpWaveHdr
->dwBytesRecorded
== 0) break;
448 TRACE(mciwave
,"before WIDM_UNPREPARE \n");
449 dwRet
= widMessage(wDevID
,WIDM_UNPREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
450 TRACE(mciwave
,"after WIDM_UNPREPARE \n");
451 if (lpWaveHdr
->lpData
!= NULL
) {
452 GlobalUnlock16(hData
);
454 lpWaveHdr
->lpData
= NULL
;
456 if (dwFlags
& MCI_NOTIFY
) {
457 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
458 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
459 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
465 /**************************************************************************
466 * WAVE_mciStop [internal]
468 static DWORD
WAVE_mciStop(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
472 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
473 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
474 if (MCIWavDev
[wDevID
].fInput
)
475 dwRet
= widMessage(wDevID
, WIDM_STOP
, 0, dwFlags
, (DWORD
)lpParms
);
477 dwRet
= wodMessage(wDevID
, WODM_STOP
, 0, dwFlags
, (DWORD
)lpParms
);
483 /**************************************************************************
484 * WAVE_mciPause [internal]
486 static DWORD
WAVE_mciPause(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
490 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
491 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
492 if (MCIWavDev
[wDevID
].fInput
)
493 dwRet
= widMessage(wDevID
, WIDM_PAUSE
, 0, dwFlags
, (DWORD
)lpParms
);
495 dwRet
= wodMessage(wDevID
, WODM_PAUSE
, 0, dwFlags
, (DWORD
)lpParms
);
501 /**************************************************************************
502 * WAVE_mciResume [internal]
504 static DWORD
WAVE_mciResume(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
506 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
507 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
512 /**************************************************************************
513 * WAVE_mciSet [internal]
515 static DWORD
WAVE_mciSet(UINT16 wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
517 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
518 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
519 TRACE(mciwave
, "dwTimeFormat=%08lX\n", lpParms
->dwTimeFormat
);
520 TRACE(mciwave
, "dwAudio=%08lX\n", lpParms
->dwAudio
);
521 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
522 switch (lpParms
->dwTimeFormat
) {
523 case MCI_FORMAT_MILLISECONDS
:
524 TRACE(mciwave
, "MCI_FORMAT_MILLISECONDS !\n");
526 case MCI_FORMAT_BYTES
:
527 TRACE(mciwave
, "MCI_FORMAT_BYTES !\n");
529 case MCI_FORMAT_SAMPLES
:
530 TRACE(mciwave
, "MCI_FORMAT_SAMPLES !\n");
533 WARN(mciwave
, "bad time format !\n");
534 return MCIERR_BAD_TIME_FORMAT
;
537 if (dwFlags
& MCI_SET_VIDEO
) return MCIERR_UNSUPPORTED_FUNCTION
;
538 if (dwFlags
& MCI_SET_DOOR_OPEN
) return MCIERR_UNSUPPORTED_FUNCTION
;
539 if (dwFlags
& MCI_SET_DOOR_CLOSED
) return MCIERR_UNSUPPORTED_FUNCTION
;
540 if (dwFlags
& MCI_SET_AUDIO
)
541 TRACE(mciwave
,"MCI_SET_AUDIO !\n");
542 if (dwFlags
&& MCI_SET_ON
) {
543 TRACE(mciwave
,"MCI_SET_ON !\n");
544 if (dwFlags
&& MCI_SET_AUDIO_LEFT
)
545 TRACE(mciwave
,"MCI_SET_AUDIO_LEFT !\n");
546 if (dwFlags
&& MCI_SET_AUDIO_RIGHT
)
547 TRACE(mciwave
,"MCI_SET_AUDIO_RIGHT !\n");
549 if (dwFlags
& MCI_SET_OFF
)
550 TRACE(mciwave
,"MCI_SET_OFF !\n");
551 if (dwFlags
& MCI_WAVE_INPUT
)
552 TRACE(mciwave
,"MCI_WAVE_INPUT !\n");
553 if (dwFlags
& MCI_WAVE_OUTPUT
)
554 TRACE(mciwave
,"MCI_WAVE_OUTPUT !\n");
555 if (dwFlags
& MCI_WAVE_SET_ANYINPUT
)
556 TRACE(mciwave
,"MCI_WAVE_SET_ANYINPUT !\n");
557 if (dwFlags
& MCI_WAVE_SET_ANYOUTPUT
)
558 TRACE(mciwave
,"MCI_WAVE_SET_ANYOUTPUT !\n");
559 if (dwFlags
& MCI_WAVE_SET_AVGBYTESPERSEC
)
560 TRACE(mciwave
, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
561 if (dwFlags
& MCI_WAVE_SET_BITSPERSAMPLE
)
562 TRACE(mciwave
, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
563 if (dwFlags
& MCI_WAVE_SET_BLOCKALIGN
)
564 TRACE(mciwave
,"MCI_WAVE_SET_BLOCKALIGN !\n");
565 if (dwFlags
& MCI_WAVE_SET_CHANNELS
)
566 TRACE(mciwave
,"MCI_WAVE_SET_CHANNELS !\n");
567 if (dwFlags
& MCI_WAVE_SET_FORMATTAG
)
568 TRACE(mciwave
,"MCI_WAVE_SET_FORMATTAG !\n");
569 if (dwFlags
& MCI_WAVE_SET_SAMPLESPERSEC
)
570 TRACE(mciwave
, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
575 /**************************************************************************
576 * WAVE_mciStatus [internal]
578 static DWORD
WAVE_mciStatus(UINT16 wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
580 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
581 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
582 if (dwFlags
& MCI_STATUS_ITEM
) {
583 switch(lpParms
->dwItem
) {
584 case MCI_STATUS_CURRENT_TRACK
:
585 lpParms
->dwReturn
= 1;
587 case MCI_STATUS_LENGTH
:
588 lpParms
->dwReturn
= 5555;
589 if (dwFlags
& MCI_TRACK
) {
590 lpParms
->dwTrack
= 1;
591 lpParms
->dwReturn
= 2222;
594 case MCI_STATUS_MODE
:
595 lpParms
->dwReturn
= MCI_MODE_STOP
;
597 case MCI_STATUS_MEDIA_PRESENT
:
598 TRACE(mciwave
,"MCI_STATUS_MEDIA_PRESENT !\n");
599 lpParms
->dwReturn
= TRUE
;
601 case MCI_STATUS_NUMBER_OF_TRACKS
:
602 lpParms
->dwReturn
= 1;
604 case MCI_STATUS_POSITION
:
605 lpParms
->dwReturn
= 3333;
606 if (dwFlags
& MCI_STATUS_START
)
608 if (dwFlags
& MCI_TRACK
) {
609 lpParms
->dwTrack
= 1;
610 lpParms
->dwReturn
= 777;
613 case MCI_STATUS_READY
:
614 TRACE(mciwave
,"MCI_STATUS_READY !\n");
615 lpParms
->dwReturn
= TRUE
;
617 case MCI_STATUS_TIME_FORMAT
:
618 TRACE(mciwave
,"MCI_STATUS_TIME_FORMAT !\n");
619 lpParms
->dwReturn
= MCI_FORMAT_MILLISECONDS
;
622 TRACE(mciwave
,"MCI_WAVE_INPUT !\n");
623 lpParms
->dwReturn
= 0;
625 case MCI_WAVE_OUTPUT
:
626 TRACE(mciwave
,"MCI_WAVE_OUTPUT !\n");
627 lpParms
->dwReturn
= 0;
629 case MCI_WAVE_STATUS_AVGBYTESPERSEC
:
630 TRACE(mciwave
,"MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
631 lpParms
->dwReturn
= 22050;
633 case MCI_WAVE_STATUS_BITSPERSAMPLE
:
634 TRACE(mciwave
,"MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
635 lpParms
->dwReturn
= 8;
637 case MCI_WAVE_STATUS_BLOCKALIGN
:
638 TRACE(mciwave
,"MCI_WAVE_STATUS_BLOCKALIGN !\n");
639 lpParms
->dwReturn
= 1;
641 case MCI_WAVE_STATUS_CHANNELS
:
642 TRACE(mciwave
,"MCI_WAVE_STATUS_CHANNELS !\n");
643 lpParms
->dwReturn
= 1;
645 case MCI_WAVE_STATUS_FORMATTAG
:
646 TRACE(mciwave
,"MCI_WAVE_FORMATTAG !\n");
647 lpParms
->dwReturn
= WAVE_FORMAT_PCM
;
649 case MCI_WAVE_STATUS_LEVEL
:
650 TRACE(mciwave
,"MCI_WAVE_STATUS_LEVEL !\n");
651 lpParms
->dwReturn
= 0xAAAA5555;
653 case MCI_WAVE_STATUS_SAMPLESPERSEC
:
654 TRACE(mciwave
,"MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
655 lpParms
->dwReturn
= 22050;
658 WARN(mciwave
,"unknown command %08lX !\n", lpParms
->dwItem
);
659 return MCIERR_UNRECOGNIZED_COMMAND
;
662 if (dwFlags
& MCI_NOTIFY
) {
663 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
664 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
665 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
670 /**************************************************************************
671 * WAVE_mciGetDevCaps [internal]
673 static DWORD
WAVE_mciGetDevCaps(UINT16 wDevID
, DWORD dwFlags
,
674 LPMCI_GETDEVCAPS_PARMS lpParms
)
676 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
677 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
678 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
679 switch(lpParms
->dwItem
) {
680 case MCI_GETDEVCAPS_CAN_RECORD
:
681 lpParms
->dwReturn
= TRUE
;
683 case MCI_GETDEVCAPS_HAS_AUDIO
:
684 lpParms
->dwReturn
= TRUE
;
686 case MCI_GETDEVCAPS_HAS_VIDEO
:
687 lpParms
->dwReturn
= FALSE
;
689 case MCI_GETDEVCAPS_DEVICE_TYPE
:
690 lpParms
->dwReturn
= MCI_DEVTYPE_WAVEFORM_AUDIO
;
692 case MCI_GETDEVCAPS_USES_FILES
:
693 lpParms
->dwReturn
= TRUE
;
695 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
696 lpParms
->dwReturn
= TRUE
;
698 case MCI_GETDEVCAPS_CAN_EJECT
:
699 lpParms
->dwReturn
= FALSE
;
701 case MCI_GETDEVCAPS_CAN_PLAY
:
702 lpParms
->dwReturn
= TRUE
;
704 case MCI_GETDEVCAPS_CAN_SAVE
:
705 lpParms
->dwReturn
= TRUE
;
707 case MCI_WAVE_GETDEVCAPS_INPUTS
:
708 lpParms
->dwReturn
= 1;
710 case MCI_WAVE_GETDEVCAPS_OUTPUTS
:
711 lpParms
->dwReturn
= 1;
714 return MCIERR_UNRECOGNIZED_COMMAND
;
720 /**************************************************************************
721 * WAVE_mciInfo [internal]
723 static DWORD
WAVE_mciInfo(UINT16 wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMS16 lpParms
)
725 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
726 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
727 lpParms
->lpstrReturn
= NULL
;
729 case MCI_INFO_PRODUCT
:
730 lpParms
->lpstrReturn
= "Open Sound System 0.5";
733 lpParms
->lpstrReturn
=
734 (LPSTR
)MCIWavDev
[wDevID
].openParms
.lpstrElementName
;
737 lpParms
->lpstrReturn
= "Open Sound System 0.5";
739 case MCI_WAVE_OUTPUT
:
740 lpParms
->lpstrReturn
= "Open Sound System 0.5";
743 return MCIERR_UNRECOGNIZED_COMMAND
;
745 if (lpParms
->lpstrReturn
!= NULL
)
746 lpParms
->dwRetSize
= strlen(lpParms
->lpstrReturn
);
748 lpParms
->dwRetSize
= 0;
753 /*-----------------------------------------------------------------------*/
756 /**************************************************************************
757 * wodGetDevCaps [internal]
759 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPS16 lpCaps
, DWORD dwSize
)
767 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
768 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
769 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
770 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
771 if (audio
== -1) return MMSYSERR_ALLOCATED
;
773 lpCaps
->wMid
= 0x0002;
774 lpCaps
->wPid
= 0x0104;
775 strcpy(lpCaps
->szPname
, "SB16 Wave Out");
777 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
778 lpCaps
->wPid
= 0x0001; /* Product ID */
779 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVOUT Driver");
781 lpCaps
->vDriverVersion
= 0x0100;
782 lpCaps
->dwFormats
= 0x00000000;
783 lpCaps
->dwSupport
= WAVECAPS_VOLUME
;
785 /* First bytespersampl, then stereo */
786 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
788 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
789 if (lpCaps
->wChannels
> 1) lpCaps
->dwSupport
|= WAVECAPS_LRVOLUME
;
792 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
793 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
794 if (lpCaps
->wChannels
> 1)
795 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
796 if (bytespersmpl
> 1) {
797 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
798 if (lpCaps
->wChannels
> 1)
799 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
803 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
804 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
805 if (lpCaps
->wChannels
> 1)
806 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
807 if (bytespersmpl
> 1) {
808 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
809 if (lpCaps
->wChannels
> 1)
810 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
814 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
815 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
816 if (lpCaps
->wChannels
> 1)
817 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
818 if (bytespersmpl
> 1) {
819 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
820 if (lpCaps
->wChannels
> 1)
821 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
825 TRACE(mciwave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
826 return MMSYSERR_NOERROR
;
830 /**************************************************************************
833 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
835 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
836 LPWAVEFORMAT lpFormat
;
838 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
839 if (lpDesc
== NULL
) {
840 WARN(mciwave
, "Invalid Parameter !\n");
841 return MMSYSERR_INVALPARAM
;
843 if (wDevID
>= MAX_WAVOUTDRV
) {
844 TRACE(mciwave
,"MAX_WAVOUTDRV reached !\n");
845 return MMSYSERR_ALLOCATED
;
847 WOutDev
[wDevID
].unixdev
= 0;
848 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
849 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
851 WARN(mciwave
, "can't open !\n");
852 return MMSYSERR_ALLOCATED
;
854 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
855 if (abuf_size
< 1024 || abuf_size
> 65536) {
857 WARN(mciwave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
859 WARN(mciwave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
860 return MMSYSERR_NOTENABLED
;
862 WOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
863 switch(WOutDev
[wDevID
].wFlags
) {
865 TRACE(mciwave
, "CALLBACK_NULL !\n");
868 TRACE(mciwave
, "CALLBACK_WINDOW !\n");
871 TRACE(mciwave
, "CALLBACK_TASK !\n");
874 TRACE(mciwave
, "CALLBACK_FUNCTION !\n");
877 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
878 WOutDev
[wDevID
].unixdev
= audio
;
879 WOutDev
[wDevID
].dwTotalPlayed
= 0;
880 WOutDev
[wDevID
].bufsize
= abuf_size
;
881 /* FIXME: copy lpFormat too? */
882 memcpy(&WOutDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
883 TRACE(mciwave
,"lpDesc->lpFormat = %p\n",lpDesc
->lpFormat
);
884 lpFormat
= lpDesc
->lpFormat
;
885 TRACE(mciwave
,"lpFormat = %p\n",lpFormat
);
886 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
887 WARN(mciwave
,"Bad format %04X !\n",
888 lpFormat
->wFormatTag
);
889 WARN(mciwave
,"Bad nChannels %d !\n",
890 lpFormat
->nChannels
);
891 WARN(mciwave
,"Bad nSamplesPerSec %ld !\n",
892 lpFormat
->nSamplesPerSec
);
893 return WAVERR_BADFORMAT
;
895 memcpy(&WOutDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
896 if (WOutDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
897 if (WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
898 TRACE(mciwave
,"wBitsPerSample=%u !\n",
899 WOutDev
[wDevID
].Format
.wBitsPerSample
);
900 if (WOutDev
[wDevID
].Format
.wBitsPerSample
== 0) {
901 WOutDev
[wDevID
].Format
.wBitsPerSample
= 8 *
902 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
903 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
904 WOutDev
[wDevID
].Format
.wf
.nChannels
;
906 samplesize
= WOutDev
[wDevID
].Format
.wBitsPerSample
;
907 smplrate
= WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
908 dsp_stereo
= (WOutDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
910 /* First size and stereo then samplerate */
911 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
912 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
913 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
915 TRACE(mciwave
,"wBitsPerSample=%u !\n",
916 WOutDev
[wDevID
].Format
.wBitsPerSample
);
917 TRACE(mciwave
,"nAvgBytesPerSec=%lu !\n",
918 WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
919 TRACE(mciwave
,"nSamplesPerSec=%lu !\n",
920 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
921 TRACE(mciwave
,"nChannels=%u !\n",
922 WOutDev
[wDevID
].Format
.wf
.nChannels
);
923 if (WAVE_NotifyClient(wDevID
, WOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
924 WARN(mciwave
, "can't notify client !\n");
925 return MMSYSERR_INVALPARAM
;
927 return MMSYSERR_NOERROR
;
930 /**************************************************************************
931 * wodClose [internal]
933 static DWORD
wodClose(WORD wDevID
)
935 TRACE(mciwave
,"(%u);\n", wDevID
);
936 if (wDevID
> MAX_WAVOUTDRV
) return MMSYSERR_INVALPARAM
;
937 if (WOutDev
[wDevID
].unixdev
== 0) {
938 WARN(mciwave
, "can't close !\n");
939 return MMSYSERR_NOTENABLED
;
941 if (WOutDev
[wDevID
].lpQueueHdr
!= NULL
) {
942 WARN(mciwave
, "still buffers open !\n");
943 /* Don't care. Who needs those buffers anyway */
944 /*return WAVERR_STILLPLAYING; */
946 close(WOutDev
[wDevID
].unixdev
);
947 WOutDev
[wDevID
].unixdev
= 0;
948 WOutDev
[wDevID
].bufsize
= 0;
949 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
950 if (WAVE_NotifyClient(wDevID
, WOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
951 WARN(mciwave
, "can't notify client !\n");
952 return MMSYSERR_INVALPARAM
;
954 return MMSYSERR_NOERROR
;
957 /**************************************************************************
958 * wodWrite [internal]
959 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
960 * device, and initiate async playing.
962 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
968 TRACE(mciwave
,"(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
969 if (WOutDev
[wDevID
].unixdev
== 0) {
970 WARN(mciwave
, "can't play !\n");
971 return MMSYSERR_NOTENABLED
;
973 if (lpWaveHdr
->lpData
== NULL
) return WAVERR_UNPREPARED
;
974 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) return WAVERR_UNPREPARED
;
975 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) return WAVERR_STILLPLAYING
;
976 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
977 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
978 TRACE(mciwave
, "dwBufferLength %lu !\n",
979 lpWaveHdr
->dwBufferLength
);
980 TRACE(mciwave
, "WOutDev[%u].unixdev %u !\n",
981 wDevID
, WOutDev
[wDevID
].unixdev
);
982 lpData
= lpWaveHdr
->lpData
;
983 count
= write (WOutDev
[wDevID
].unixdev
, lpData
, lpWaveHdr
->dwBufferLength
);
984 TRACE(mciwave
,"write returned count %u !\n",count
);
985 if (count
!= lpWaveHdr
->dwBufferLength
) {
986 WARN(mciwave
, " error writting !\n");
987 return MMSYSERR_NOTENABLED
;
989 WOutDev
[wDevID
].dwTotalPlayed
+= count
;
990 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
991 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
992 if ((DWORD
)lpWaveHdr
->lpData
!=lpWaveHdr
->reserved
) {
993 /* FIXME: what if it expects it's OWN lpwavehdr back? */
994 xwavehdr
= SEGPTR_NEW(WAVEHDR
);
995 memcpy(xwavehdr
,lpWaveHdr
,sizeof(WAVEHDR
));
996 xwavehdr
->lpData
= (LPBYTE
)xwavehdr
->reserved
;
997 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)SEGPTR_GET(xwavehdr
), count
) != MMSYSERR_NOERROR
) {
998 WARN(mciwave
, "can't notify client !\n");
999 SEGPTR_FREE(xwavehdr
);
1000 return MMSYSERR_INVALPARAM
;
1002 SEGPTR_FREE(xwavehdr
);
1004 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)lpWaveHdr
, count
) != MMSYSERR_NOERROR
) {
1005 WARN(mciwave
, "can't notify client !\n");
1006 return MMSYSERR_INVALPARAM
;
1009 return MMSYSERR_NOERROR
;
1012 /**************************************************************************
1013 * wodPrepare [internal]
1015 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1017 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1018 if (WOutDev
[wDevID
].unixdev
== 0) {
1019 WARN(mciwave
, "can't prepare !\n");
1020 return MMSYSERR_NOTENABLED
;
1022 /* don't append to queue, wodWrite does that */
1023 WOutDev
[wDevID
].dwTotalPlayed
= 0;
1024 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1025 return WAVERR_STILLPLAYING
;
1026 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1027 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1028 return MMSYSERR_NOERROR
;
1031 /**************************************************************************
1032 * wodUnprepare [internal]
1034 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1036 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1037 if (WOutDev
[wDevID
].unixdev
== 0) {
1038 WARN(mciwave
, "can't unprepare !\n");
1039 return MMSYSERR_NOTENABLED
;
1041 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1042 return WAVERR_STILLPLAYING
;
1044 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
1045 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1046 TRACE(mciwave
, "all headers unprepared !\n");
1047 return MMSYSERR_NOERROR
;
1050 /**************************************************************************
1051 * wodRestart [internal]
1053 static DWORD
wodRestart(WORD wDevID
)
1055 TRACE(mciwave
,"(%u);\n", wDevID
);
1056 if (WOutDev
[wDevID
].unixdev
== 0) {
1057 WARN(mciwave
, "can't restart !\n");
1058 return MMSYSERR_NOTENABLED
;
1060 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1061 /* FIXME: Myst crashes with this ... hmm -MM
1062 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1063 WARN(mciwave, "can't notify client !\n");
1064 return MMSYSERR_INVALPARAM;
1068 return MMSYSERR_NOERROR
;
1071 /**************************************************************************
1072 * wodReset [internal]
1074 static DWORD
wodReset(WORD wDevID
)
1076 TRACE(mciwave
,"(%u);\n", wDevID
);
1077 if (WOutDev
[wDevID
].unixdev
== 0) {
1078 WARN(mciwave
, "can't reset !\n");
1079 return MMSYSERR_NOTENABLED
;
1081 return MMSYSERR_NOERROR
;
1085 /**************************************************************************
1086 * wodGetPosition [internal]
1088 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
1091 TRACE(mciwave
,"(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
1092 if (WOutDev
[wDevID
].unixdev
== 0) {
1093 WARN(mciwave
, "can't get pos !\n");
1094 return MMSYSERR_NOTENABLED
;
1096 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
1097 TRACE(mciwave
,"wType=%04X !\n",
1099 TRACE(mciwave
,"wBitsPerSample=%u\n",
1100 WOutDev
[wDevID
].Format
.wBitsPerSample
);
1101 TRACE(mciwave
,"nSamplesPerSec=%lu\n",
1102 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1103 TRACE(mciwave
,"nChannels=%u\n",
1104 WOutDev
[wDevID
].Format
.wf
.nChannels
);
1105 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1106 WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1107 switch(lpTime
->wType
) {
1109 lpTime
->u
.cb
= WOutDev
[wDevID
].dwTotalPlayed
;
1110 TRACE(mciwave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
1113 TRACE(mciwave
,"dwTotalPlayed=%lu\n",
1114 WOutDev
[wDevID
].dwTotalPlayed
);
1115 TRACE(mciwave
,"wBitsPerSample=%u\n",
1116 WOutDev
[wDevID
].Format
.wBitsPerSample
);
1117 lpTime
->u
.sample
= WOutDev
[wDevID
].dwTotalPlayed
* 8 /
1118 WOutDev
[wDevID
].Format
.wBitsPerSample
;
1119 TRACE(mciwave
,"TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
1122 time
= WOutDev
[wDevID
].dwTotalPlayed
/
1123 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1124 lpTime
->u
.smpte
.hour
= time
/ 108000;
1125 time
-= lpTime
->u
.smpte
.hour
* 108000;
1126 lpTime
->u
.smpte
.min
= time
/ 1800;
1127 time
-= lpTime
->u
.smpte
.min
* 1800;
1128 lpTime
->u
.smpte
.sec
= time
/ 30;
1129 time
-= lpTime
->u
.smpte
.sec
* 30;
1130 lpTime
->u
.smpte
.frame
= time
;
1131 lpTime
->u
.smpte
.fps
= 30;
1133 "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1134 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
1135 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1138 FIXME(mciwave
, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime
->wType
);
1139 lpTime
->wType
= TIME_MS
;
1141 lpTime
->u
.ms
= WOutDev
[wDevID
].dwTotalPlayed
/
1142 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1143 TRACE(mciwave
,"wodGetPosition // TIME_MS=%lu\n", lpTime
->u
.ms
);
1146 return MMSYSERR_NOERROR
;
1149 /**************************************************************************
1150 * wodGetVolume [internal]
1152 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
1155 int volume
, left
, right
;
1156 TRACE(mciwave
,"(%u, %p);\n", wDevID
, lpdwVol
);
1157 if (lpdwVol
== NULL
) return MMSYSERR_NOTENABLED
;
1158 if ((mixer
= open(MIXER_DEV
, O_RDONLY
)) < 0) {
1159 WARN(mciwave
, "mixer device not available !\n");
1160 return MMSYSERR_NOTENABLED
;
1162 if (ioctl(mixer
, SOUND_MIXER_READ_PCM
, &volume
) == -1) {
1163 WARN(mciwave
, "unable read mixer !\n");
1164 return MMSYSERR_NOTENABLED
;
1167 left
= volume
& 0x7F;
1168 right
= (volume
>> 8) & 0x7F;
1169 TRACE(mciwave
,"left=%d right=%d !\n", left
, right
);
1170 *lpdwVol
= MAKELONG(left
<< 9, right
<< 9);
1171 return MMSYSERR_NOERROR
;
1175 /**************************************************************************
1176 * wodSetVolume [internal]
1178 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
1182 TRACE(mciwave
,"(%u, %08lX);\n", wDevID
, dwParam
);
1183 volume
= (LOWORD(dwParam
) >> 9 & 0x7F) +
1184 ((HIWORD(dwParam
) >> 9 & 0x7F) << 8);
1185 if ((mixer
= open(MIXER_DEV
, O_WRONLY
)) < 0) {
1186 WARN(mciwave
, "mixer device not available !\n");
1187 return MMSYSERR_NOTENABLED
;
1189 if (ioctl(mixer
, SOUND_MIXER_WRITE_PCM
, &volume
) == -1) {
1190 WARN(mciwave
, "unable set mixer !\n");
1191 return MMSYSERR_NOTENABLED
;
1194 return MMSYSERR_NOERROR
;
1197 /**************************************************************************
1198 * wodMessage [sample driver]
1200 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1201 DWORD dwParam1
, DWORD dwParam2
)
1204 TRACE(mciwave
,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1205 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1208 return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1210 return wodClose(wDevID
);
1212 return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1214 return MMSYSERR_NOTSUPPORTED
;
1216 return MMSYSERR_NOTSUPPORTED
;
1218 return wodGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1219 case WODM_BREAKLOOP
:
1220 return MMSYSERR_NOTSUPPORTED
;
1222 return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1223 case WODM_UNPREPARE
:
1224 return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1225 case WODM_GETDEVCAPS
:
1226 return wodGetDevCaps(wDevID
,(LPWAVEOUTCAPS16
)dwParam1
,dwParam2
);
1227 case WODM_GETNUMDEVS
:
1228 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1229 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
1238 return MMSYSERR_NOTSUPPORTED
;
1240 return MMSYSERR_NOTSUPPORTED
;
1241 case WODM_GETPLAYBACKRATE
:
1242 return MMSYSERR_NOTSUPPORTED
;
1243 case WODM_SETPLAYBACKRATE
:
1244 return MMSYSERR_NOTSUPPORTED
;
1245 case WODM_GETVOLUME
:
1246 return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
1247 case WODM_SETVOLUME
:
1248 return wodSetVolume(wDevID
, dwParam1
);
1250 return wodRestart(wDevID
);
1252 return wodReset(wDevID
);
1254 WARN(mciwave
,"unknown message !\n");
1256 return MMSYSERR_NOTSUPPORTED
;
1260 /*-----------------------------------------------------------------------*/
1262 /**************************************************************************
1263 * widGetDevCaps [internal]
1265 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPS16 lpCaps
, DWORD dwSize
)
1267 int audio
,smplrate
,samplesize
=16,dsp_stereo
=1,bytespersmpl
;
1269 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
1270 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
1271 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
1272 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1273 if (audio
== -1) return MMSYSERR_ALLOCATED
;
1275 lpCaps
->wMid
= 0x0002;
1276 lpCaps
->wPid
= 0x0004;
1277 strcpy(lpCaps
->szPname
, "SB16 Wave In");
1279 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
1280 lpCaps
->wPid
= 0x0001; /* Product ID */
1281 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVIN Driver");
1283 lpCaps
->dwFormats
= 0x00000000;
1284 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
1285 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
1287 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1288 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
1289 if (lpCaps
->wChannels
> 1)
1290 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
1291 if (bytespersmpl
> 1) {
1292 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
1293 if (lpCaps
->wChannels
> 1)
1294 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
1298 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1299 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
1300 if (lpCaps
->wChannels
> 1)
1301 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
1302 if (bytespersmpl
> 1) {
1303 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
1304 if (lpCaps
->wChannels
> 1)
1305 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
1309 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1310 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
1311 if (lpCaps
->wChannels
> 1)
1312 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
1313 if (bytespersmpl
> 1) {
1314 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
1315 if (lpCaps
->wChannels
> 1)
1316 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
1320 TRACE(mciwave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
1321 return MMSYSERR_NOERROR
;
1325 /**************************************************************************
1326 * widOpen [internal]
1328 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
1330 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
1331 LPWAVEFORMAT lpFormat
;
1333 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
1334 if (lpDesc
== NULL
) {
1335 WARN(mciwave
, "Invalid Parameter !\n");
1336 return MMSYSERR_INVALPARAM
;
1338 if (wDevID
>= MAX_WAVINDRV
) {
1339 TRACE(mciwave
,"MAX_WAVINDRV reached !\n");
1340 return MMSYSERR_ALLOCATED
;
1342 WInDev
[wDevID
].unixdev
= 0;
1343 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
1344 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1346 WARN(mciwave
,"can't open !\n");
1347 return MMSYSERR_ALLOCATED
;
1349 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
1350 if (abuf_size
< 1024 || abuf_size
> 65536) {
1351 if (abuf_size
== -1)
1352 WARN(mciwave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1354 WARN(mciwave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1355 return MMSYSERR_NOTENABLED
;
1357 WInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
1358 switch(WInDev
[wDevID
].wFlags
) {
1360 TRACE(mciwave
,"CALLBACK_NULL!\n");
1363 TRACE(mciwave
,"CALLBACK_WINDOW!\n");
1366 TRACE(mciwave
,"CALLBACK_TASK!\n");
1369 TRACE(mciwave
,"CALLBACK_FUNCTION!\n");
1372 if (WInDev
[wDevID
].lpQueueHdr
) {
1373 HeapFree(GetProcessHeap(),0,WInDev
[wDevID
].lpQueueHdr
);
1374 WInDev
[wDevID
].lpQueueHdr
= NULL
;
1376 WInDev
[wDevID
].unixdev
= audio
;
1377 WInDev
[wDevID
].bufsize
= abuf_size
;
1378 WInDev
[wDevID
].dwTotalRecorded
= 0;
1379 memcpy(&WInDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
1380 lpFormat
= (LPWAVEFORMAT
) lpDesc
->lpFormat
;
1381 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
1382 WARN(mciwave
, "Bad format %04X !\n",
1383 lpFormat
->wFormatTag
);
1384 return WAVERR_BADFORMAT
;
1386 memcpy(&WInDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
1387 WInDev
[wDevID
].Format
.wBitsPerSample
= 8; /* <-------------- */
1388 if (WInDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
1389 if (WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
1390 if (WInDev
[wDevID
].Format
.wBitsPerSample
== 0) {
1391 WInDev
[wDevID
].Format
.wBitsPerSample
= 8 *
1392 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
1393 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
1394 WInDev
[wDevID
].Format
.wf
.nChannels
;
1396 samplesize
= WInDev
[wDevID
].Format
.wBitsPerSample
;
1397 smplrate
= WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
1398 dsp_stereo
= (WInDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
1399 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
1400 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
1401 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
1402 TRACE(mciwave
,"wBitsPerSample=%u !\n",
1403 WInDev
[wDevID
].Format
.wBitsPerSample
);
1404 TRACE(mciwave
,"nSamplesPerSec=%lu !\n",
1405 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1406 TRACE(mciwave
,"nChannels=%u !\n",
1407 WInDev
[wDevID
].Format
.wf
.nChannels
);
1408 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1409 WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1410 if (WAVE_NotifyClient(wDevID
, WIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
1411 WARN(mciwave
,"can't notify client !\n");
1412 return MMSYSERR_INVALPARAM
;
1414 return MMSYSERR_NOERROR
;
1417 /**************************************************************************
1418 * widClose [internal]
1420 static DWORD
widClose(WORD wDevID
)
1422 TRACE(mciwave
,"(%u);\n", wDevID
);
1423 if (wDevID
> MAX_WAVINDRV
) return MMSYSERR_INVALPARAM
;
1424 if (WInDev
[wDevID
].unixdev
== 0) {
1425 WARN(mciwave
,"can't close !\n");
1426 return MMSYSERR_NOTENABLED
;
1428 if (WInDev
[wDevID
].lpQueueHdr
!= NULL
) {
1429 WARN(mciwave
, "still buffers open !\n");
1430 return WAVERR_STILLPLAYING
;
1432 close(WInDev
[wDevID
].unixdev
);
1433 WInDev
[wDevID
].unixdev
= 0;
1434 WInDev
[wDevID
].bufsize
= 0;
1435 if (WAVE_NotifyClient(wDevID
, WIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
1436 WARN(mciwave
,"can't notify client !\n");
1437 return MMSYSERR_INVALPARAM
;
1439 return MMSYSERR_NOERROR
;
1442 /**************************************************************************
1443 * widAddBuffer [internal]
1445 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1450 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1451 if (WInDev
[wDevID
].unixdev
== 0) {
1452 WARN(mciwave
,"can't do it !\n");
1453 return MMSYSERR_NOTENABLED
;
1455 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
1456 TRACE(mciwave
, "never been prepared !\n");
1457 return WAVERR_UNPREPARED
;
1459 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
1460 TRACE(mciwave
, "header already in use !\n");
1461 return WAVERR_STILLPLAYING
;
1463 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1464 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
1465 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1466 lpWaveHdr
->dwBytesRecorded
= 0;
1467 if (WInDev
[wDevID
].lpQueueHdr
== NULL
) {
1468 WInDev
[wDevID
].lpQueueHdr
= lpWaveHdr
;
1470 lpWIHdr
= WInDev
[wDevID
].lpQueueHdr
;
1471 while (lpWIHdr
->lpNext
!= NULL
) {
1472 lpWIHdr
= lpWIHdr
->lpNext
;
1475 lpWIHdr
->lpNext
= lpWaveHdr
;
1476 lpWaveHdr
->lpNext
= NULL
;
1479 TRACE(mciwave
, "buffer added ! (now %u in queue)\n", count
);
1480 return MMSYSERR_NOERROR
;
1483 /**************************************************************************
1484 * widPrepare [internal]
1486 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1488 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1489 if (WInDev
[wDevID
].unixdev
== 0) {
1490 WARN(mciwave
,"can't prepare !\n");
1491 return MMSYSERR_NOTENABLED
;
1493 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1494 return WAVERR_STILLPLAYING
;
1495 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1496 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1497 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1498 lpWaveHdr
->dwBytesRecorded
= 0;
1499 TRACE(mciwave
,"header prepared !\n");
1500 return MMSYSERR_NOERROR
;
1503 /**************************************************************************
1504 * widUnprepare [internal]
1506 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1508 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1509 if (WInDev
[wDevID
].unixdev
== 0) {
1510 WARN(mciwave
,"can't unprepare !\n");
1511 return MMSYSERR_NOTENABLED
;
1513 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
1514 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1515 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1517 TRACE(mciwave
, "all headers unprepared !\n");
1518 return MMSYSERR_NOERROR
;
1521 /**************************************************************************
1522 * widStart [internal]
1524 static DWORD
widStart(WORD wDevID
)
1529 LPWAVEHDR
*lpWaveHdr
;
1531 TRACE(mciwave
,"(%u);\n", wDevID
);
1532 if (WInDev
[wDevID
].unixdev
== 0) {
1533 WARN(mciwave
, "can't start recording !\n");
1534 return MMSYSERR_NOTENABLED
;
1537 lpWaveHdr
= &(WInDev
[wDevID
].lpQueueHdr
);
1538 TRACE(mciwave
,"lpWaveHdr = %08lx\n",(DWORD
)lpWaveHdr
);
1539 if (!*lpWaveHdr
|| !(*lpWaveHdr
)->lpData
) {
1540 TRACE(mciwave
,"never been prepared !\n");
1541 return WAVERR_UNPREPARED
;
1544 while(*lpWaveHdr
!= NULL
) {
1545 lpWIHdr
= *lpWaveHdr
;
1546 TRACE(mciwave
, "recording buf#%u=%p size=%lu \n",
1547 count
, lpWIHdr
->lpData
, lpWIHdr
->dwBufferLength
);
1549 bytesRead
= read (WInDev
[wDevID
].unixdev
,
1551 lpWIHdr
->dwBufferLength
);
1553 perror("read from audio device");
1554 TRACE(mciwave
,"bytesread=%d (%ld)\n",
1555 bytesRead
,lpWIHdr
->dwBufferLength
);
1556 lpWIHdr
->dwBytesRecorded
= bytesRead
;
1557 WInDev
[wDevID
].dwTotalRecorded
+= lpWIHdr
->dwBytesRecorded
;
1558 lpWIHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1559 lpWIHdr
->dwFlags
|= WHDR_DONE
;
1561 /* FIXME: should pass segmented pointer here, do we need that?*/
1562 if (WAVE_NotifyClient(wDevID
, WIM_DATA
, (DWORD
)lpWaveHdr
, lpWIHdr
->dwBytesRecorded
) != MMSYSERR_NOERROR
) {
1563 WARN(mciwave
, "can't notify client !\n");
1564 return MMSYSERR_INVALPARAM
;
1566 /* removes the current block from the queue */
1567 *lpWaveHdr
= lpWIHdr
->lpNext
;
1570 TRACE(mciwave
,"end of recording !\n");
1572 return MMSYSERR_NOERROR
;
1575 /**************************************************************************
1576 * widStop [internal]
1578 static DWORD
widStop(WORD wDevID
)
1580 TRACE(mciwave
,"(%u);\n", wDevID
);
1581 if (WInDev
[wDevID
].unixdev
== 0) {
1582 WARN(mciwave
,"can't stop !\n");
1583 return MMSYSERR_NOTENABLED
;
1585 return MMSYSERR_NOERROR
;
1588 /**************************************************************************
1589 * widReset [internal]
1591 static DWORD
widReset(WORD wDevID
)
1593 TRACE(mciwave
,"(%u);\n", wDevID
);
1594 if (WInDev
[wDevID
].unixdev
== 0) {
1595 WARN(mciwave
,"can't reset !\n");
1596 return MMSYSERR_NOTENABLED
;
1598 return MMSYSERR_NOERROR
;
1601 /**************************************************************************
1602 * widGetPosition [internal]
1604 static DWORD
widGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
1608 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
1609 if (WInDev
[wDevID
].unixdev
== 0) {
1610 WARN(mciwave
,"can't get pos !\n");
1611 return MMSYSERR_NOTENABLED
;
1613 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
1614 TRACE(mciwave
,"wType=%04X !\n",
1616 TRACE(mciwave
,"wBitsPerSample=%u\n",
1617 WInDev
[wDevID
].Format
.wBitsPerSample
);
1618 TRACE(mciwave
,"nSamplesPerSec=%lu\n",
1619 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1620 TRACE(mciwave
,"nChannels=%u\n",
1621 WInDev
[wDevID
].Format
.wf
.nChannels
);
1622 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1623 WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1625 switch(lpTime
->wType
) {
1627 lpTime
->u
.cb
= WInDev
[wDevID
].dwTotalRecorded
;
1628 TRACE(mciwave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
1631 lpTime
->u
.sample
= WInDev
[wDevID
].dwTotalRecorded
* 8 /
1632 WInDev
[wDevID
].Format
.wBitsPerSample
;
1633 TRACE(mciwave
, "TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
1636 time
= WInDev
[wDevID
].dwTotalRecorded
/
1637 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1638 lpTime
->u
.smpte
.hour
= time
/ 108000;
1639 time
-= lpTime
->u
.smpte
.hour
* 108000;
1640 lpTime
->u
.smpte
.min
= time
/ 1800;
1641 time
-= lpTime
->u
.smpte
.min
* 1800;
1642 lpTime
->u
.smpte
.sec
= time
/ 30;
1643 time
-= lpTime
->u
.smpte
.sec
* 30;
1644 lpTime
->u
.smpte
.frame
= time
;
1645 lpTime
->u
.smpte
.fps
= 30;
1646 TRACE(mciwave
,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1647 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
1648 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1651 FIXME(mciwave
, "format not supported ! use TIME_MS !\n");
1652 lpTime
->wType
= TIME_MS
;
1654 lpTime
->u
.ms
= WInDev
[wDevID
].dwTotalRecorded
/
1655 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1656 TRACE(mciwave
, "TIME_MS=%lu\n", lpTime
->u
.ms
);
1659 return MMSYSERR_NOERROR
;
1662 /**************************************************************************
1663 * widMessage [sample driver]
1665 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1666 DWORD dwParam1
, DWORD dwParam2
)
1669 TRACE(mciwave
,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1670 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1673 return widOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1675 return widClose(wDevID
);
1676 case WIDM_ADDBUFFER
:
1677 return widAddBuffer(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1679 return widPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1680 case WIDM_UNPREPARE
:
1681 return widUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1682 case WIDM_GETDEVCAPS
:
1683 return widGetDevCaps(wDevID
, (LPWAVEINCAPS16
)dwParam1
,dwParam2
);
1684 case WIDM_GETNUMDEVS
:
1685 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1686 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1695 return widGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1697 return widReset(wDevID
);
1699 return widStart(wDevID
);
1701 return widStop(wDevID
);
1703 return widStop(wDevID
);
1705 WARN(mciwave
,"unknown message !\n");
1707 return MMSYSERR_NOTSUPPORTED
;
1711 /**************************************************************************
1712 * WAVE_DriverProc16 [sample driver]
1714 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1715 DWORD dwParam1
, DWORD dwParam2
)
1717 TRACE(mciwave
,"(%08lX, %04X, %04X, %08lX, %08lX)\n",
1718 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1720 case DRV_LOAD
: return 1;
1721 case DRV_FREE
: return 1;
1722 case DRV_OPEN
: return 1;
1723 case DRV_CLOSE
: return 1;
1724 case DRV_ENABLE
: return 1;
1725 case DRV_DISABLE
: return 1;
1726 case DRV_QUERYCONFIGURE
: return 1;
1727 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1728 case DRV_INSTALL
: return DRVCNF_RESTART
;
1729 case DRV_REMOVE
: return DRVCNF_RESTART
;
1730 case MCI_OPEN_DRIVER
:
1731 case MCI_OPEN
: return WAVE_mciOpen(dwDevID
, dwParam1
, PTR_SEG_TO_LIN(dwParam2
), FALSE
);
1732 case MCI_CUE
: return WAVE_mciCue(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1733 case MCI_CLOSE_DRIVER
:
1734 case MCI_CLOSE
: return WAVE_mciClose(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1735 case MCI_PLAY
: return WAVE_mciPlay(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1736 case MCI_RECORD
: return WAVE_mciRecord(dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1737 case MCI_STOP
: return WAVE_mciStop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1738 case MCI_SET
: return WAVE_mciSet(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1739 case MCI_PAUSE
: return WAVE_mciPause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1740 case MCI_RESUME
: return WAVE_mciResume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1741 case MCI_STATUS
: return WAVE_mciStatus(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1742 case MCI_GETDEVCAPS
: return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1743 case MCI_INFO
: return WAVE_mciInfo(dwDevID
, dwParam1
, (LPMCI_INFO_PARMS16
)PTR_SEG_TO_LIN(dwParam2
));
1744 case MCI_LOAD
: return MMSYSERR_NOTSUPPORTED
;
1745 case MCI_SAVE
: return MMSYSERR_NOTSUPPORTED
;
1746 case MCI_SEEK
: return MMSYSERR_NOTSUPPORTED
;
1747 case MCI_FREEZE
: return MMSYSERR_NOTSUPPORTED
;
1748 case MCI_PUT
: return MMSYSERR_NOTSUPPORTED
;
1749 case MCI_REALIZE
: return MMSYSERR_NOTSUPPORTED
;
1750 case MCI_UNFREEZE
: return MMSYSERR_NOTSUPPORTED
;
1751 case MCI_UPDATE
: return MMSYSERR_NOTSUPPORTED
;
1752 case MCI_WHERE
: return MMSYSERR_NOTSUPPORTED
;
1753 case MCI_WINDOW
: return MMSYSERR_NOTSUPPORTED
;
1754 case MCI_STEP
: return MMSYSERR_NOTSUPPORTED
;
1755 case MCI_SPIN
: return MMSYSERR_NOTSUPPORTED
;
1756 case MCI_ESCAPE
: return MMSYSERR_NOTSUPPORTED
;
1757 case MCI_COPY
: return MMSYSERR_NOTSUPPORTED
;
1758 case MCI_CUT
: return MMSYSERR_NOTSUPPORTED
;
1759 case MCI_DELETE
: return MMSYSERR_NOTSUPPORTED
;
1760 case MCI_PASTE
: return MMSYSERR_NOTSUPPORTED
;
1763 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1765 return MMSYSERR_NOTENABLED
;
1767 /**************************************************************************
1768 * WAVE_DriverProc32 [sample driver]
1770 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1771 DWORD dwParam1
, DWORD dwParam2
)
1773 TRACE(mciwave
,"(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1774 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1776 case DRV_LOAD
: return 1;
1777 case DRV_FREE
: return 1;
1778 case DRV_OPEN
: return 1;
1779 case DRV_CLOSE
: return 1;
1780 case DRV_ENABLE
: return 1;
1781 case DRV_DISABLE
: return 1;
1782 case DRV_QUERYCONFIGURE
: return 1;
1783 case DRV_CONFIGURE
: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
1784 case DRV_INSTALL
: return DRVCNF_RESTART
;
1785 case DRV_REMOVE
: return DRVCNF_RESTART
;
1786 case MCI_OPEN_DRIVER
:
1787 case MCI_OPEN
: return WAVE_mciOpen(dwDevID
, dwParam1
, (LPMCI_WAVE_OPEN_PARMS32A
)dwParam2
, TRUE
);
1788 case MCI_CUE
: return WAVE_mciCue(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1789 case MCI_CLOSE_DRIVER
:
1790 case MCI_CLOSE
: return WAVE_mciClose(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1791 case MCI_PLAY
: return WAVE_mciPlay(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)dwParam2
);
1792 case MCI_RECORD
: return WAVE_mciRecord(dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
)dwParam2
);
1793 case MCI_STOP
: return WAVE_mciStop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1794 case MCI_SET
: return WAVE_mciSet(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)dwParam2
);
1795 case MCI_PAUSE
: return WAVE_mciPause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1796 case MCI_RESUME
: return WAVE_mciResume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
1797 case MCI_STATUS
: return WAVE_mciStatus(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)dwParam2
);
1798 case MCI_GETDEVCAPS
: return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)dwParam2
);
1799 case MCI_INFO
: return WAVE_mciInfo(dwDevID
, dwParam1
, (LPMCI_INFO_PARMS16
)dwParam2
);
1800 case MCI_LOAD
: return MMSYSERR_NOTSUPPORTED
;
1801 case MCI_SAVE
: return MMSYSERR_NOTSUPPORTED
;
1802 case MCI_SEEK
: return MMSYSERR_NOTSUPPORTED
;
1803 case MCI_FREEZE
: return MMSYSERR_NOTSUPPORTED
;
1804 case MCI_PUT
: return MMSYSERR_NOTSUPPORTED
;
1805 case MCI_REALIZE
: return MMSYSERR_NOTSUPPORTED
;
1806 case MCI_UNFREEZE
: return MMSYSERR_NOTSUPPORTED
;
1807 case MCI_UPDATE
: return MMSYSERR_NOTSUPPORTED
;
1808 case MCI_WHERE
: return MMSYSERR_NOTSUPPORTED
;
1809 case MCI_WINDOW
: return MMSYSERR_NOTSUPPORTED
;
1810 case MCI_STEP
: return MMSYSERR_NOTSUPPORTED
;
1811 case MCI_SPIN
: return MMSYSERR_NOTSUPPORTED
;
1812 case MCI_ESCAPE
: return MMSYSERR_NOTSUPPORTED
;
1813 case MCI_COPY
: return MMSYSERR_NOTSUPPORTED
;
1814 case MCI_CUT
: return MMSYSERR_NOTSUPPORTED
;
1815 case MCI_DELETE
: return MMSYSERR_NOTSUPPORTED
;
1816 case MCI_PASTE
: return MMSYSERR_NOTSUPPORTED
;
1819 FIXME(mciwave
, "is probably wrong\n");
1820 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1822 return MMSYSERR_NOTENABLED
;
1825 #else /* !HAVE_OSS */
1827 /**************************************************************************
1828 * wodMessage [sample driver]
1830 DWORD WINAPI
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1831 DWORD dwParam1
, DWORD dwParam2
)
1833 FIXME(mciwave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1834 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1835 return MMSYSERR_NOTENABLED
;
1838 /**************************************************************************
1839 * widMessage [sample driver]
1841 DWORD WINAPI
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1842 DWORD dwParam1
, DWORD dwParam2
)
1844 FIXME(mciwave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1845 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1846 return MMSYSERR_NOTENABLED
;
1849 /**************************************************************************
1850 * WAVE_DriverProc16 [sample driver]
1852 LONG
WAVE_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1853 DWORD dwParam1
, DWORD dwParam2
)
1855 return MMSYSERR_NOTENABLED
;
1858 /**************************************************************************
1859 * WAVE_DriverProc32 [sample driver]
1861 LONG
WAVE_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
1862 DWORD dwParam1
, DWORD dwParam2
)
1864 return MMSYSERR_NOTENABLED
;
1866 #endif /* HAVE_OSS */