2 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
4 * Copyright 1994 Martin Ayotte
8 * - record/play should and must be done asynchronous
9 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
20 #include <sys/ioctl.h>
31 #ifdef HAVE_MACHINE_SOUNDCARD_H
32 # include <machine/soundcard.h>
34 #ifdef HAVE_SYS_SOUNDCARD_H
35 # include <sys/soundcard.h>
38 #define SOUND_DEV "/dev/dsp"
39 #define MIXER_DEV "/dev/mixer"
42 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
44 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
47 #define MAX_WAVOUTDRV (1)
48 #define MAX_WAVINDRV (1)
49 #define MAX_MCIWAVDRV (1)
55 WAVEOPENDESC waveDesc
;
65 DWORD bufsize
; /* OpenSound '/dev/dsp' give us that size */
66 WAVEOPENDESC waveDesc
;
70 DWORD dwTotalRecorded
;
74 int nUseCount
; /* Incremented for each shared open */
75 BOOL16 fShareable
; /* TRUE if first open was shareable */
76 WORD wNotifyDeviceID
;/* MCI device ID with a pending notification */
77 HANDLE16 hCallback
; /* Callback handle for pending notification */
78 HMMIO16 hFile
; /* mmio file handle open as Element */
79 MCI_WAVE_OPEN_PARMS16 openParms
;
80 PCMWAVEFORMAT WaveFormat
;
82 BOOL16 fInput
; /* FALSE = Output, TRUE = Input */
85 static LINUX_WAVEOUT WOutDev
[MAX_WAVOUTDRV
];
86 static LINUX_WAVEIN WInDev
[MAX_WAVOUTDRV
];
87 static LINUX_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
, LPMCI_WAVE_OPEN_PARMS16 lpParms
)
140 LPPCMWAVEFORMAT lpWaveFormat
;
141 WAVEOPENDESC waveDesc
;
142 LPSTR lpstrElementName
;
146 TRACE(mciwave
,"(%04X, %08lX, %p)\n",
147 wDevID
, dwFlags
, lpParms
);
148 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
150 if (MCIWavDev
[wDevID
].nUseCount
> 0) {
151 /* The driver already open on this channel */
152 /* If the driver was opened shareable before and this open specifies */
153 /* shareable then increment the use count */
154 if (MCIWavDev
[wDevID
].fShareable
&& (dwFlags
& MCI_OPEN_SHAREABLE
))
155 ++MCIWavDev
[wDevID
].nUseCount
;
157 return MCIERR_MUST_USE_SHAREABLE
;
159 MCIWavDev
[wDevID
].nUseCount
= 1;
160 MCIWavDev
[wDevID
].fShareable
= dwFlags
& MCI_OPEN_SHAREABLE
;
163 MCIWavDev
[wDevID
].fInput
= FALSE
;
165 TRACE(mciwave
,"wDevID=%04X\n", wDevID
);
166 TRACE(mciwave
,"before OPEN_ELEMENT\n");
167 if (dwFlags
& MCI_OPEN_ELEMENT
) {
168 lpstrElementName
= (LPSTR
)PTR_SEG_TO_LIN(lpParms
->lpstrElementName
);
169 TRACE(mciwave
,"MCI_OPEN_ELEMENT '%s' !\n",
171 if ( lpstrElementName
&& (strlen(lpstrElementName
) > 0)) {
172 strcpy(str
, lpstrElementName
);
174 MCIWavDev
[wDevID
].hFile
= mmioOpen16(str
, NULL
,
175 MMIO_ALLOCBUF
| MMIO_READWRITE
| MMIO_EXCLUSIVE
);
176 if (MCIWavDev
[wDevID
].hFile
== 0) {
177 WARN(mciwave
, "can't find file='%s' !\n", str
);
178 return MCIERR_FILE_NOT_FOUND
;
182 MCIWavDev
[wDevID
].hFile
= 0;
184 TRACE(mciwave
,"hFile=%u\n", MCIWavDev
[wDevID
].hFile
);
185 memcpy(&MCIWavDev
[wDevID
].openParms
, lpParms
, sizeof(MCI_WAVE_OPEN_PARMS16
));
186 MCIWavDev
[wDevID
].wNotifyDeviceID
= lpParms
->wDeviceID
;
187 lpWaveFormat
= &MCIWavDev
[wDevID
].WaveFormat
;
191 lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
192 lpWaveFormat->wBitsPerSample = 8;
193 lpWaveFormat->wf.nChannels = 1;
194 lpWaveFormat->wf.nSamplesPerSec = 11025;
195 lpWaveFormat->wf.nAvgBytesPerSec = 11025;
196 lpWaveFormat->wf.nBlockAlign = 1;
198 if (MCIWavDev
[wDevID
].hFile
!= 0) {
201 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &ckMainRIFF
, NULL
, 0) != 0)
202 return MCIERR_INTERNAL
;
203 TRACE(mciwave
, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
204 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
,
206 if ((ckMainRIFF
.ckid
!= FOURCC_RIFF
) ||
207 (ckMainRIFF
.fccType
!= mmioFOURCC('W', 'A', 'V', 'E')))
208 return MCIERR_INTERNAL
;
209 mmckInfo
.ckid
= mmioFOURCC('f', 'm', 't', ' ');
210 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &mmckInfo
, &ckMainRIFF
, MMIO_FINDCHUNK
) != 0)
211 return MCIERR_INTERNAL
;
212 TRACE(mciwave
, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
213 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
,
215 if (mmioRead32(MCIWavDev
[wDevID
].hFile
, (HPSTR
) lpWaveFormat
,
216 (long) sizeof(PCMWAVEFORMAT
)) != (long) sizeof(PCMWAVEFORMAT
))
217 return MCIERR_INTERNAL
;
218 mmckInfo
.ckid
= mmioFOURCC('d', 'a', 't', 'a');
219 if (mmioDescend(MCIWavDev
[wDevID
].hFile
, &mmckInfo
, &ckMainRIFF
, MMIO_FINDCHUNK
) != 0)
220 return MCIERR_INTERNAL
;
221 TRACE(mciwave
,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
222 (LPSTR
)&mmckInfo
.ckid
, (LPSTR
)&mmckInfo
.fccType
,
224 TRACE(mciwave
, "nChannels=%d nSamplesPerSec=%ld\n",
225 lpWaveFormat
->wf
.nChannels
, lpWaveFormat
->wf
.nSamplesPerSec
);
226 lpWaveFormat
->wBitsPerSample
= 0;
228 lpWaveFormat
->wf
.nAvgBytesPerSec
=
229 lpWaveFormat
->wf
.nSamplesPerSec
* lpWaveFormat
->wf
.nBlockAlign
;
230 waveDesc
.lpFormat
= (LPWAVEFORMAT
)lpWaveFormat
;
233 By default the device will be opened for output, the MCI_CUE function is there to
234 change from output to input and back
237 dwRet
=wodMessage(wDevID
,WODM_OPEN
,0,(DWORD
)&waveDesc
,CALLBACK_NULL
);
241 /**************************************************************************
242 * WAVE_mciCue [internal]
245 static DWORD
WAVE_mciCue(UINT16 wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
250 This routine is far from complete. At the moment only a check is done on the
251 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
254 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
259 WAVEOPENDESC waveDesc
;
261 TRACE(mciwave
,"(%u, %08lX, %p);\n", wDevID
, dwParam
, lpParms
);
263 /* always close elements ? */
265 if (MCIWavDev
[wDevID
].hFile
!= 0) {
266 mmioClose32(MCIWavDev
[wDevID
].hFile
, 0);
267 MCIWavDev
[wDevID
].hFile
= 0;
270 dwRet
= MMSYSERR_NOERROR
; /* assume success */
271 if ((dwParam
& MCI_WAVE_INPUT
) && !MCIWavDev
[wDevID
].fInput
) {
272 /* FIXME this is just a hack WOutDev should be hidden here */
273 memcpy(&waveDesc
,&WOutDev
[wDevID
].waveDesc
,sizeof(WAVEOPENDESC
));
275 dwRet
= wodMessage(wDevID
, WODM_CLOSE
, 0, 0L, 0L);
276 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
277 dwRet
= widMessage(wDevID
, WIDM_OPEN
, 0, (DWORD
)&waveDesc
, CALLBACK_NULL
);
278 MCIWavDev
[wDevID
].fInput
= TRUE
;
280 else if (MCIWavDev
[wDevID
].fInput
) {
281 /* FIXME this is just a hack WInDev should be hidden here */
282 memcpy(&waveDesc
,&WInDev
[wDevID
].waveDesc
,sizeof(WAVEOPENDESC
));
284 dwRet
= widMessage(wDevID
, WIDM_CLOSE
, 0, 0L, 0L);
285 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
286 dwRet
= wodMessage(wDevID
, WODM_OPEN
, 0, (DWORD
)&waveDesc
, CALLBACK_NULL
);
287 MCIWavDev
[wDevID
].fInput
= FALSE
;
292 /**************************************************************************
293 * WAVE_mciClose [internal]
295 static DWORD
WAVE_mciClose(UINT16 wDevID
, DWORD dwParam
, LPMCI_GENERIC_PARMS lpParms
)
299 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwParam
, lpParms
);
300 MCIWavDev
[wDevID
].nUseCount
--;
301 if (MCIWavDev
[wDevID
].nUseCount
== 0) {
302 if (MCIWavDev
[wDevID
].hFile
!= 0) {
303 mmioClose32(MCIWavDev
[wDevID
].hFile
, 0);
304 MCIWavDev
[wDevID
].hFile
= 0;
306 if (MCIWavDev
[wDevID
].fInput
)
307 dwRet
= widMessage(wDevID
, WIDM_CLOSE
, 0, 0L, 0L);
309 dwRet
= wodMessage(wDevID
, WODM_CLOSE
, 0, 0L, 0L);
311 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
317 /**************************************************************************
318 * WAVE_mciPlay [internal]
320 static DWORD
WAVE_mciPlay(UINT16 wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
328 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
330 if (MCIWavDev
[wDevID
].fInput
) {
331 WARN(mciwave
, "cannot play on input device\n");
332 return MCIERR_NONAPPLICABLE_FUNCTION
;
335 if (MCIWavDev
[wDevID
].hFile
== 0) {
336 WARN(mciwave
, "can't find file='%08lx' !\n",
337 MCIWavDev
[wDevID
].openParms
.lpstrElementName
);
338 return MCIERR_FILE_NOT_FOUND
;
340 start
= 1; end
= 99999;
341 if (dwFlags
& MCI_FROM
) {
342 start
= lpParms
->dwFrom
;
343 TRACE(mciwave
, "MCI_FROM=%d \n", start
);
345 if (dwFlags
& MCI_TO
) {
347 TRACE(mciwave
,"MCI_TO=%d \n", end
);
350 if (dwFlags
& MCI_NOTIFY
) {
351 TRACE(mciwave
, "MCI_NOTIFY %08lX !\n", lpParms
->dwCallback
);
354 WARN(mciwave
, "Can't 'fork' process !\n");
359 TRACE(mciwave
,"process started ! return to caller...\n");
365 lpWaveHdr
= &MCIWavDev
[wDevID
].WaveHdr
;
366 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
367 lpWaveHdr
->lpData
= (LPSTR
) GlobalLock16(hData
);
368 lpWaveHdr
->dwUser
= 0L;
369 lpWaveHdr
->dwFlags
= 0L;
370 lpWaveHdr
->dwLoops
= 0L;
371 dwRet
=wodMessage(wDevID
,WODM_PREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
373 count
= mmioRead32(MCIWavDev
[wDevID
].hFile
, lpWaveHdr
->lpData
, bufsize
);
374 TRACE(mciwave
,"mmioRead bufsize=%ld count=%ld\n", bufsize
, count
);
375 if (count
< 1) break;
376 lpWaveHdr
->dwBufferLength
= count
;
377 /* lpWaveHdr->dwBytesRecorded = count; */
378 TRACE(mciwave
,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
379 lpWaveHdr
, lpWaveHdr
->dwBufferLength
, lpWaveHdr
->dwBytesRecorded
);
380 dwRet
=wodMessage(wDevID
,WODM_WRITE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
382 dwRet
= wodMessage(wDevID
,WODM_UNPREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
383 if (lpWaveHdr
->lpData
!= NULL
) {
384 GlobalUnlock16(hData
);
386 lpWaveHdr
->lpData
= NULL
;
388 if (dwFlags
& MCI_NOTIFY
) {
389 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
390 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
391 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
397 /**************************************************************************
398 * WAVE_mciRecord [internal]
400 static DWORD
WAVE_mciRecord(UINT16 wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
408 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
410 if (!MCIWavDev
[wDevID
].fInput
) {
411 WARN(mciwave
, "cannot record on output device\n");
412 return MCIERR_NONAPPLICABLE_FUNCTION
;
415 if (MCIWavDev
[wDevID
].hFile
== 0) {
416 WARN(mciwave
, "can't find file='%08lx' !\n",
417 MCIWavDev
[wDevID
].openParms
.lpstrElementName
);
418 return MCIERR_FILE_NOT_FOUND
;
420 start
= 1; end
= 99999;
421 if (dwFlags
& MCI_FROM
) {
422 start
= lpParms
->dwFrom
;
423 TRACE(mciwave
, "MCI_FROM=%d \n", start
);
425 if (dwFlags
& MCI_TO
) {
427 TRACE(mciwave
,"MCI_TO=%d \n", end
);
430 lpWaveHdr
= &MCIWavDev
[wDevID
].WaveHdr
;
431 hData
= GlobalAlloc16(GMEM_MOVEABLE
, bufsize
);
432 lpWaveHdr
->lpData
= (LPSTR
)GlobalLock16(hData
);
433 lpWaveHdr
->dwBufferLength
= bufsize
;
434 lpWaveHdr
->dwUser
= 0L;
435 lpWaveHdr
->dwFlags
= 0L;
436 lpWaveHdr
->dwLoops
= 0L;
437 dwRet
=widMessage(wDevID
,WIDM_PREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
438 TRACE(mciwave
,"after WIDM_PREPARE \n");
440 lpWaveHdr
->dwBytesRecorded
= 0;
441 dwRet
= widMessage(wDevID
, WIDM_START
, 0, 0L, 0L);
442 TRACE(mciwave
, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
443 lpWaveHdr
, lpWaveHdr
->dwBytesRecorded
);
444 if (lpWaveHdr
->dwBytesRecorded
== 0) break;
446 TRACE(mciwave
,"before WIDM_UNPREPARE \n");
447 dwRet
= widMessage(wDevID
,WIDM_UNPREPARE
,0,(DWORD
)lpWaveHdr
,sizeof(WAVEHDR
));
448 TRACE(mciwave
,"after WIDM_UNPREPARE \n");
449 if (lpWaveHdr
->lpData
!= NULL
) {
450 GlobalUnlock16(hData
);
452 lpWaveHdr
->lpData
= NULL
;
454 if (dwFlags
& MCI_NOTIFY
) {
455 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
456 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
457 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
463 /**************************************************************************
464 * WAVE_mciStop [internal]
466 static DWORD
WAVE_mciStop(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
470 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
471 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
472 if (MCIWavDev
[wDevID
].fInput
)
473 dwRet
= widMessage(wDevID
, WIDM_STOP
, 0, dwFlags
, (DWORD
)lpParms
);
475 dwRet
= wodMessage(wDevID
, WODM_STOP
, 0, dwFlags
, (DWORD
)lpParms
);
481 /**************************************************************************
482 * WAVE_mciPause [internal]
484 static DWORD
WAVE_mciPause(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
488 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
489 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
490 if (MCIWavDev
[wDevID
].fInput
)
491 dwRet
= widMessage(wDevID
, WIDM_PAUSE
, 0, dwFlags
, (DWORD
)lpParms
);
493 dwRet
= wodMessage(wDevID
, WODM_PAUSE
, 0, dwFlags
, (DWORD
)lpParms
);
499 /**************************************************************************
500 * WAVE_mciResume [internal]
502 static DWORD
WAVE_mciResume(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
504 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
505 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
510 /**************************************************************************
511 * WAVE_mciSet [internal]
513 static DWORD
WAVE_mciSet(UINT16 wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
515 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
516 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
517 TRACE(mciwave
, "dwTimeFormat=%08lX\n", lpParms
->dwTimeFormat
);
518 TRACE(mciwave
, "dwAudio=%08lX\n", lpParms
->dwAudio
);
519 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
520 switch (lpParms
->dwTimeFormat
) {
521 case MCI_FORMAT_MILLISECONDS
:
522 TRACE(mciwave
, "MCI_FORMAT_MILLISECONDS !\n");
524 case MCI_FORMAT_BYTES
:
525 TRACE(mciwave
, "MCI_FORMAT_BYTES !\n");
527 case MCI_FORMAT_SAMPLES
:
528 TRACE(mciwave
, "MCI_FORMAT_SAMPLES !\n");
531 WARN(mciwave
, "bad time format !\n");
532 return MCIERR_BAD_TIME_FORMAT
;
535 if (dwFlags
& MCI_SET_VIDEO
) return MCIERR_UNSUPPORTED_FUNCTION
;
536 if (dwFlags
& MCI_SET_DOOR_OPEN
) return MCIERR_UNSUPPORTED_FUNCTION
;
537 if (dwFlags
& MCI_SET_DOOR_CLOSED
) return MCIERR_UNSUPPORTED_FUNCTION
;
538 if (dwFlags
& MCI_SET_AUDIO
)
539 TRACE(mciwave
,"MCI_SET_AUDIO !\n");
540 if (dwFlags
&& MCI_SET_ON
) {
541 TRACE(mciwave
,"MCI_SET_ON !\n");
542 if (dwFlags
&& MCI_SET_AUDIO_LEFT
)
543 TRACE(mciwave
,"MCI_SET_AUDIO_LEFT !\n");
544 if (dwFlags
&& MCI_SET_AUDIO_RIGHT
)
545 TRACE(mciwave
,"MCI_SET_AUDIO_RIGHT !\n");
547 if (dwFlags
& MCI_SET_OFF
)
548 TRACE(mciwave
,"MCI_SET_OFF !\n");
549 if (dwFlags
& MCI_WAVE_INPUT
)
550 TRACE(mciwave
,"MCI_WAVE_INPUT !\n");
551 if (dwFlags
& MCI_WAVE_OUTPUT
)
552 TRACE(mciwave
,"MCI_WAVE_OUTPUT !\n");
553 if (dwFlags
& MCI_WAVE_SET_ANYINPUT
)
554 TRACE(mciwave
,"MCI_WAVE_SET_ANYINPUT !\n");
555 if (dwFlags
& MCI_WAVE_SET_ANYOUTPUT
)
556 TRACE(mciwave
,"MCI_WAVE_SET_ANYOUTPUT !\n");
557 if (dwFlags
& MCI_WAVE_SET_AVGBYTESPERSEC
)
558 TRACE(mciwave
, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
559 if (dwFlags
& MCI_WAVE_SET_BITSPERSAMPLE
)
560 TRACE(mciwave
, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
561 if (dwFlags
& MCI_WAVE_SET_BLOCKALIGN
)
562 TRACE(mciwave
,"MCI_WAVE_SET_BLOCKALIGN !\n");
563 if (dwFlags
& MCI_WAVE_SET_CHANNELS
)
564 TRACE(mciwave
,"MCI_WAVE_SET_CHANNELS !\n");
565 if (dwFlags
& MCI_WAVE_SET_FORMATTAG
)
566 TRACE(mciwave
,"MCI_WAVE_SET_FORMATTAG !\n");
567 if (dwFlags
& MCI_WAVE_SET_SAMPLESPERSEC
)
568 TRACE(mciwave
, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
573 /**************************************************************************
574 * WAVE_mciStatus [internal]
576 static DWORD
WAVE_mciStatus(UINT16 wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
578 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
579 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
580 if (dwFlags
& MCI_STATUS_ITEM
) {
581 switch(lpParms
->dwItem
) {
582 case MCI_STATUS_CURRENT_TRACK
:
583 lpParms
->dwReturn
= 1;
585 case MCI_STATUS_LENGTH
:
586 lpParms
->dwReturn
= 5555;
587 if (dwFlags
& MCI_TRACK
) {
588 lpParms
->dwTrack
= 1;
589 lpParms
->dwReturn
= 2222;
592 case MCI_STATUS_MODE
:
593 lpParms
->dwReturn
= MCI_MODE_STOP
;
595 case MCI_STATUS_MEDIA_PRESENT
:
596 TRACE(mciwave
,"MCI_STATUS_MEDIA_PRESENT !\n");
597 lpParms
->dwReturn
= TRUE
;
599 case MCI_STATUS_NUMBER_OF_TRACKS
:
600 lpParms
->dwReturn
= 1;
602 case MCI_STATUS_POSITION
:
603 lpParms
->dwReturn
= 3333;
604 if (dwFlags
& MCI_STATUS_START
)
606 if (dwFlags
& MCI_TRACK
) {
607 lpParms
->dwTrack
= 1;
608 lpParms
->dwReturn
= 777;
611 case MCI_STATUS_READY
:
612 TRACE(mciwave
,"MCI_STATUS_READY !\n");
613 lpParms
->dwReturn
= TRUE
;
615 case MCI_STATUS_TIME_FORMAT
:
616 TRACE(mciwave
,"MCI_STATUS_TIME_FORMAT !\n");
617 lpParms
->dwReturn
= MCI_FORMAT_MILLISECONDS
;
620 TRACE(mciwave
,"MCI_WAVE_INPUT !\n");
621 lpParms
->dwReturn
= 0;
623 case MCI_WAVE_OUTPUT
:
624 TRACE(mciwave
,"MCI_WAVE_OUTPUT !\n");
625 lpParms
->dwReturn
= 0;
627 case MCI_WAVE_STATUS_AVGBYTESPERSEC
:
628 TRACE(mciwave
,"MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
629 lpParms
->dwReturn
= 22050;
631 case MCI_WAVE_STATUS_BITSPERSAMPLE
:
632 TRACE(mciwave
,"MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
633 lpParms
->dwReturn
= 8;
635 case MCI_WAVE_STATUS_BLOCKALIGN
:
636 TRACE(mciwave
,"MCI_WAVE_STATUS_BLOCKALIGN !\n");
637 lpParms
->dwReturn
= 1;
639 case MCI_WAVE_STATUS_CHANNELS
:
640 TRACE(mciwave
,"MCI_WAVE_STATUS_CHANNELS !\n");
641 lpParms
->dwReturn
= 1;
643 case MCI_WAVE_STATUS_FORMATTAG
:
644 TRACE(mciwave
,"MCI_WAVE_FORMATTAG !\n");
645 lpParms
->dwReturn
= WAVE_FORMAT_PCM
;
647 case MCI_WAVE_STATUS_LEVEL
:
648 TRACE(mciwave
,"MCI_WAVE_STATUS_LEVEL !\n");
649 lpParms
->dwReturn
= 0xAAAA5555;
651 case MCI_WAVE_STATUS_SAMPLESPERSEC
:
652 TRACE(mciwave
,"MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
653 lpParms
->dwReturn
= 22050;
656 WARN(mciwave
,"unknown command %08lX !\n", lpParms
->dwItem
);
657 return MCIERR_UNRECOGNIZED_COMMAND
;
660 if (dwFlags
& MCI_NOTIFY
) {
661 TRACE(mciwave
,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
662 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
663 MCIWavDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
668 /**************************************************************************
669 * WAVE_mciGetDevCaps [internal]
671 static DWORD
WAVE_mciGetDevCaps(UINT16 wDevID
, DWORD dwFlags
,
672 LPMCI_GETDEVCAPS_PARMS lpParms
)
674 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
675 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
676 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
677 switch(lpParms
->dwItem
) {
678 case MCI_GETDEVCAPS_CAN_RECORD
:
679 lpParms
->dwReturn
= TRUE
;
681 case MCI_GETDEVCAPS_HAS_AUDIO
:
682 lpParms
->dwReturn
= TRUE
;
684 case MCI_GETDEVCAPS_HAS_VIDEO
:
685 lpParms
->dwReturn
= FALSE
;
687 case MCI_GETDEVCAPS_DEVICE_TYPE
:
688 lpParms
->dwReturn
= MCI_DEVTYPE_WAVEFORM_AUDIO
;
690 case MCI_GETDEVCAPS_USES_FILES
:
691 lpParms
->dwReturn
= TRUE
;
693 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
694 lpParms
->dwReturn
= TRUE
;
696 case MCI_GETDEVCAPS_CAN_EJECT
:
697 lpParms
->dwReturn
= FALSE
;
699 case MCI_GETDEVCAPS_CAN_PLAY
:
700 lpParms
->dwReturn
= TRUE
;
702 case MCI_GETDEVCAPS_CAN_SAVE
:
703 lpParms
->dwReturn
= TRUE
;
705 case MCI_WAVE_GETDEVCAPS_INPUTS
:
706 lpParms
->dwReturn
= 1;
708 case MCI_WAVE_GETDEVCAPS_OUTPUTS
:
709 lpParms
->dwReturn
= 1;
712 return MCIERR_UNRECOGNIZED_COMMAND
;
718 /**************************************************************************
719 * WAVE_mciInfo [internal]
721 static DWORD
WAVE_mciInfo(UINT16 wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMS16 lpParms
)
723 TRACE(mciwave
, "(%u, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
724 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
725 lpParms
->lpstrReturn
= NULL
;
727 case MCI_INFO_PRODUCT
:
728 lpParms
->lpstrReturn
= "Open Sound System 0.5";
731 lpParms
->lpstrReturn
=
732 (LPSTR
)MCIWavDev
[wDevID
].openParms
.lpstrElementName
;
735 lpParms
->lpstrReturn
= "Open Sound System 0.5";
737 case MCI_WAVE_OUTPUT
:
738 lpParms
->lpstrReturn
= "Open Sound System 0.5";
741 return MCIERR_UNRECOGNIZED_COMMAND
;
743 if (lpParms
->lpstrReturn
!= NULL
)
744 lpParms
->dwRetSize
= strlen(lpParms
->lpstrReturn
);
746 lpParms
->dwRetSize
= 0;
751 /*-----------------------------------------------------------------------*/
754 /**************************************************************************
755 * wodGetDevCaps [internal]
757 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPS16 lpCaps
, DWORD dwSize
)
765 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
766 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
767 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
768 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
769 if (audio
== -1) return MMSYSERR_ALLOCATED
;
771 lpCaps
->wMid
= 0x0002;
772 lpCaps
->wPid
= 0x0104;
773 strcpy(lpCaps
->szPname
, "SB16 Wave Out");
775 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
776 lpCaps
->wPid
= 0x0001; /* Product ID */
777 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVOUT Driver");
779 lpCaps
->vDriverVersion
= 0x0100;
780 lpCaps
->dwFormats
= 0x00000000;
781 lpCaps
->dwSupport
= WAVECAPS_VOLUME
;
783 /* First bytespersampl, then stereo */
784 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
786 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
787 if (lpCaps
->wChannels
> 1) lpCaps
->dwSupport
|= WAVECAPS_LRVOLUME
;
790 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
791 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
792 if (lpCaps
->wChannels
> 1)
793 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
794 if (bytespersmpl
> 1) {
795 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
796 if (lpCaps
->wChannels
> 1)
797 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
801 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
802 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
803 if (lpCaps
->wChannels
> 1)
804 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
805 if (bytespersmpl
> 1) {
806 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
807 if (lpCaps
->wChannels
> 1)
808 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
812 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
813 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
814 if (lpCaps
->wChannels
> 1)
815 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
816 if (bytespersmpl
> 1) {
817 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
818 if (lpCaps
->wChannels
> 1)
819 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
823 TRACE(mciwave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
824 return MMSYSERR_NOERROR
;
828 /**************************************************************************
831 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
833 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
834 LPWAVEFORMAT lpFormat
;
836 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
837 if (lpDesc
== NULL
) {
838 WARN(mciwave
, "Invalid Parameter !\n");
839 return MMSYSERR_INVALPARAM
;
841 if (wDevID
>= MAX_WAVOUTDRV
) {
842 TRACE(mciwave
,"MAX_WAVOUTDRV reached !\n");
843 return MMSYSERR_ALLOCATED
;
845 WOutDev
[wDevID
].unixdev
= 0;
846 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
847 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
849 WARN(mciwave
, "can't open !\n");
850 return MMSYSERR_ALLOCATED
;
852 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
853 if (abuf_size
< 1024 || abuf_size
> 65536) {
855 WARN(mciwave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
857 WARN(mciwave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
858 return MMSYSERR_NOTENABLED
;
860 WOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
861 switch(WOutDev
[wDevID
].wFlags
) {
863 TRACE(mciwave
, "CALLBACK_NULL !\n");
866 TRACE(mciwave
, "CALLBACK_WINDOW !\n");
869 TRACE(mciwave
, "CALLBACK_TASK !\n");
872 TRACE(mciwave
, "CALLBACK_FUNCTION !\n");
875 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
876 WOutDev
[wDevID
].unixdev
= audio
;
877 WOutDev
[wDevID
].dwTotalPlayed
= 0;
878 WOutDev
[wDevID
].bufsize
= abuf_size
;
879 /* FIXME: copy lpFormat too? */
880 memcpy(&WOutDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
881 TRACE(mciwave
,"lpDesc->lpFormat = %p\n",lpDesc
->lpFormat
);
882 lpFormat
= lpDesc
->lpFormat
;
883 TRACE(mciwave
,"lpFormat = %p\n",lpFormat
);
884 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
885 WARN(mciwave
,"Bad format %04X !\n",
886 lpFormat
->wFormatTag
);
887 WARN(mciwave
,"Bad nChannels %d !\n",
888 lpFormat
->nChannels
);
889 WARN(mciwave
,"Bad nSamplesPerSec %ld !\n",
890 lpFormat
->nSamplesPerSec
);
891 return WAVERR_BADFORMAT
;
893 memcpy(&WOutDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
894 if (WOutDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
895 if (WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
896 TRACE(mciwave
,"wBitsPerSample=%u !\n",
897 WOutDev
[wDevID
].Format
.wBitsPerSample
);
898 if (WOutDev
[wDevID
].Format
.wBitsPerSample
== 0) {
899 WOutDev
[wDevID
].Format
.wBitsPerSample
= 8 *
900 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
901 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
902 WOutDev
[wDevID
].Format
.wf
.nChannels
;
904 samplesize
= WOutDev
[wDevID
].Format
.wBitsPerSample
;
905 smplrate
= WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
906 dsp_stereo
= (WOutDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
908 /* First size and stereo then samplerate */
909 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
910 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
911 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
913 TRACE(mciwave
,"wBitsPerSample=%u !\n",
914 WOutDev
[wDevID
].Format
.wBitsPerSample
);
915 TRACE(mciwave
,"nAvgBytesPerSec=%lu !\n",
916 WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
917 TRACE(mciwave
,"nSamplesPerSec=%lu !\n",
918 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
919 TRACE(mciwave
,"nChannels=%u !\n",
920 WOutDev
[wDevID
].Format
.wf
.nChannels
);
921 if (WAVE_NotifyClient(wDevID
, WOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
922 WARN(mciwave
, "can't notify client !\n");
923 return MMSYSERR_INVALPARAM
;
925 return MMSYSERR_NOERROR
;
928 /**************************************************************************
929 * wodClose [internal]
931 static DWORD
wodClose(WORD wDevID
)
933 TRACE(mciwave
,"(%u);\n", wDevID
);
934 if (wDevID
> MAX_WAVOUTDRV
) return MMSYSERR_INVALPARAM
;
935 if (WOutDev
[wDevID
].unixdev
== 0) {
936 WARN(mciwave
, "can't close !\n");
937 return MMSYSERR_NOTENABLED
;
939 if (WOutDev
[wDevID
].lpQueueHdr
!= NULL
) {
940 WARN(mciwave
, "still buffers open !\n");
941 /* Don't care. Who needs those buffers anyway */
942 /*return WAVERR_STILLPLAYING; */
944 close(WOutDev
[wDevID
].unixdev
);
945 WOutDev
[wDevID
].unixdev
= 0;
946 WOutDev
[wDevID
].bufsize
= 0;
947 WOutDev
[wDevID
].lpQueueHdr
= NULL
;
948 if (WAVE_NotifyClient(wDevID
, WOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
949 WARN(mciwave
, "can't notify client !\n");
950 return MMSYSERR_INVALPARAM
;
952 return MMSYSERR_NOERROR
;
955 /**************************************************************************
956 * wodWrite [internal]
957 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
958 * device, and initiate async playing.
960 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
966 TRACE(mciwave
,"(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
967 if (WOutDev
[wDevID
].unixdev
== 0) {
968 WARN(mciwave
, "can't play !\n");
969 return MMSYSERR_NOTENABLED
;
971 if (lpWaveHdr
->lpData
== NULL
) return WAVERR_UNPREPARED
;
972 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) return WAVERR_UNPREPARED
;
973 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) return WAVERR_STILLPLAYING
;
974 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
975 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
976 TRACE(mciwave
, "dwBufferLength %lu !\n",
977 lpWaveHdr
->dwBufferLength
);
978 TRACE(mciwave
, "WOutDev[%u].unixdev %u !\n",
979 wDevID
, WOutDev
[wDevID
].unixdev
);
980 lpData
= lpWaveHdr
->lpData
;
981 count
= write (WOutDev
[wDevID
].unixdev
, lpData
, lpWaveHdr
->dwBufferLength
);
982 TRACE(mciwave
,"write returned count %u !\n",count
);
983 if (count
!= lpWaveHdr
->dwBufferLength
) {
984 WARN(mciwave
, " error writting !\n");
985 return MMSYSERR_NOTENABLED
;
987 WOutDev
[wDevID
].dwTotalPlayed
+= count
;
988 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
989 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
990 if ((DWORD
)lpWaveHdr
->lpData
!=lpWaveHdr
->reserved
) {
991 /* FIXME: what if it expects it's OWN lpwavehdr back? */
992 xwavehdr
= SEGPTR_NEW(WAVEHDR
);
993 memcpy(xwavehdr
,lpWaveHdr
,sizeof(WAVEHDR
));
994 xwavehdr
->lpData
= (LPBYTE
)xwavehdr
->reserved
;
995 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)SEGPTR_GET(xwavehdr
), count
) != MMSYSERR_NOERROR
) {
996 WARN(mciwave
, "can't notify client !\n");
997 SEGPTR_FREE(xwavehdr
);
998 return MMSYSERR_INVALPARAM
;
1000 SEGPTR_FREE(xwavehdr
);
1002 if (WAVE_NotifyClient(wDevID
, WOM_DONE
, (DWORD
)lpWaveHdr
, count
) != MMSYSERR_NOERROR
) {
1003 WARN(mciwave
, "can't notify client !\n");
1004 return MMSYSERR_INVALPARAM
;
1007 return MMSYSERR_NOERROR
;
1010 /**************************************************************************
1011 * wodPrepare [internal]
1013 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1015 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1016 if (WOutDev
[wDevID
].unixdev
== 0) {
1017 WARN(mciwave
, "can't prepare !\n");
1018 return MMSYSERR_NOTENABLED
;
1020 /* don't append to queue, wodWrite does that */
1021 WOutDev
[wDevID
].dwTotalPlayed
= 0;
1022 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1023 return WAVERR_STILLPLAYING
;
1024 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1025 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1026 return MMSYSERR_NOERROR
;
1029 /**************************************************************************
1030 * wodUnprepare [internal]
1032 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1034 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1035 if (WOutDev
[wDevID
].unixdev
== 0) {
1036 WARN(mciwave
, "can't unprepare !\n");
1037 return MMSYSERR_NOTENABLED
;
1039 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1040 return WAVERR_STILLPLAYING
;
1042 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
1043 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1044 TRACE(mciwave
, "all headers unprepared !\n");
1045 return MMSYSERR_NOERROR
;
1048 /**************************************************************************
1049 * wodRestart [internal]
1051 static DWORD
wodRestart(WORD wDevID
)
1053 TRACE(mciwave
,"(%u);\n", wDevID
);
1054 if (WOutDev
[wDevID
].unixdev
== 0) {
1055 WARN(mciwave
, "can't restart !\n");
1056 return MMSYSERR_NOTENABLED
;
1058 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1059 /* FIXME: Myst crashes with this ... hmm -MM
1060 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1061 WARN(mciwave, "can't notify client !\n");
1062 return MMSYSERR_INVALPARAM;
1066 return MMSYSERR_NOERROR
;
1069 /**************************************************************************
1070 * wodReset [internal]
1072 static DWORD
wodReset(WORD wDevID
)
1074 TRACE(mciwave
,"(%u);\n", wDevID
);
1075 if (WOutDev
[wDevID
].unixdev
== 0) {
1076 WARN(mciwave
, "can't reset !\n");
1077 return MMSYSERR_NOTENABLED
;
1079 return MMSYSERR_NOERROR
;
1083 /**************************************************************************
1084 * wodGetPosition [internal]
1086 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
1089 TRACE(mciwave
,"(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
1090 if (WOutDev
[wDevID
].unixdev
== 0) {
1091 WARN(mciwave
, "can't get pos !\n");
1092 return MMSYSERR_NOTENABLED
;
1094 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
1095 TRACE(mciwave
,"wType=%04X !\n",
1097 TRACE(mciwave
,"wBitsPerSample=%u\n",
1098 WOutDev
[wDevID
].Format
.wBitsPerSample
);
1099 TRACE(mciwave
,"nSamplesPerSec=%lu\n",
1100 WOutDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1101 TRACE(mciwave
,"nChannels=%u\n",
1102 WOutDev
[wDevID
].Format
.wf
.nChannels
);
1103 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1104 WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1105 switch(lpTime
->wType
) {
1107 lpTime
->u
.cb
= WOutDev
[wDevID
].dwTotalPlayed
;
1108 TRACE(mciwave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
1111 TRACE(mciwave
,"dwTotalPlayed=%lu\n",
1112 WOutDev
[wDevID
].dwTotalPlayed
);
1113 TRACE(mciwave
,"wBitsPerSample=%u\n",
1114 WOutDev
[wDevID
].Format
.wBitsPerSample
);
1115 lpTime
->u
.sample
= WOutDev
[wDevID
].dwTotalPlayed
* 8 /
1116 WOutDev
[wDevID
].Format
.wBitsPerSample
;
1117 TRACE(mciwave
,"TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
1120 time
= WOutDev
[wDevID
].dwTotalPlayed
/
1121 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1122 lpTime
->u
.smpte
.hour
= time
/ 108000;
1123 time
-= lpTime
->u
.smpte
.hour
* 108000;
1124 lpTime
->u
.smpte
.min
= time
/ 1800;
1125 time
-= lpTime
->u
.smpte
.min
* 1800;
1126 lpTime
->u
.smpte
.sec
= time
/ 30;
1127 time
-= lpTime
->u
.smpte
.sec
* 30;
1128 lpTime
->u
.smpte
.frame
= time
;
1129 lpTime
->u
.smpte
.fps
= 30;
1131 "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1132 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
1133 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1136 FIXME(mciwave
, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime
->wType
);
1137 lpTime
->wType
= TIME_MS
;
1139 lpTime
->u
.ms
= WOutDev
[wDevID
].dwTotalPlayed
/
1140 (WOutDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1141 TRACE(mciwave
,"wodGetPosition // TIME_MS=%lu\n", lpTime
->u
.ms
);
1144 return MMSYSERR_NOERROR
;
1147 /**************************************************************************
1148 * wodGetVolume [internal]
1150 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
1153 int volume
, left
, right
;
1154 TRACE(mciwave
,"(%u, %p);\n", wDevID
, lpdwVol
);
1155 if (lpdwVol
== NULL
) return MMSYSERR_NOTENABLED
;
1156 if ((mixer
= open(MIXER_DEV
, O_RDONLY
)) < 0) {
1157 WARN(mciwave
, "mixer device not available !\n");
1158 return MMSYSERR_NOTENABLED
;
1160 if (ioctl(mixer
, SOUND_MIXER_READ_PCM
, &volume
) == -1) {
1161 WARN(mciwave
, "unable read mixer !\n");
1162 return MMSYSERR_NOTENABLED
;
1165 left
= volume
& 0x7F;
1166 right
= (volume
>> 8) & 0x7F;
1167 TRACE(mciwave
,"left=%d right=%d !\n", left
, right
);
1168 *lpdwVol
= MAKELONG(left
<< 9, right
<< 9);
1169 return MMSYSERR_NOERROR
;
1173 /**************************************************************************
1174 * wodSetVolume [internal]
1176 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
1180 TRACE(mciwave
,"(%u, %08lX);\n", wDevID
, dwParam
);
1181 volume
= (LOWORD(dwParam
) >> 9 & 0x7F) +
1182 ((HIWORD(dwParam
) >> 9 & 0x7F) << 8);
1183 if ((mixer
= open(MIXER_DEV
, O_WRONLY
)) < 0) {
1184 WARN(mciwave
, "mixer device not available !\n");
1185 return MMSYSERR_NOTENABLED
;
1187 if (ioctl(mixer
, SOUND_MIXER_WRITE_PCM
, &volume
) == -1) {
1188 WARN(mciwave
, "unable set mixer !\n");
1189 return MMSYSERR_NOTENABLED
;
1192 return MMSYSERR_NOERROR
;
1195 /**************************************************************************
1196 * wodMessage [sample driver]
1198 DWORD
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1199 DWORD dwParam1
, DWORD dwParam2
)
1202 TRACE(mciwave
,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1203 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1206 return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1208 return wodClose(wDevID
);
1210 return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1212 return MMSYSERR_NOTSUPPORTED
;
1214 return MMSYSERR_NOTSUPPORTED
;
1216 return wodGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1217 case WODM_BREAKLOOP
:
1218 return MMSYSERR_NOTSUPPORTED
;
1220 return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1221 case WODM_UNPREPARE
:
1222 return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1223 case WODM_GETDEVCAPS
:
1224 return wodGetDevCaps(wDevID
,(LPWAVEOUTCAPS16
)dwParam1
,dwParam2
);
1225 case WODM_GETNUMDEVS
:
1226 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1227 audio
= open (SOUND_DEV
, O_WRONLY
, 0);
1236 return MMSYSERR_NOTSUPPORTED
;
1238 return MMSYSERR_NOTSUPPORTED
;
1239 case WODM_GETPLAYBACKRATE
:
1240 return MMSYSERR_NOTSUPPORTED
;
1241 case WODM_SETPLAYBACKRATE
:
1242 return MMSYSERR_NOTSUPPORTED
;
1243 case WODM_GETVOLUME
:
1244 return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
1245 case WODM_SETVOLUME
:
1246 return wodSetVolume(wDevID
, dwParam1
);
1248 return wodRestart(wDevID
);
1250 return wodReset(wDevID
);
1252 WARN(mciwave
,"unknown message !\n");
1254 return MMSYSERR_NOTSUPPORTED
;
1258 /*-----------------------------------------------------------------------*/
1260 /**************************************************************************
1261 * widGetDevCaps [internal]
1263 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPS16 lpCaps
, DWORD dwSize
)
1265 int audio
,smplrate
,samplesize
=16,dsp_stereo
=1,bytespersmpl
;
1267 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
1268 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
1269 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
1270 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1271 if (audio
== -1) return MMSYSERR_ALLOCATED
;
1273 lpCaps
->wMid
= 0x0002;
1274 lpCaps
->wPid
= 0x0004;
1275 strcpy(lpCaps
->szPname
, "SB16 Wave In");
1277 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
1278 lpCaps
->wPid
= 0x0001; /* Product ID */
1279 strcpy(lpCaps
->szPname
, "OpenSoundSystem WAVIN Driver");
1281 lpCaps
->dwFormats
= 0x00000000;
1282 lpCaps
->wChannels
= (IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
) != 0) ? 1 : 2;
1283 bytespersmpl
= (IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
) != 0) ? 1 : 2;
1285 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1286 lpCaps
->dwFormats
|= WAVE_FORMAT_4M08
;
1287 if (lpCaps
->wChannels
> 1)
1288 lpCaps
->dwFormats
|= WAVE_FORMAT_4S08
;
1289 if (bytespersmpl
> 1) {
1290 lpCaps
->dwFormats
|= WAVE_FORMAT_4M16
;
1291 if (lpCaps
->wChannels
> 1)
1292 lpCaps
->dwFormats
|= WAVE_FORMAT_4S16
;
1296 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1297 lpCaps
->dwFormats
|= WAVE_FORMAT_2M08
;
1298 if (lpCaps
->wChannels
> 1)
1299 lpCaps
->dwFormats
|= WAVE_FORMAT_2S08
;
1300 if (bytespersmpl
> 1) {
1301 lpCaps
->dwFormats
|= WAVE_FORMAT_2M16
;
1302 if (lpCaps
->wChannels
> 1)
1303 lpCaps
->dwFormats
|= WAVE_FORMAT_2S16
;
1307 if (IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
) == 0) {
1308 lpCaps
->dwFormats
|= WAVE_FORMAT_1M08
;
1309 if (lpCaps
->wChannels
> 1)
1310 lpCaps
->dwFormats
|= WAVE_FORMAT_1S08
;
1311 if (bytespersmpl
> 1) {
1312 lpCaps
->dwFormats
|= WAVE_FORMAT_1M16
;
1313 if (lpCaps
->wChannels
> 1)
1314 lpCaps
->dwFormats
|= WAVE_FORMAT_1S16
;
1318 TRACE(mciwave
, "dwFormats = %08lX\n", lpCaps
->dwFormats
);
1319 return MMSYSERR_NOERROR
;
1323 /**************************************************************************
1324 * widOpen [internal]
1326 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
1328 int audio
,abuf_size
,smplrate
,samplesize
,dsp_stereo
;
1329 LPWAVEFORMAT lpFormat
;
1331 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
1332 if (lpDesc
== NULL
) {
1333 WARN(mciwave
, "Invalid Parameter !\n");
1334 return MMSYSERR_INVALPARAM
;
1336 if (wDevID
>= MAX_WAVINDRV
) {
1337 TRACE(mciwave
,"MAX_WAVINDRV reached !\n");
1338 return MMSYSERR_ALLOCATED
;
1340 WInDev
[wDevID
].unixdev
= 0;
1341 if (access(SOUND_DEV
,0) != 0) return MMSYSERR_NOTENABLED
;
1342 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1344 WARN(mciwave
,"can't open !\n");
1345 return MMSYSERR_ALLOCATED
;
1347 IOCTL(audio
, SNDCTL_DSP_GETBLKSIZE
, abuf_size
);
1348 if (abuf_size
< 1024 || abuf_size
> 65536) {
1349 if (abuf_size
== -1)
1350 WARN(mciwave
, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1352 WARN(mciwave
, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1353 return MMSYSERR_NOTENABLED
;
1355 WInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
1356 switch(WInDev
[wDevID
].wFlags
) {
1358 TRACE(mciwave
,"CALLBACK_NULL!\n");
1361 TRACE(mciwave
,"CALLBACK_WINDOW!\n");
1364 TRACE(mciwave
,"CALLBACK_TASK!\n");
1367 TRACE(mciwave
,"CALLBACK_FUNCTION!\n");
1370 if (WInDev
[wDevID
].lpQueueHdr
) {
1371 HeapFree(GetProcessHeap(),0,WInDev
[wDevID
].lpQueueHdr
);
1372 WInDev
[wDevID
].lpQueueHdr
= NULL
;
1374 WInDev
[wDevID
].unixdev
= audio
;
1375 WInDev
[wDevID
].bufsize
= abuf_size
;
1376 WInDev
[wDevID
].dwTotalRecorded
= 0;
1377 memcpy(&WInDev
[wDevID
].waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
1378 lpFormat
= (LPWAVEFORMAT
) lpDesc
->lpFormat
;
1379 if (lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
) {
1380 WARN(mciwave
, "Bad format %04X !\n",
1381 lpFormat
->wFormatTag
);
1382 return WAVERR_BADFORMAT
;
1384 memcpy(&WInDev
[wDevID
].Format
, lpFormat
, sizeof(PCMWAVEFORMAT
));
1385 WInDev
[wDevID
].Format
.wBitsPerSample
= 8; /* <-------------- */
1386 if (WInDev
[wDevID
].Format
.wf
.nChannels
== 0) return WAVERR_BADFORMAT
;
1387 if (WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
== 0) return WAVERR_BADFORMAT
;
1388 if (WInDev
[wDevID
].Format
.wBitsPerSample
== 0) {
1389 WInDev
[wDevID
].Format
.wBitsPerSample
= 8 *
1390 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/
1391 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
) /
1392 WInDev
[wDevID
].Format
.wf
.nChannels
;
1394 samplesize
= WInDev
[wDevID
].Format
.wBitsPerSample
;
1395 smplrate
= WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
;
1396 dsp_stereo
= (WInDev
[wDevID
].Format
.wf
.nChannels
> 1) ? TRUE
: FALSE
;
1397 IOCTL(audio
, SNDCTL_DSP_SPEED
, smplrate
);
1398 IOCTL(audio
, SNDCTL_DSP_SAMPLESIZE
, samplesize
);
1399 IOCTL(audio
, SNDCTL_DSP_STEREO
, dsp_stereo
);
1400 TRACE(mciwave
,"wBitsPerSample=%u !\n",
1401 WInDev
[wDevID
].Format
.wBitsPerSample
);
1402 TRACE(mciwave
,"nSamplesPerSec=%lu !\n",
1403 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1404 TRACE(mciwave
,"nChannels=%u !\n",
1405 WInDev
[wDevID
].Format
.wf
.nChannels
);
1406 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1407 WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1408 if (WAVE_NotifyClient(wDevID
, WIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
1409 WARN(mciwave
,"can't notify client !\n");
1410 return MMSYSERR_INVALPARAM
;
1412 return MMSYSERR_NOERROR
;
1415 /**************************************************************************
1416 * widClose [internal]
1418 static DWORD
widClose(WORD wDevID
)
1420 TRACE(mciwave
,"(%u);\n", wDevID
);
1421 if (wDevID
> MAX_WAVINDRV
) return MMSYSERR_INVALPARAM
;
1422 if (WInDev
[wDevID
].unixdev
== 0) {
1423 WARN(mciwave
,"can't close !\n");
1424 return MMSYSERR_NOTENABLED
;
1426 if (WInDev
[wDevID
].lpQueueHdr
!= NULL
) {
1427 WARN(mciwave
, "still buffers open !\n");
1428 return WAVERR_STILLPLAYING
;
1430 close(WInDev
[wDevID
].unixdev
);
1431 WInDev
[wDevID
].unixdev
= 0;
1432 WInDev
[wDevID
].bufsize
= 0;
1433 if (WAVE_NotifyClient(wDevID
, WIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
1434 WARN(mciwave
,"can't notify client !\n");
1435 return MMSYSERR_INVALPARAM
;
1437 return MMSYSERR_NOERROR
;
1440 /**************************************************************************
1441 * widAddBuffer [internal]
1443 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1448 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1449 if (WInDev
[wDevID
].unixdev
== 0) {
1450 WARN(mciwave
,"can't do it !\n");
1451 return MMSYSERR_NOTENABLED
;
1453 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
1454 TRACE(mciwave
, "never been prepared !\n");
1455 return WAVERR_UNPREPARED
;
1457 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
1458 TRACE(mciwave
, "header already in use !\n");
1459 return WAVERR_STILLPLAYING
;
1461 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1462 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
1463 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1464 lpWaveHdr
->dwBytesRecorded
= 0;
1465 if (WInDev
[wDevID
].lpQueueHdr
== NULL
) {
1466 WInDev
[wDevID
].lpQueueHdr
= lpWaveHdr
;
1468 lpWIHdr
= WInDev
[wDevID
].lpQueueHdr
;
1469 while (lpWIHdr
->lpNext
!= NULL
) {
1470 lpWIHdr
= lpWIHdr
->lpNext
;
1473 lpWIHdr
->lpNext
= lpWaveHdr
;
1474 lpWaveHdr
->lpNext
= NULL
;
1477 TRACE(mciwave
, "buffer added ! (now %u in queue)\n", count
);
1478 return MMSYSERR_NOERROR
;
1481 /**************************************************************************
1482 * widPrepare [internal]
1484 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1486 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1487 if (WInDev
[wDevID
].unixdev
== 0) {
1488 WARN(mciwave
,"can't prepare !\n");
1489 return MMSYSERR_NOTENABLED
;
1491 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1492 return WAVERR_STILLPLAYING
;
1493 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1494 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1495 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1496 lpWaveHdr
->dwBytesRecorded
= 0;
1497 TRACE(mciwave
,"header prepared !\n");
1498 return MMSYSERR_NOERROR
;
1501 /**************************************************************************
1502 * widUnprepare [internal]
1504 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1506 TRACE(mciwave
, "(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1507 if (WInDev
[wDevID
].unixdev
== 0) {
1508 WARN(mciwave
,"can't unprepare !\n");
1509 return MMSYSERR_NOTENABLED
;
1511 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
1512 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1513 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1515 TRACE(mciwave
, "all headers unprepared !\n");
1516 return MMSYSERR_NOERROR
;
1519 /**************************************************************************
1520 * widStart [internal]
1522 static DWORD
widStart(WORD wDevID
)
1527 LPWAVEHDR
*lpWaveHdr
;
1529 TRACE(mciwave
,"(%u);\n", wDevID
);
1530 if (WInDev
[wDevID
].unixdev
== 0) {
1531 WARN(mciwave
, "can't start recording !\n");
1532 return MMSYSERR_NOTENABLED
;
1535 lpWaveHdr
= &(WInDev
[wDevID
].lpQueueHdr
);
1536 TRACE(mciwave
,"lpWaveHdr = %08lx\n",(DWORD
)lpWaveHdr
);
1537 if (!*lpWaveHdr
|| !(*lpWaveHdr
)->lpData
) {
1538 TRACE(mciwave
,"never been prepared !\n");
1539 return WAVERR_UNPREPARED
;
1542 while(*lpWaveHdr
!= NULL
) {
1543 lpWIHdr
= *lpWaveHdr
;
1544 TRACE(mciwave
, "recording buf#%u=%p size=%lu \n",
1545 count
, lpWIHdr
->lpData
, lpWIHdr
->dwBufferLength
);
1547 bytesRead
= read (WInDev
[wDevID
].unixdev
,
1549 lpWIHdr
->dwBufferLength
);
1551 perror("read from audio device");
1552 TRACE(mciwave
,"bytesread=%d (%ld)\n",
1553 bytesRead
,lpWIHdr
->dwBufferLength
);
1554 lpWIHdr
->dwBytesRecorded
= bytesRead
;
1555 WInDev
[wDevID
].dwTotalRecorded
+= lpWIHdr
->dwBytesRecorded
;
1556 lpWIHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1557 lpWIHdr
->dwFlags
|= WHDR_DONE
;
1559 /* FIXME: should pass segmented pointer here, do we need that?*/
1560 if (WAVE_NotifyClient(wDevID
, WIM_DATA
, (DWORD
)lpWaveHdr
, lpWIHdr
->dwBytesRecorded
) != MMSYSERR_NOERROR
) {
1561 WARN(mciwave
, "can't notify client !\n");
1562 return MMSYSERR_INVALPARAM
;
1564 /* removes the current block from the queue */
1565 *lpWaveHdr
= lpWIHdr
->lpNext
;
1568 TRACE(mciwave
,"end of recording !\n");
1570 return MMSYSERR_NOERROR
;
1573 /**************************************************************************
1574 * widStop [internal]
1576 static DWORD
widStop(WORD wDevID
)
1578 TRACE(mciwave
,"(%u);\n", wDevID
);
1579 if (WInDev
[wDevID
].unixdev
== 0) {
1580 WARN(mciwave
,"can't stop !\n");
1581 return MMSYSERR_NOTENABLED
;
1583 return MMSYSERR_NOERROR
;
1586 /**************************************************************************
1587 * widReset [internal]
1589 static DWORD
widReset(WORD wDevID
)
1591 TRACE(mciwave
,"(%u);\n", wDevID
);
1592 if (WInDev
[wDevID
].unixdev
== 0) {
1593 WARN(mciwave
,"can't reset !\n");
1594 return MMSYSERR_NOTENABLED
;
1596 return MMSYSERR_NOERROR
;
1599 /**************************************************************************
1600 * widGetPosition [internal]
1602 static DWORD
widGetPosition(WORD wDevID
, LPMMTIME16 lpTime
, DWORD uSize
)
1606 TRACE(mciwave
, "(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
1607 if (WInDev
[wDevID
].unixdev
== 0) {
1608 WARN(mciwave
,"can't get pos !\n");
1609 return MMSYSERR_NOTENABLED
;
1611 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
1612 TRACE(mciwave
,"wType=%04X !\n",
1614 TRACE(mciwave
,"wBitsPerSample=%u\n",
1615 WInDev
[wDevID
].Format
.wBitsPerSample
);
1616 TRACE(mciwave
,"nSamplesPerSec=%lu\n",
1617 WInDev
[wDevID
].Format
.wf
.nSamplesPerSec
);
1618 TRACE(mciwave
,"nChannels=%u\n",
1619 WInDev
[wDevID
].Format
.wf
.nChannels
);
1620 TRACE(mciwave
,"nAvgBytesPerSec=%lu\n",
1621 WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
);
1623 switch(lpTime
->wType
) {
1625 lpTime
->u
.cb
= WInDev
[wDevID
].dwTotalRecorded
;
1626 TRACE(mciwave
,"TIME_BYTES=%lu\n", lpTime
->u
.cb
);
1629 lpTime
->u
.sample
= WInDev
[wDevID
].dwTotalRecorded
* 8 /
1630 WInDev
[wDevID
].Format
.wBitsPerSample
;
1631 TRACE(mciwave
, "TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
1634 time
= WInDev
[wDevID
].dwTotalRecorded
/
1635 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1636 lpTime
->u
.smpte
.hour
= time
/ 108000;
1637 time
-= lpTime
->u
.smpte
.hour
* 108000;
1638 lpTime
->u
.smpte
.min
= time
/ 1800;
1639 time
-= lpTime
->u
.smpte
.min
* 1800;
1640 lpTime
->u
.smpte
.sec
= time
/ 30;
1641 time
-= lpTime
->u
.smpte
.sec
* 30;
1642 lpTime
->u
.smpte
.frame
= time
;
1643 lpTime
->u
.smpte
.fps
= 30;
1644 TRACE(mciwave
,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1645 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
1646 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1649 FIXME(mciwave
, "format not supported ! use TIME_MS !\n");
1650 lpTime
->wType
= TIME_MS
;
1652 lpTime
->u
.ms
= WInDev
[wDevID
].dwTotalRecorded
/
1653 (WInDev
[wDevID
].Format
.wf
.nAvgBytesPerSec
/ 1000);
1654 TRACE(mciwave
, "TIME_MS=%lu\n", lpTime
->u
.ms
);
1657 return MMSYSERR_NOERROR
;
1660 /**************************************************************************
1661 * widMessage [sample driver]
1663 DWORD
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1664 DWORD dwParam1
, DWORD dwParam2
)
1667 TRACE(mciwave
,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1668 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1671 return widOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1673 return widClose(wDevID
);
1674 case WIDM_ADDBUFFER
:
1675 return widAddBuffer(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1677 return widPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1678 case WIDM_UNPREPARE
:
1679 return widUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1680 case WIDM_GETDEVCAPS
:
1681 return widGetDevCaps(wDevID
, (LPWAVEINCAPS16
)dwParam1
,dwParam2
);
1682 case WIDM_GETNUMDEVS
:
1683 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1684 audio
= open (SOUND_DEV
, O_RDONLY
, 0);
1693 return widGetPosition(wDevID
, (LPMMTIME16
)dwParam1
, dwParam2
);
1695 return widReset(wDevID
);
1697 return widStart(wDevID
);
1699 return widStop(wDevID
);
1701 return widStop(wDevID
);
1703 WARN(mciwave
,"unknown message !\n");
1705 return MMSYSERR_NOTSUPPORTED
;
1709 /**************************************************************************
1710 * AUDIO_DriverProc [sample driver]
1712 LONG
WAVE_DriverProc(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1713 DWORD dwParam1
, DWORD dwParam2
)
1715 TRACE(mciwave
,"(%08lX, %04X, %04X, %08lX, %08lX)\n",
1716 dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1730 case DRV_QUERYCONFIGURE
:
1733 MessageBox16(0, "Sample MultiMedia Linux Driver !",
1734 "MMLinux Driver", MB_OK
);
1737 return DRVCNF_RESTART
;
1739 return DRVCNF_RESTART
;
1740 case MCI_OPEN_DRIVER
:
1742 return WAVE_mciOpen(dwDevID
, dwParam1
, (LPMCI_WAVE_OPEN_PARMS16
)PTR_SEG_TO_LIN(dwParam2
));
1744 return WAVE_mciCue(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1745 case MCI_CLOSE_DRIVER
:
1747 return WAVE_mciClose(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1749 return WAVE_mciPlay(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1751 return WAVE_mciRecord(dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1753 return WAVE_mciStop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1755 return WAVE_mciSet(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1757 return WAVE_mciPause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1759 return WAVE_mciResume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1761 return WAVE_mciStatus(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1762 case MCI_GETDEVCAPS
:
1763 return WAVE_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
1765 return WAVE_mciInfo(dwDevID
, dwParam1
, (LPMCI_INFO_PARMS16
)PTR_SEG_TO_LIN(dwParam2
));
1768 return MMSYSERR_NOTSUPPORTED
;
1770 return MMSYSERR_NOTSUPPORTED
;
1772 return MMSYSERR_NOTSUPPORTED
;
1774 return MMSYSERR_NOTSUPPORTED
;
1776 return MMSYSERR_NOTSUPPORTED
;
1778 return MMSYSERR_NOTSUPPORTED
;
1780 return MMSYSERR_NOTSUPPORTED
;
1782 return MMSYSERR_NOTSUPPORTED
;
1784 return MMSYSERR_NOTSUPPORTED
;
1786 return MMSYSERR_NOTSUPPORTED
;
1788 return MMSYSERR_NOTSUPPORTED
;
1790 return MMSYSERR_NOTSUPPORTED
;
1792 return MMSYSERR_NOTSUPPORTED
;
1794 return MMSYSERR_NOTSUPPORTED
;
1796 return MMSYSERR_NOTSUPPORTED
;
1798 return MMSYSERR_NOTSUPPORTED
;
1800 return MMSYSERR_NOTSUPPORTED
;
1803 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
1805 return MMSYSERR_NOTENABLED
;
1808 #else /* !HAVE_OSS */
1810 /**************************************************************************
1811 * wodMessage [sample driver]
1813 DWORD
wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1814 DWORD dwParam1
, DWORD dwParam2
)
1816 FIXME(mciwave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1817 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1818 return MMSYSERR_NOTENABLED
;
1821 /**************************************************************************
1822 * widMessage [sample driver]
1824 DWORD
widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1825 DWORD dwParam1
, DWORD dwParam2
)
1827 FIXME(mciwave
,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1828 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1829 return MMSYSERR_NOTENABLED
;
1832 /**************************************************************************
1833 * AUDIO_DriverProc [sample driver]
1835 LONG
WAVE_DriverProc(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
1836 DWORD dwParam1
, DWORD dwParam2
)
1838 return MMSYSERR_NOTENABLED
;
1840 #endif /* HAVE_OSS */