Release 980726
[wine/multimedia.git] / multimedia / audio.c
blob7ae02514acc7a48845c0249e5bab48177ef21798
1 /*
2 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
4 * Copyright 1994 Martin Ayotte
5 */
6 /*
7 * FIXME:
8 * - record/play should and must be done asynchronous
9 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
12 #define EMULATE_SB16
14 #define DEBUG_MCIWAVE
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include "windows.h"
22 #include "user.h"
23 #include "driver.h"
24 #include "mmsystem.h"
25 #include "heap.h"
26 #include "ldt.h"
27 #include "debug.h"
29 #ifdef HAVE_OSS
31 #ifdef HAVE_MACHINE_SOUNDCARD_H
32 # include <machine/soundcard.h>
33 #endif
34 #ifdef HAVE_SYS_SOUNDCARD_H
35 # include <sys/soundcard.h>
36 #endif
38 #define SOUND_DEV "/dev/dsp"
39 #define MIXER_DEV "/dev/mixer"
41 #ifdef SOUND_VERSION
42 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
43 #else
44 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
45 #endif
47 #define MAX_WAVOUTDRV (1)
48 #define MAX_WAVINDRV (1)
49 #define MAX_MCIWAVDRV (1)
51 typedef struct {
52 int unixdev;
53 int state;
54 DWORD bufsize;
55 WAVEOPENDESC waveDesc;
56 WORD wFlags;
57 PCMWAVEFORMAT Format;
58 LPWAVEHDR lpQueueHdr;
59 DWORD dwTotalPlayed;
60 } LINUX_WAVEOUT;
62 typedef struct {
63 int unixdev;
64 int state;
65 DWORD bufsize; /* OpenSound '/dev/dsp' give us that size */
66 WAVEOPENDESC waveDesc;
67 WORD wFlags;
68 PCMWAVEFORMAT Format;
69 LPWAVEHDR lpQueueHdr;
70 DWORD dwTotalRecorded;
71 } LINUX_WAVEIN;
73 typedef struct {
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;
81 WAVEHDR WaveHdr;
82 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
83 } LINUX_MCIWAVE;
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);
98 switch (wMsg) {
99 case WOM_OPEN:
100 case WOM_CLOSE:
101 case WOM_DONE:
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,
108 wMsg,
109 WOutDev[wDevID].waveDesc.dwInstance,
110 dwParam1,
111 dwParam2)) {
112 WARN(mciwave, "can't notify client !\n");
113 return MMSYSERR_NOERROR;
115 break;
117 case WIM_OPEN:
118 case WIM_CLOSE:
119 case WIM_DATA:
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;
129 break;
131 return 0;
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;
143 DWORD dwRet;
144 char str[128];
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;
156 else
157 return MCIERR_MUST_USE_SHAREABLE;
158 } else {
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",
170 lpstrElementName);
171 if ( lpstrElementName && (strlen(lpstrElementName) > 0)) {
172 strcpy(str, lpstrElementName);
173 CharUpper32A(str);
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;
181 else
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;
189 waveDesc.hWave = 0;
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) {
199 MMCKINFO mmckInfo;
200 MMCKINFO ckMainRIFF;
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,
205 ckMainRIFF.cksize);
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,
214 mmckInfo.cksize);
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,
223 mmckInfo.cksize);
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);
238 return 0;
241 /**************************************************************************
242 * WAVE_mciCue [internal]
245 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
248 FIXME
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
252 is the default.
254 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
255 are ignored
258 DWORD dwRet;
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;
289 return dwRet;
292 /**************************************************************************
293 * WAVE_mciClose [internal]
295 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
297 DWORD dwRet;
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);
308 else
309 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
311 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
313 return 0;
317 /**************************************************************************
318 * WAVE_mciPlay [internal]
320 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
322 int start, end;
323 LONG bufsize, count;
324 HGLOBAL16 hData;
325 LPWAVEHDR lpWaveHdr;
326 DWORD dwRet;
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) {
346 end = lpParms->dwTo;
347 TRACE(mciwave,"MCI_TO=%d \n", end);
349 #if 0
350 if (dwFlags & MCI_NOTIFY) {
351 TRACE(mciwave, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
352 switch(fork()) {
353 case -1:
354 WARN(mciwave, "Can't 'fork' process !\n");
355 break;
356 case 0:
357 break;
358 default:
359 TRACE(mciwave,"process started ! return to caller...\n");
360 return 0;
363 #endif
364 bufsize = 64000;
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));
372 while(TRUE) {
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);
385 GlobalFree16(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);
393 return 0;
397 /**************************************************************************
398 * WAVE_mciRecord [internal]
400 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
402 int start, end;
403 LONG bufsize;
404 HGLOBAL16 hData;
405 LPWAVEHDR lpWaveHdr;
406 DWORD dwRet;
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) {
426 end = lpParms->dwTo;
427 TRACE(mciwave,"MCI_TO=%d \n", end);
429 bufsize = 64000;
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");
439 while(TRUE) {
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);
451 GlobalFree16(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);
459 return 0;
463 /**************************************************************************
464 * WAVE_mciStop [internal]
466 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
468 DWORD dwRet;
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);
474 else
475 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
477 return dwRet;
481 /**************************************************************************
482 * WAVE_mciPause [internal]
484 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
486 DWORD dwRet;
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);
492 else
493 dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
495 return dwRet;
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;
506 return 0;
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");
523 break;
524 case MCI_FORMAT_BYTES:
525 TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
526 break;
527 case MCI_FORMAT_SAMPLES:
528 TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
529 break;
530 default:
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");
569 return 0;
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;
584 break;
585 case MCI_STATUS_LENGTH:
586 lpParms->dwReturn = 5555;
587 if (dwFlags & MCI_TRACK) {
588 lpParms->dwTrack = 1;
589 lpParms->dwReturn = 2222;
591 break;
592 case MCI_STATUS_MODE:
593 lpParms->dwReturn = MCI_MODE_STOP;
594 break;
595 case MCI_STATUS_MEDIA_PRESENT:
596 TRACE(mciwave,"MCI_STATUS_MEDIA_PRESENT !\n");
597 lpParms->dwReturn = TRUE;
598 break;
599 case MCI_STATUS_NUMBER_OF_TRACKS:
600 lpParms->dwReturn = 1;
601 break;
602 case MCI_STATUS_POSITION:
603 lpParms->dwReturn = 3333;
604 if (dwFlags & MCI_STATUS_START)
605 lpParms->dwItem = 1;
606 if (dwFlags & MCI_TRACK) {
607 lpParms->dwTrack = 1;
608 lpParms->dwReturn = 777;
610 break;
611 case MCI_STATUS_READY:
612 TRACE(mciwave,"MCI_STATUS_READY !\n");
613 lpParms->dwReturn = TRUE;
614 break;
615 case MCI_STATUS_TIME_FORMAT:
616 TRACE(mciwave,"MCI_STATUS_TIME_FORMAT !\n");
617 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
618 break;
619 case MCI_WAVE_INPUT:
620 TRACE(mciwave,"MCI_WAVE_INPUT !\n");
621 lpParms->dwReturn = 0;
622 break;
623 case MCI_WAVE_OUTPUT:
624 TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
625 lpParms->dwReturn = 0;
626 break;
627 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
628 TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
629 lpParms->dwReturn = 22050;
630 break;
631 case MCI_WAVE_STATUS_BITSPERSAMPLE:
632 TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
633 lpParms->dwReturn = 8;
634 break;
635 case MCI_WAVE_STATUS_BLOCKALIGN:
636 TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN !\n");
637 lpParms->dwReturn = 1;
638 break;
639 case MCI_WAVE_STATUS_CHANNELS:
640 TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS !\n");
641 lpParms->dwReturn = 1;
642 break;
643 case MCI_WAVE_STATUS_FORMATTAG:
644 TRACE(mciwave,"MCI_WAVE_FORMATTAG !\n");
645 lpParms->dwReturn = WAVE_FORMAT_PCM;
646 break;
647 case MCI_WAVE_STATUS_LEVEL:
648 TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
649 lpParms->dwReturn = 0xAAAA5555;
650 break;
651 case MCI_WAVE_STATUS_SAMPLESPERSEC:
652 TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
653 lpParms->dwReturn = 22050;
654 break;
655 default:
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);
665 return 0;
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;
680 break;
681 case MCI_GETDEVCAPS_HAS_AUDIO:
682 lpParms->dwReturn = TRUE;
683 break;
684 case MCI_GETDEVCAPS_HAS_VIDEO:
685 lpParms->dwReturn = FALSE;
686 break;
687 case MCI_GETDEVCAPS_DEVICE_TYPE:
688 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
689 break;
690 case MCI_GETDEVCAPS_USES_FILES:
691 lpParms->dwReturn = TRUE;
692 break;
693 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
694 lpParms->dwReturn = TRUE;
695 break;
696 case MCI_GETDEVCAPS_CAN_EJECT:
697 lpParms->dwReturn = FALSE;
698 break;
699 case MCI_GETDEVCAPS_CAN_PLAY:
700 lpParms->dwReturn = TRUE;
701 break;
702 case MCI_GETDEVCAPS_CAN_SAVE:
703 lpParms->dwReturn = TRUE;
704 break;
705 case MCI_WAVE_GETDEVCAPS_INPUTS:
706 lpParms->dwReturn = 1;
707 break;
708 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
709 lpParms->dwReturn = 1;
710 break;
711 default:
712 return MCIERR_UNRECOGNIZED_COMMAND;
715 return 0;
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;
726 switch(dwFlags) {
727 case MCI_INFO_PRODUCT:
728 lpParms->lpstrReturn = "Open Sound System 0.5";
729 break;
730 case MCI_INFO_FILE:
731 lpParms->lpstrReturn =
732 (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
733 break;
734 case MCI_WAVE_INPUT:
735 lpParms->lpstrReturn = "Open Sound System 0.5";
736 break;
737 case MCI_WAVE_OUTPUT:
738 lpParms->lpstrReturn = "Open Sound System 0.5";
739 break;
740 default:
741 return MCIERR_UNRECOGNIZED_COMMAND;
743 if (lpParms->lpstrReturn != NULL)
744 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
745 else
746 lpParms->dwRetSize = 0;
747 return 0;
751 /*-----------------------------------------------------------------------*/
754 /**************************************************************************
755 * wodGetDevCaps [internal]
757 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
759 int audio;
760 int smplrate;
761 int samplesize = 16;
762 int dsp_stereo = 1;
763 int bytespersmpl;
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 ;
770 #ifdef EMULATE_SB16
771 lpCaps->wMid = 0x0002;
772 lpCaps->wPid = 0x0104;
773 strcpy(lpCaps->szPname, "SB16 Wave Out");
774 #else
775 lpCaps->wMid = 0x00FF; /* Manufac ID */
776 lpCaps->wPid = 0x0001; /* Product ID */
777 strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
778 #endif
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;
789 smplrate = 44100;
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;
800 smplrate = 22050;
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;
811 smplrate = 11025;
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;
822 close(audio);
823 TRACE(mciwave, "dwFormats = %08lX\n", lpCaps->dwFormats);
824 return MMSYSERR_NOERROR;
828 /**************************************************************************
829 * wodOpen [internal]
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);
848 if (audio == -1) {
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) {
854 if (abuf_size == -1)
855 WARN(mciwave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
856 else
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) {
862 case DCB_NULL:
863 TRACE(mciwave, "CALLBACK_NULL !\n");
864 break;
865 case DCB_WINDOW:
866 TRACE(mciwave, "CALLBACK_WINDOW !\n");
867 break;
868 case DCB_TASK:
869 TRACE(mciwave, "CALLBACK_TASK !\n");
870 break;
871 case DCB_FUNCTION:
872 TRACE(mciwave, "CALLBACK_FUNCTION !\n");
873 break;
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)
962 int count;
963 LPSTR lpData;
964 LPWAVEHDR xwavehdr;
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);
1001 } else {
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)
1088 int time;
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",
1096 lpTime->wType);
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) {
1106 case TIME_BYTES:
1107 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1108 TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1109 break;
1110 case TIME_SAMPLES:
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);
1118 break;
1119 case TIME_SMPTE:
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;
1130 TRACE(mciwave,
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);
1134 break;
1135 default:
1136 FIXME(mciwave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
1137 lpTime->wType = TIME_MS;
1138 case 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);
1142 break;
1144 return MMSYSERR_NOERROR;
1147 /**************************************************************************
1148 * wodGetVolume [internal]
1150 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1152 int mixer;
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;
1164 close(mixer);
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)
1178 int mixer;
1179 int volume;
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;
1191 close(mixer);
1192 return MMSYSERR_NOERROR;
1195 /**************************************************************************
1196 * wodMessage [sample driver]
1198 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1199 DWORD dwParam1, DWORD dwParam2)
1201 int audio;
1202 TRACE(mciwave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1203 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1204 switch(wMsg) {
1205 case WODM_OPEN:
1206 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1207 case WODM_CLOSE:
1208 return wodClose(wDevID);
1209 case WODM_WRITE:
1210 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1211 case WODM_PAUSE:
1212 return MMSYSERR_NOTSUPPORTED;
1213 case WODM_STOP:
1214 return MMSYSERR_NOTSUPPORTED;
1215 case WODM_GETPOS:
1216 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1217 case WODM_BREAKLOOP:
1218 return MMSYSERR_NOTSUPPORTED;
1219 case WODM_PREPARE:
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);
1228 if (audio == -1)
1229 if (errno == EBUSY)
1230 return 1;
1231 else
1232 return 0;
1233 close (audio);
1234 return 1;
1235 case WODM_GETPITCH:
1236 return MMSYSERR_NOTSUPPORTED;
1237 case WODM_SETPITCH:
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);
1247 case WODM_RESTART:
1248 return wodRestart(wDevID);
1249 case WODM_RESET:
1250 return wodReset(wDevID);
1251 default:
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 ;
1272 #ifdef EMULATE_SB16
1273 lpCaps->wMid = 0x0002;
1274 lpCaps->wPid = 0x0004;
1275 strcpy(lpCaps->szPname, "SB16 Wave In");
1276 #else
1277 lpCaps->wMid = 0x00FF; /* Manufac ID */
1278 lpCaps->wPid = 0x0001; /* Product ID */
1279 strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
1280 #endif
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;
1284 smplrate = 44100;
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;
1295 smplrate = 22050;
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;
1306 smplrate = 11025;
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;
1317 close(audio);
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);
1343 if (audio == -1) {
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");
1351 else
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) {
1357 case DCB_NULL:
1358 TRACE(mciwave,"CALLBACK_NULL!\n");
1359 break;
1360 case DCB_WINDOW:
1361 TRACE(mciwave,"CALLBACK_WINDOW!\n");
1362 break;
1363 case DCB_TASK:
1364 TRACE(mciwave,"CALLBACK_TASK!\n");
1365 break;
1366 case DCB_FUNCTION:
1367 TRACE(mciwave,"CALLBACK_FUNCTION!\n");
1368 break;
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)
1445 int count = 1;
1446 LPWAVEHDR lpWIHdr;
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;
1467 } else {
1468 lpWIHdr = WInDev[wDevID].lpQueueHdr;
1469 while (lpWIHdr->lpNext != NULL) {
1470 lpWIHdr = lpWIHdr->lpNext;
1471 count++;
1473 lpWIHdr->lpNext = lpWaveHdr;
1474 lpWaveHdr->lpNext = NULL;
1475 count++;
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)
1524 int count = 1;
1525 int bytesRead;
1526 LPWAVEHDR lpWIHdr;
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);
1546 fflush(stddeb);
1547 bytesRead = read (WInDev[wDevID].unixdev,
1548 lpWIHdr->lpData,
1549 lpWIHdr->dwBufferLength);
1550 if (bytesRead==-1)
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;
1566 count++;
1568 TRACE(mciwave,"end of recording !\n");
1569 fflush(stddeb);
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)
1604 int time;
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",
1613 lpTime->wType);
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);
1622 fflush(stddeb);
1623 switch(lpTime->wType) {
1624 case TIME_BYTES:
1625 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1626 TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1627 break;
1628 case TIME_SAMPLES:
1629 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1630 WInDev[wDevID].Format.wBitsPerSample;
1631 TRACE(mciwave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
1632 break;
1633 case TIME_SMPTE:
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);
1647 break;
1648 default:
1649 FIXME(mciwave, "format not supported ! use TIME_MS !\n");
1650 lpTime->wType = TIME_MS;
1651 case 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);
1655 break;
1657 return MMSYSERR_NOERROR;
1660 /**************************************************************************
1661 * widMessage [sample driver]
1663 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1664 DWORD dwParam1, DWORD dwParam2)
1666 int audio;
1667 TRACE(mciwave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1668 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1669 switch(wMsg) {
1670 case WIDM_OPEN:
1671 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1672 case WIDM_CLOSE:
1673 return widClose(wDevID);
1674 case WIDM_ADDBUFFER:
1675 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1676 case WIDM_PREPARE:
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);
1685 if (audio == -1)
1686 if (errno == EBUSY)
1687 return 1;
1688 else
1689 return 0;
1690 close (audio);
1691 return 1;
1692 case WIDM_GETPOS:
1693 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1694 case WIDM_RESET:
1695 return widReset(wDevID);
1696 case WIDM_START:
1697 return widStart(wDevID);
1698 case WIDM_PAUSE:
1699 return widStop(wDevID);
1700 case WIDM_STOP:
1701 return widStop(wDevID);
1702 default:
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);
1717 switch(wMsg) {
1718 case DRV_LOAD:
1719 return 1;
1720 case DRV_FREE:
1721 return 1;
1722 case DRV_OPEN:
1723 return 1;
1724 case DRV_CLOSE:
1725 return 1;
1726 case DRV_ENABLE:
1727 return 1;
1728 case DRV_DISABLE:
1729 return 1;
1730 case DRV_QUERYCONFIGURE:
1731 return 1;
1732 case DRV_CONFIGURE:
1733 MessageBox16(0, "Sample MultiMedia Linux Driver !",
1734 "MMLinux Driver", MB_OK);
1735 return 1;
1736 case DRV_INSTALL:
1737 return DRVCNF_RESTART;
1738 case DRV_REMOVE:
1739 return DRVCNF_RESTART;
1740 case MCI_OPEN_DRIVER:
1741 case MCI_OPEN:
1742 return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1743 case MCI_CUE:
1744 return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1745 case MCI_CLOSE_DRIVER:
1746 case MCI_CLOSE:
1747 return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1748 case MCI_PLAY:
1749 return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1750 case MCI_RECORD:
1751 return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1752 case MCI_STOP:
1753 return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1754 case MCI_SET:
1755 return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1756 case MCI_PAUSE:
1757 return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1758 case MCI_RESUME:
1759 return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1760 case MCI_STATUS:
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));
1764 case MCI_INFO:
1765 return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1767 case MCI_LOAD:
1768 return MMSYSERR_NOTSUPPORTED;
1769 case MCI_SAVE:
1770 return MMSYSERR_NOTSUPPORTED;
1771 case MCI_SEEK:
1772 return MMSYSERR_NOTSUPPORTED;
1773 case MCI_FREEZE:
1774 return MMSYSERR_NOTSUPPORTED;
1775 case MCI_PUT:
1776 return MMSYSERR_NOTSUPPORTED;
1777 case MCI_REALIZE:
1778 return MMSYSERR_NOTSUPPORTED;
1779 case MCI_UNFREEZE:
1780 return MMSYSERR_NOTSUPPORTED;
1781 case MCI_UPDATE:
1782 return MMSYSERR_NOTSUPPORTED;
1783 case MCI_WHERE:
1784 return MMSYSERR_NOTSUPPORTED;
1785 case MCI_WINDOW:
1786 return MMSYSERR_NOTSUPPORTED;
1787 case MCI_STEP:
1788 return MMSYSERR_NOTSUPPORTED;
1789 case MCI_SPIN:
1790 return MMSYSERR_NOTSUPPORTED;
1791 case MCI_ESCAPE:
1792 return MMSYSERR_NOTSUPPORTED;
1793 case MCI_COPY:
1794 return MMSYSERR_NOTSUPPORTED;
1795 case MCI_CUT:
1796 return MMSYSERR_NOTSUPPORTED;
1797 case MCI_DELETE:
1798 return MMSYSERR_NOTSUPPORTED;
1799 case MCI_PASTE:
1800 return MMSYSERR_NOTSUPPORTED;
1802 default:
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 */