Small fixes to get the default language to a sensible value.
[wine/multimedia.git] / multimedia / audio.c
blob2ca9955661d1fc215a640920df78d10c93f10457
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
5 * Copyright 1994 Martin Ayotte
6 */
7 /*
8 * FIXME:
9 * - record/play should and must be done asynchronous
10 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
13 #define EMULATE_SB16
15 #define DEBUG_MCIWAVE
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sys/ioctl.h>
22 #include "windows.h"
23 #include "user.h"
24 #include "driver.h"
25 #include "mmsystem.h"
26 #include "heap.h"
27 #include "ldt.h"
28 #include "debug.h"
30 #ifdef HAVE_OSS
32 #ifdef HAVE_MACHINE_SOUNDCARD_H
33 # include <machine/soundcard.h>
34 #endif
35 #ifdef HAVE_SYS_SOUNDCARD_H
36 # include <sys/soundcard.h>
37 #endif
39 #define SOUND_DEV "/dev/dsp"
40 #define MIXER_DEV "/dev/mixer"
42 #ifdef SOUND_VERSION
43 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
44 #else
45 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
46 #endif
48 #define MAX_WAVOUTDRV (1)
49 #define MAX_WAVINDRV (1)
50 #define MAX_MCIWAVDRV (1)
52 typedef struct {
53 int unixdev;
54 int state;
55 DWORD bufsize;
56 WAVEOPENDESC waveDesc;
57 WORD wFlags;
58 PCMWAVEFORMAT Format;
59 LPWAVEHDR lpQueueHdr;
60 DWORD dwTotalPlayed;
61 } WINE_WAVEOUT;
63 typedef struct {
64 int unixdev;
65 int state;
66 DWORD bufsize; /* OpenSound '/dev/dsp' give us that size */
67 WAVEOPENDESC waveDesc;
68 WORD wFlags;
69 PCMWAVEFORMAT Format;
70 LPWAVEHDR lpQueueHdr;
71 DWORD dwTotalRecorded;
72 } WINE_WAVEIN;
74 typedef struct {
75 int nUseCount; /* Incremented for each shared open */
76 BOOL16 fShareable; /* TRUE if first open was shareable */
77 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
78 HANDLE16 hCallback; /* Callback handle for pending notification */
79 HMMIO32 hFile; /* mmio file handle open as Element */
80 MCI_WAVE_OPEN_PARMS16 openParms;
81 PCMWAVEFORMAT WaveFormat;
82 WAVEHDR WaveHdr;
83 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
84 } WINE_MCIWAVE;
86 static WINE_WAVEOUT WOutDev[MAX_WAVOUTDRV];
87 static WINE_WAVEIN WInDev[MAX_WAVOUTDRV];
88 static WINE_MCIWAVE MCIWavDev[MAX_MCIWAVDRV];
90 /**************************************************************************
91 * WAVE_NotifyClient [internal]
93 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg,
94 DWORD dwParam1, DWORD dwParam2)
96 TRACE(mciwave,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
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, void* lp, BOOL32 is32)
140 LPPCMWAVEFORMAT lpWaveFormat;
141 WAVEOPENDESC waveDesc;
142 DWORD dwRet;
143 DWORD dwDeviceID;
145 TRACE(mciwave,"(%04X, %08lX, %p)\n", wDevID, dwFlags, lp);
146 if (lp == NULL) return MCIERR_INTERNAL;
148 if (is32) dwDeviceID = ((LPMCI_OPEN_PARMS32A)lp)->wDeviceID;
149 else dwDeviceID = ((LPMCI_OPEN_PARMS16)lp)->wDeviceID;
151 if (MCIWavDev[wDevID].nUseCount > 0) {
152 /* The driver already open on this channel */
153 /* If the driver was opened shareable before and this open specifies */
154 /* shareable then increment the use count */
155 if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
156 ++MCIWavDev[wDevID].nUseCount;
157 else
158 return MCIERR_MUST_USE_SHAREABLE;
159 } else {
160 MCIWavDev[wDevID].nUseCount = 1;
161 MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
164 MCIWavDev[wDevID].fInput = FALSE;
166 TRACE(mciwave,"wDevID=%04X\n", wDevID);
167 TRACE(mciwave,"before OPEN_ELEMENT\n");
168 if (dwFlags & MCI_OPEN_ELEMENT) {
169 LPSTR lpstrElementName;
171 if (is32) lpstrElementName = ((LPMCI_WAVE_OPEN_PARMS32A)lp)->lpstrElementName;
172 else lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(((LPMCI_WAVE_OPEN_PARMS16)lp)->lpstrElementName);
174 TRACE(mciwave,"MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
175 if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
176 MCIWavDev[wDevID].hFile = mmioOpen32A(lpstrElementName, NULL,
177 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
178 if (MCIWavDev[wDevID].hFile == 0) {
179 WARN(mciwave, "can't find file='%s' !\n", lpstrElementName);
180 return MCIERR_FILE_NOT_FOUND;
183 else
184 MCIWavDev[wDevID].hFile = 0;
186 TRACE(mciwave,"hFile=%u\n", MCIWavDev[wDevID].hFile);
187 memcpy(&MCIWavDev[wDevID].openParms, lp, sizeof(MCI_WAVE_OPEN_PARMS16));
188 MCIWavDev[wDevID].wNotifyDeviceID = dwDeviceID;
189 lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
191 waveDesc.hWave = 0;
193 lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
194 lpWaveFormat->wBitsPerSample = 8;
195 lpWaveFormat->wf.nChannels = 1;
196 lpWaveFormat->wf.nSamplesPerSec = 11025;
197 lpWaveFormat->wf.nAvgBytesPerSec = 11025;
198 lpWaveFormat->wf.nBlockAlign = 1;
200 if (MCIWavDev[wDevID].hFile != 0) {
201 MMCKINFO mmckInfo;
202 MMCKINFO ckMainRIFF;
203 if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0)
204 return MCIERR_INTERNAL;
205 TRACE(mciwave, "ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
206 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
207 ckMainRIFF.cksize);
208 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
209 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
210 return MCIERR_INTERNAL;
211 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
212 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
213 return MCIERR_INTERNAL;
214 TRACE(mciwave, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
215 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
216 mmckInfo.cksize);
217 if (mmioRead32(MCIWavDev[wDevID].hFile, (HPSTR) lpWaveFormat,
218 (long) sizeof(PCMWAVEFORMAT)) != (long) sizeof(PCMWAVEFORMAT))
219 return MCIERR_INTERNAL;
220 mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
221 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
222 return MCIERR_INTERNAL;
223 TRACE(mciwave,"Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
224 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
225 mmckInfo.cksize);
226 TRACE(mciwave, "nChannels=%d nSamplesPerSec=%ld\n",
227 lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
228 lpWaveFormat->wBitsPerSample = 0;
230 lpWaveFormat->wf.nAvgBytesPerSec =
231 lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
232 waveDesc.lpFormat = (LPWAVEFORMAT)lpWaveFormat;
235 By default the device will be opened for output, the MCI_CUE function is there to
236 change from output to input and back
239 dwRet=wodMessage(wDevID,WODM_OPEN,0,(DWORD)&waveDesc,CALLBACK_NULL);
240 return 0;
243 /**************************************************************************
244 * WAVE_mciCue [internal]
247 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
250 FIXME
252 This routine is far from complete. At the moment only a check is done on the
253 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
254 is the default.
256 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
257 are ignored
260 DWORD dwRet;
261 WAVEOPENDESC waveDesc;
263 TRACE(mciwave,"(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
265 /* always close elements ? */
267 if (MCIWavDev[wDevID].hFile != 0) {
268 mmioClose32(MCIWavDev[wDevID].hFile, 0);
269 MCIWavDev[wDevID].hFile = 0;
272 dwRet = MMSYSERR_NOERROR; /* assume success */
273 if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
274 /* FIXME this is just a hack WOutDev should be hidden here */
275 memcpy(&waveDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
277 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
278 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
279 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
280 MCIWavDev[wDevID].fInput = TRUE;
282 else if (MCIWavDev[wDevID].fInput) {
283 /* FIXME this is just a hack WInDev should be hidden here */
284 memcpy(&waveDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
286 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
287 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
288 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
289 MCIWavDev[wDevID].fInput = FALSE;
291 return dwRet;
294 /**************************************************************************
295 * WAVE_mciClose [internal]
297 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
299 DWORD dwRet;
301 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
302 MCIWavDev[wDevID].nUseCount--;
303 if (MCIWavDev[wDevID].nUseCount == 0) {
304 if (MCIWavDev[wDevID].hFile != 0) {
305 mmioClose32(MCIWavDev[wDevID].hFile, 0);
306 MCIWavDev[wDevID].hFile = 0;
308 if (MCIWavDev[wDevID].fInput)
309 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
310 else
311 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
313 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
315 return 0;
319 /**************************************************************************
320 * WAVE_mciPlay [internal]
322 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
324 int start, end;
325 LONG bufsize, count;
326 HGLOBAL16 hData;
327 LPWAVEHDR lpWaveHdr;
328 DWORD dwRet;
330 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
332 if (MCIWavDev[wDevID].fInput) {
333 WARN(mciwave, "cannot play on input device\n");
334 return MCIERR_NONAPPLICABLE_FUNCTION;
337 if (MCIWavDev[wDevID].hFile == 0) {
338 WARN(mciwave, "can't find file='%08lx' !\n",
339 MCIWavDev[wDevID].openParms.lpstrElementName);
340 return MCIERR_FILE_NOT_FOUND;
342 start = 1; end = 99999;
343 if (dwFlags & MCI_FROM) {
344 start = lpParms->dwFrom;
345 TRACE(mciwave, "MCI_FROM=%d \n", start);
347 if (dwFlags & MCI_TO) {
348 end = lpParms->dwTo;
349 TRACE(mciwave,"MCI_TO=%d \n", end);
351 #if 0
352 if (dwFlags & MCI_NOTIFY) {
353 TRACE(mciwave, "MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
354 switch(fork()) {
355 case -1:
356 WARN(mciwave, "Can't 'fork' process !\n");
357 break;
358 case 0:
359 break;
360 default:
361 TRACE(mciwave,"process started ! return to caller...\n");
362 return 0;
365 #endif
366 bufsize = 64000;
367 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
368 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
369 lpWaveHdr->lpData = (LPSTR) GlobalLock16(hData);
370 lpWaveHdr->dwUser = 0L;
371 lpWaveHdr->dwFlags = 0L;
372 lpWaveHdr->dwLoops = 0L;
373 dwRet=wodMessage(wDevID,WODM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
374 while(TRUE) {
375 count = mmioRead32(MCIWavDev[wDevID].hFile, lpWaveHdr->lpData, bufsize);
376 TRACE(mciwave,"mmioRead bufsize=%ld count=%ld\n", bufsize, count);
377 if (count < 1) break;
378 lpWaveHdr->dwBufferLength = count;
379 /* lpWaveHdr->dwBytesRecorded = count; */
380 TRACE(mciwave,"before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
381 lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
382 dwRet=wodMessage(wDevID,WODM_WRITE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
384 dwRet = wodMessage(wDevID,WODM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
385 if (lpWaveHdr->lpData != NULL) {
386 GlobalUnlock16(hData);
387 GlobalFree16(hData);
388 lpWaveHdr->lpData = NULL;
390 if (dwFlags & MCI_NOTIFY) {
391 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
392 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
393 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
395 return 0;
399 /**************************************************************************
400 * WAVE_mciRecord [internal]
402 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
404 int start, end;
405 LONG bufsize;
406 HGLOBAL16 hData;
407 LPWAVEHDR lpWaveHdr;
408 DWORD dwRet;
410 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
412 if (!MCIWavDev[wDevID].fInput) {
413 WARN(mciwave, "cannot record on output device\n");
414 return MCIERR_NONAPPLICABLE_FUNCTION;
417 if (MCIWavDev[wDevID].hFile == 0) {
418 WARN(mciwave, "can't find file='%08lx' !\n",
419 MCIWavDev[wDevID].openParms.lpstrElementName);
420 return MCIERR_FILE_NOT_FOUND;
422 start = 1; end = 99999;
423 if (dwFlags & MCI_FROM) {
424 start = lpParms->dwFrom;
425 TRACE(mciwave, "MCI_FROM=%d \n", start);
427 if (dwFlags & MCI_TO) {
428 end = lpParms->dwTo;
429 TRACE(mciwave,"MCI_TO=%d \n", end);
431 bufsize = 64000;
432 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
433 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
434 lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
435 lpWaveHdr->dwBufferLength = bufsize;
436 lpWaveHdr->dwUser = 0L;
437 lpWaveHdr->dwFlags = 0L;
438 lpWaveHdr->dwLoops = 0L;
439 dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
440 TRACE(mciwave,"after WIDM_PREPARE \n");
441 while(TRUE) {
442 lpWaveHdr->dwBytesRecorded = 0;
443 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
444 TRACE(mciwave, "after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
445 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
446 if (lpWaveHdr->dwBytesRecorded == 0) break;
448 TRACE(mciwave,"before WIDM_UNPREPARE \n");
449 dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
450 TRACE(mciwave,"after WIDM_UNPREPARE \n");
451 if (lpWaveHdr->lpData != NULL) {
452 GlobalUnlock16(hData);
453 GlobalFree16(hData);
454 lpWaveHdr->lpData = NULL;
456 if (dwFlags & MCI_NOTIFY) {
457 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
458 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
459 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
461 return 0;
465 /**************************************************************************
466 * WAVE_mciStop [internal]
468 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
470 DWORD dwRet;
472 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
473 if (lpParms == NULL) return MCIERR_INTERNAL;
474 if (MCIWavDev[wDevID].fInput)
475 dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
476 else
477 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
479 return dwRet;
483 /**************************************************************************
484 * WAVE_mciPause [internal]
486 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
488 DWORD dwRet;
490 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
491 if (lpParms == NULL) return MCIERR_INTERNAL;
492 if (MCIWavDev[wDevID].fInput)
493 dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
494 else
495 dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
497 return dwRet;
501 /**************************************************************************
502 * WAVE_mciResume [internal]
504 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
506 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
507 if (lpParms == NULL) return MCIERR_INTERNAL;
508 return 0;
512 /**************************************************************************
513 * WAVE_mciSet [internal]
515 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
517 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
518 if (lpParms == NULL) return MCIERR_INTERNAL;
519 TRACE(mciwave, "dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
520 TRACE(mciwave, "dwAudio=%08lX\n", lpParms->dwAudio);
521 if (dwFlags & MCI_SET_TIME_FORMAT) {
522 switch (lpParms->dwTimeFormat) {
523 case MCI_FORMAT_MILLISECONDS:
524 TRACE(mciwave, "MCI_FORMAT_MILLISECONDS !\n");
525 break;
526 case MCI_FORMAT_BYTES:
527 TRACE(mciwave, "MCI_FORMAT_BYTES !\n");
528 break;
529 case MCI_FORMAT_SAMPLES:
530 TRACE(mciwave, "MCI_FORMAT_SAMPLES !\n");
531 break;
532 default:
533 WARN(mciwave, "bad time format !\n");
534 return MCIERR_BAD_TIME_FORMAT;
537 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
538 if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
539 if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
540 if (dwFlags & MCI_SET_AUDIO)
541 TRACE(mciwave,"MCI_SET_AUDIO !\n");
542 if (dwFlags && MCI_SET_ON) {
543 TRACE(mciwave,"MCI_SET_ON !\n");
544 if (dwFlags && MCI_SET_AUDIO_LEFT)
545 TRACE(mciwave,"MCI_SET_AUDIO_LEFT !\n");
546 if (dwFlags && MCI_SET_AUDIO_RIGHT)
547 TRACE(mciwave,"MCI_SET_AUDIO_RIGHT !\n");
549 if (dwFlags & MCI_SET_OFF)
550 TRACE(mciwave,"MCI_SET_OFF !\n");
551 if (dwFlags & MCI_WAVE_INPUT)
552 TRACE(mciwave,"MCI_WAVE_INPUT !\n");
553 if (dwFlags & MCI_WAVE_OUTPUT)
554 TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
555 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
556 TRACE(mciwave,"MCI_WAVE_SET_ANYINPUT !\n");
557 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
558 TRACE(mciwave,"MCI_WAVE_SET_ANYOUTPUT !\n");
559 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
560 TRACE(mciwave, "MCI_WAVE_SET_AVGBYTESPERSEC !\n");
561 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
562 TRACE(mciwave, "MCI_WAVE_SET_BITSPERSAMPLE !\n");
563 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
564 TRACE(mciwave,"MCI_WAVE_SET_BLOCKALIGN !\n");
565 if (dwFlags & MCI_WAVE_SET_CHANNELS)
566 TRACE(mciwave,"MCI_WAVE_SET_CHANNELS !\n");
567 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
568 TRACE(mciwave,"MCI_WAVE_SET_FORMATTAG !\n");
569 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
570 TRACE(mciwave, "MCI_WAVE_SET_SAMPLESPERSEC !\n");
571 return 0;
575 /**************************************************************************
576 * WAVE_mciStatus [internal]
578 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
580 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
581 if (lpParms == NULL) return MCIERR_INTERNAL;
582 if (dwFlags & MCI_STATUS_ITEM) {
583 switch(lpParms->dwItem) {
584 case MCI_STATUS_CURRENT_TRACK:
585 lpParms->dwReturn = 1;
586 break;
587 case MCI_STATUS_LENGTH:
588 lpParms->dwReturn = 5555;
589 if (dwFlags & MCI_TRACK) {
590 lpParms->dwTrack = 1;
591 lpParms->dwReturn = 2222;
593 break;
594 case MCI_STATUS_MODE:
595 lpParms->dwReturn = MCI_MODE_STOP;
596 break;
597 case MCI_STATUS_MEDIA_PRESENT:
598 TRACE(mciwave,"MCI_STATUS_MEDIA_PRESENT !\n");
599 lpParms->dwReturn = TRUE;
600 break;
601 case MCI_STATUS_NUMBER_OF_TRACKS:
602 lpParms->dwReturn = 1;
603 break;
604 case MCI_STATUS_POSITION:
605 lpParms->dwReturn = 3333;
606 if (dwFlags & MCI_STATUS_START)
607 lpParms->dwItem = 1;
608 if (dwFlags & MCI_TRACK) {
609 lpParms->dwTrack = 1;
610 lpParms->dwReturn = 777;
612 break;
613 case MCI_STATUS_READY:
614 TRACE(mciwave,"MCI_STATUS_READY !\n");
615 lpParms->dwReturn = TRUE;
616 break;
617 case MCI_STATUS_TIME_FORMAT:
618 TRACE(mciwave,"MCI_STATUS_TIME_FORMAT !\n");
619 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
620 break;
621 case MCI_WAVE_INPUT:
622 TRACE(mciwave,"MCI_WAVE_INPUT !\n");
623 lpParms->dwReturn = 0;
624 break;
625 case MCI_WAVE_OUTPUT:
626 TRACE(mciwave,"MCI_WAVE_OUTPUT !\n");
627 lpParms->dwReturn = 0;
628 break;
629 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
630 TRACE(mciwave,"MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
631 lpParms->dwReturn = 22050;
632 break;
633 case MCI_WAVE_STATUS_BITSPERSAMPLE:
634 TRACE(mciwave,"MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
635 lpParms->dwReturn = 8;
636 break;
637 case MCI_WAVE_STATUS_BLOCKALIGN:
638 TRACE(mciwave,"MCI_WAVE_STATUS_BLOCKALIGN !\n");
639 lpParms->dwReturn = 1;
640 break;
641 case MCI_WAVE_STATUS_CHANNELS:
642 TRACE(mciwave,"MCI_WAVE_STATUS_CHANNELS !\n");
643 lpParms->dwReturn = 1;
644 break;
645 case MCI_WAVE_STATUS_FORMATTAG:
646 TRACE(mciwave,"MCI_WAVE_FORMATTAG !\n");
647 lpParms->dwReturn = WAVE_FORMAT_PCM;
648 break;
649 case MCI_WAVE_STATUS_LEVEL:
650 TRACE(mciwave,"MCI_WAVE_STATUS_LEVEL !\n");
651 lpParms->dwReturn = 0xAAAA5555;
652 break;
653 case MCI_WAVE_STATUS_SAMPLESPERSEC:
654 TRACE(mciwave,"MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
655 lpParms->dwReturn = 22050;
656 break;
657 default:
658 WARN(mciwave,"unknown command %08lX !\n", lpParms->dwItem);
659 return MCIERR_UNRECOGNIZED_COMMAND;
662 if (dwFlags & MCI_NOTIFY) {
663 TRACE(mciwave,"MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
664 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
665 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
667 return 0;
670 /**************************************************************************
671 * WAVE_mciGetDevCaps [internal]
673 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
674 LPMCI_GETDEVCAPS_PARMS lpParms)
676 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
677 if (lpParms == NULL) return MCIERR_INTERNAL;
678 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
679 switch(lpParms->dwItem) {
680 case MCI_GETDEVCAPS_CAN_RECORD:
681 lpParms->dwReturn = TRUE;
682 break;
683 case MCI_GETDEVCAPS_HAS_AUDIO:
684 lpParms->dwReturn = TRUE;
685 break;
686 case MCI_GETDEVCAPS_HAS_VIDEO:
687 lpParms->dwReturn = FALSE;
688 break;
689 case MCI_GETDEVCAPS_DEVICE_TYPE:
690 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
691 break;
692 case MCI_GETDEVCAPS_USES_FILES:
693 lpParms->dwReturn = TRUE;
694 break;
695 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
696 lpParms->dwReturn = TRUE;
697 break;
698 case MCI_GETDEVCAPS_CAN_EJECT:
699 lpParms->dwReturn = FALSE;
700 break;
701 case MCI_GETDEVCAPS_CAN_PLAY:
702 lpParms->dwReturn = TRUE;
703 break;
704 case MCI_GETDEVCAPS_CAN_SAVE:
705 lpParms->dwReturn = TRUE;
706 break;
707 case MCI_WAVE_GETDEVCAPS_INPUTS:
708 lpParms->dwReturn = 1;
709 break;
710 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
711 lpParms->dwReturn = 1;
712 break;
713 default:
714 return MCIERR_UNRECOGNIZED_COMMAND;
717 return 0;
720 /**************************************************************************
721 * WAVE_mciInfo [internal]
723 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
725 TRACE(mciwave, "(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
726 if (lpParms == NULL) return MCIERR_INTERNAL;
727 lpParms->lpstrReturn = NULL;
728 switch(dwFlags) {
729 case MCI_INFO_PRODUCT:
730 lpParms->lpstrReturn = "Open Sound System 0.5";
731 break;
732 case MCI_INFO_FILE:
733 lpParms->lpstrReturn =
734 (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
735 break;
736 case MCI_WAVE_INPUT:
737 lpParms->lpstrReturn = "Open Sound System 0.5";
738 break;
739 case MCI_WAVE_OUTPUT:
740 lpParms->lpstrReturn = "Open Sound System 0.5";
741 break;
742 default:
743 return MCIERR_UNRECOGNIZED_COMMAND;
745 if (lpParms->lpstrReturn != NULL)
746 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
747 else
748 lpParms->dwRetSize = 0;
749 return 0;
753 /*-----------------------------------------------------------------------*/
756 /**************************************************************************
757 * wodGetDevCaps [internal]
759 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
761 int audio;
762 int smplrate;
763 int samplesize = 16;
764 int dsp_stereo = 1;
765 int bytespersmpl;
767 TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
768 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
769 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
770 audio = open (SOUND_DEV, O_WRONLY, 0);
771 if (audio == -1) return MMSYSERR_ALLOCATED ;
772 #ifdef EMULATE_SB16
773 lpCaps->wMid = 0x0002;
774 lpCaps->wPid = 0x0104;
775 strcpy(lpCaps->szPname, "SB16 Wave Out");
776 #else
777 lpCaps->wMid = 0x00FF; /* Manufac ID */
778 lpCaps->wPid = 0x0001; /* Product ID */
779 strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
780 #endif
781 lpCaps->vDriverVersion = 0x0100;
782 lpCaps->dwFormats = 0x00000000;
783 lpCaps->dwSupport = WAVECAPS_VOLUME;
785 /* First bytespersampl, then stereo */
786 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
788 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
789 if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
791 smplrate = 44100;
792 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
793 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
794 if (lpCaps->wChannels > 1)
795 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
796 if (bytespersmpl > 1) {
797 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
798 if (lpCaps->wChannels > 1)
799 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
802 smplrate = 22050;
803 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
804 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
805 if (lpCaps->wChannels > 1)
806 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
807 if (bytespersmpl > 1) {
808 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
809 if (lpCaps->wChannels > 1)
810 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
813 smplrate = 11025;
814 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
815 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
816 if (lpCaps->wChannels > 1)
817 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
818 if (bytespersmpl > 1) {
819 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
820 if (lpCaps->wChannels > 1)
821 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
824 close(audio);
825 TRACE(mciwave, "dwFormats = %08lX\n", lpCaps->dwFormats);
826 return MMSYSERR_NOERROR;
830 /**************************************************************************
831 * wodOpen [internal]
833 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
835 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
836 LPWAVEFORMAT lpFormat;
838 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
839 if (lpDesc == NULL) {
840 WARN(mciwave, "Invalid Parameter !\n");
841 return MMSYSERR_INVALPARAM;
843 if (wDevID >= MAX_WAVOUTDRV) {
844 TRACE(mciwave,"MAX_WAVOUTDRV reached !\n");
845 return MMSYSERR_ALLOCATED;
847 WOutDev[wDevID].unixdev = 0;
848 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
849 audio = open (SOUND_DEV, O_WRONLY, 0);
850 if (audio == -1) {
851 WARN(mciwave, "can't open !\n");
852 return MMSYSERR_ALLOCATED ;
854 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
855 if (abuf_size < 1024 || abuf_size > 65536) {
856 if (abuf_size == -1)
857 WARN(mciwave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
858 else
859 WARN(mciwave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
860 return MMSYSERR_NOTENABLED;
862 WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
863 switch(WOutDev[wDevID].wFlags) {
864 case DCB_NULL:
865 TRACE(mciwave, "CALLBACK_NULL !\n");
866 break;
867 case DCB_WINDOW:
868 TRACE(mciwave, "CALLBACK_WINDOW !\n");
869 break;
870 case DCB_TASK:
871 TRACE(mciwave, "CALLBACK_TASK !\n");
872 break;
873 case DCB_FUNCTION:
874 TRACE(mciwave, "CALLBACK_FUNCTION !\n");
875 break;
877 WOutDev[wDevID].lpQueueHdr = NULL;
878 WOutDev[wDevID].unixdev = audio;
879 WOutDev[wDevID].dwTotalPlayed = 0;
880 WOutDev[wDevID].bufsize = abuf_size;
881 /* FIXME: copy lpFormat too? */
882 memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
883 TRACE(mciwave,"lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
884 lpFormat = lpDesc->lpFormat;
885 TRACE(mciwave,"lpFormat = %p\n",lpFormat);
886 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
887 WARN(mciwave,"Bad format %04X !\n",
888 lpFormat->wFormatTag);
889 WARN(mciwave,"Bad nChannels %d !\n",
890 lpFormat->nChannels);
891 WARN(mciwave,"Bad nSamplesPerSec %ld !\n",
892 lpFormat->nSamplesPerSec);
893 return WAVERR_BADFORMAT;
895 memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
896 if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
897 if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
898 TRACE(mciwave,"wBitsPerSample=%u !\n",
899 WOutDev[wDevID].Format.wBitsPerSample);
900 if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
901 WOutDev[wDevID].Format.wBitsPerSample = 8 *
902 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
903 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
904 WOutDev[wDevID].Format.wf.nChannels;
906 samplesize = WOutDev[wDevID].Format.wBitsPerSample;
907 smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
908 dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
910 /* First size and stereo then samplerate */
911 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
912 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
913 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
915 TRACE(mciwave,"wBitsPerSample=%u !\n",
916 WOutDev[wDevID].Format.wBitsPerSample);
917 TRACE(mciwave,"nAvgBytesPerSec=%lu !\n",
918 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
919 TRACE(mciwave,"nSamplesPerSec=%lu !\n",
920 WOutDev[wDevID].Format.wf.nSamplesPerSec);
921 TRACE(mciwave,"nChannels=%u !\n",
922 WOutDev[wDevID].Format.wf.nChannels);
923 if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
924 WARN(mciwave, "can't notify client !\n");
925 return MMSYSERR_INVALPARAM;
927 return MMSYSERR_NOERROR;
930 /**************************************************************************
931 * wodClose [internal]
933 static DWORD wodClose(WORD wDevID)
935 TRACE(mciwave,"(%u);\n", wDevID);
936 if (wDevID > MAX_WAVOUTDRV) return MMSYSERR_INVALPARAM;
937 if (WOutDev[wDevID].unixdev == 0) {
938 WARN(mciwave, "can't close !\n");
939 return MMSYSERR_NOTENABLED;
941 if (WOutDev[wDevID].lpQueueHdr != NULL) {
942 WARN(mciwave, "still buffers open !\n");
943 /* Don't care. Who needs those buffers anyway */
944 /*return WAVERR_STILLPLAYING; */
946 close(WOutDev[wDevID].unixdev);
947 WOutDev[wDevID].unixdev = 0;
948 WOutDev[wDevID].bufsize = 0;
949 WOutDev[wDevID].lpQueueHdr = NULL;
950 if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
951 WARN(mciwave, "can't notify client !\n");
952 return MMSYSERR_INVALPARAM;
954 return MMSYSERR_NOERROR;
957 /**************************************************************************
958 * wodWrite [internal]
959 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
960 * device, and initiate async playing.
962 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
964 int count;
965 LPSTR lpData;
966 LPWAVEHDR xwavehdr;
968 TRACE(mciwave,"(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
969 if (WOutDev[wDevID].unixdev == 0) {
970 WARN(mciwave, "can't play !\n");
971 return MMSYSERR_NOTENABLED;
973 if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
974 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
975 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
976 lpWaveHdr->dwFlags &= ~WHDR_DONE;
977 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
978 TRACE(mciwave, "dwBufferLength %lu !\n",
979 lpWaveHdr->dwBufferLength);
980 TRACE(mciwave, "WOutDev[%u].unixdev %u !\n",
981 wDevID, WOutDev[wDevID].unixdev);
982 lpData = lpWaveHdr->lpData;
983 count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
984 TRACE(mciwave,"write returned count %u !\n",count);
985 if (count != lpWaveHdr->dwBufferLength) {
986 WARN(mciwave, " error writting !\n");
987 return MMSYSERR_NOTENABLED;
989 WOutDev[wDevID].dwTotalPlayed += count;
990 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
991 lpWaveHdr->dwFlags |= WHDR_DONE;
992 if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
993 /* FIXME: what if it expects it's OWN lpwavehdr back? */
994 xwavehdr = SEGPTR_NEW(WAVEHDR);
995 memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
996 xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
997 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
998 WARN(mciwave, "can't notify client !\n");
999 SEGPTR_FREE(xwavehdr);
1000 return MMSYSERR_INVALPARAM;
1002 SEGPTR_FREE(xwavehdr);
1003 } else {
1004 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
1005 WARN(mciwave, "can't notify client !\n");
1006 return MMSYSERR_INVALPARAM;
1009 return MMSYSERR_NOERROR;
1012 /**************************************************************************
1013 * wodPrepare [internal]
1015 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1017 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1018 if (WOutDev[wDevID].unixdev == 0) {
1019 WARN(mciwave, "can't prepare !\n");
1020 return MMSYSERR_NOTENABLED;
1022 /* don't append to queue, wodWrite does that */
1023 WOutDev[wDevID].dwTotalPlayed = 0;
1024 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1025 return WAVERR_STILLPLAYING;
1026 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1027 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1028 return MMSYSERR_NOERROR;
1031 /**************************************************************************
1032 * wodUnprepare [internal]
1034 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1036 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1037 if (WOutDev[wDevID].unixdev == 0) {
1038 WARN(mciwave, "can't unprepare !\n");
1039 return MMSYSERR_NOTENABLED;
1041 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1042 return WAVERR_STILLPLAYING;
1044 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1045 lpWaveHdr->dwFlags |= WHDR_DONE;
1046 TRACE(mciwave, "all headers unprepared !\n");
1047 return MMSYSERR_NOERROR;
1050 /**************************************************************************
1051 * wodRestart [internal]
1053 static DWORD wodRestart(WORD wDevID)
1055 TRACE(mciwave,"(%u);\n", wDevID);
1056 if (WOutDev[wDevID].unixdev == 0) {
1057 WARN(mciwave, "can't restart !\n");
1058 return MMSYSERR_NOTENABLED;
1060 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1061 /* FIXME: Myst crashes with this ... hmm -MM
1062 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1063 WARN(mciwave, "can't notify client !\n");
1064 return MMSYSERR_INVALPARAM;
1068 return MMSYSERR_NOERROR;
1071 /**************************************************************************
1072 * wodReset [internal]
1074 static DWORD wodReset(WORD wDevID)
1076 TRACE(mciwave,"(%u);\n", wDevID);
1077 if (WOutDev[wDevID].unixdev == 0) {
1078 WARN(mciwave, "can't reset !\n");
1079 return MMSYSERR_NOTENABLED;
1081 return MMSYSERR_NOERROR;
1085 /**************************************************************************
1086 * wodGetPosition [internal]
1088 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1090 int time;
1091 TRACE(mciwave,"(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1092 if (WOutDev[wDevID].unixdev == 0) {
1093 WARN(mciwave, "can't get pos !\n");
1094 return MMSYSERR_NOTENABLED;
1096 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1097 TRACE(mciwave,"wType=%04X !\n",
1098 lpTime->wType);
1099 TRACE(mciwave,"wBitsPerSample=%u\n",
1100 WOutDev[wDevID].Format.wBitsPerSample);
1101 TRACE(mciwave,"nSamplesPerSec=%lu\n",
1102 WOutDev[wDevID].Format.wf.nSamplesPerSec);
1103 TRACE(mciwave,"nChannels=%u\n",
1104 WOutDev[wDevID].Format.wf.nChannels);
1105 TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1106 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
1107 switch(lpTime->wType) {
1108 case TIME_BYTES:
1109 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1110 TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1111 break;
1112 case TIME_SAMPLES:
1113 TRACE(mciwave,"dwTotalPlayed=%lu\n",
1114 WOutDev[wDevID].dwTotalPlayed);
1115 TRACE(mciwave,"wBitsPerSample=%u\n",
1116 WOutDev[wDevID].Format.wBitsPerSample);
1117 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1118 WOutDev[wDevID].Format.wBitsPerSample;
1119 TRACE(mciwave,"TIME_SAMPLES=%lu\n", lpTime->u.sample);
1120 break;
1121 case TIME_SMPTE:
1122 time = WOutDev[wDevID].dwTotalPlayed /
1123 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1124 lpTime->u.smpte.hour = time / 108000;
1125 time -= lpTime->u.smpte.hour * 108000;
1126 lpTime->u.smpte.min = time / 1800;
1127 time -= lpTime->u.smpte.min * 1800;
1128 lpTime->u.smpte.sec = time / 30;
1129 time -= lpTime->u.smpte.sec * 30;
1130 lpTime->u.smpte.frame = time;
1131 lpTime->u.smpte.fps = 30;
1132 TRACE(mciwave,
1133 "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1134 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1135 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1136 break;
1137 default:
1138 FIXME(mciwave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
1139 lpTime->wType = TIME_MS;
1140 case TIME_MS:
1141 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1142 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1143 TRACE(mciwave,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1144 break;
1146 return MMSYSERR_NOERROR;
1149 /**************************************************************************
1150 * wodGetVolume [internal]
1152 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1154 int mixer;
1155 int volume, left, right;
1156 TRACE(mciwave,"(%u, %p);\n", wDevID, lpdwVol);
1157 if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1158 if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
1159 WARN(mciwave, "mixer device not available !\n");
1160 return MMSYSERR_NOTENABLED;
1162 if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1163 WARN(mciwave, "unable read mixer !\n");
1164 return MMSYSERR_NOTENABLED;
1166 close(mixer);
1167 left = volume & 0x7F;
1168 right = (volume >> 8) & 0x7F;
1169 TRACE(mciwave,"left=%d right=%d !\n", left, right);
1170 *lpdwVol = MAKELONG(left << 9, right << 9);
1171 return MMSYSERR_NOERROR;
1175 /**************************************************************************
1176 * wodSetVolume [internal]
1178 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1180 int mixer;
1181 int volume;
1182 TRACE(mciwave,"(%u, %08lX);\n", wDevID, dwParam);
1183 volume = (LOWORD(dwParam) >> 9 & 0x7F) +
1184 ((HIWORD(dwParam) >> 9 & 0x7F) << 8);
1185 if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
1186 WARN(mciwave, "mixer device not available !\n");
1187 return MMSYSERR_NOTENABLED;
1189 if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1190 WARN(mciwave, "unable set mixer !\n");
1191 return MMSYSERR_NOTENABLED;
1193 close(mixer);
1194 return MMSYSERR_NOERROR;
1197 /**************************************************************************
1198 * wodMessage [sample driver]
1200 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1201 DWORD dwParam1, DWORD dwParam2)
1203 int audio;
1204 TRACE(mciwave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1205 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1206 switch(wMsg) {
1207 case WODM_OPEN:
1208 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1209 case WODM_CLOSE:
1210 return wodClose(wDevID);
1211 case WODM_WRITE:
1212 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1213 case WODM_PAUSE:
1214 return MMSYSERR_NOTSUPPORTED;
1215 case WODM_STOP:
1216 return MMSYSERR_NOTSUPPORTED;
1217 case WODM_GETPOS:
1218 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1219 case WODM_BREAKLOOP:
1220 return MMSYSERR_NOTSUPPORTED;
1221 case WODM_PREPARE:
1222 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1223 case WODM_UNPREPARE:
1224 return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1225 case WODM_GETDEVCAPS:
1226 return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
1227 case WODM_GETNUMDEVS:
1228 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1229 audio = open (SOUND_DEV, O_WRONLY, 0);
1230 if (audio == -1)
1232 if (errno == EBUSY)
1233 return 1;
1234 else
1235 return 0;
1237 close (audio);
1238 return 1;
1239 case WODM_GETPITCH:
1240 return MMSYSERR_NOTSUPPORTED;
1241 case WODM_SETPITCH:
1242 return MMSYSERR_NOTSUPPORTED;
1243 case WODM_GETPLAYBACKRATE:
1244 return MMSYSERR_NOTSUPPORTED;
1245 case WODM_SETPLAYBACKRATE:
1246 return MMSYSERR_NOTSUPPORTED;
1247 case WODM_GETVOLUME:
1248 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1249 case WODM_SETVOLUME:
1250 return wodSetVolume(wDevID, dwParam1);
1251 case WODM_RESTART:
1252 return wodRestart(wDevID);
1253 case WODM_RESET:
1254 return wodReset(wDevID);
1255 default:
1256 WARN(mciwave,"unknown message !\n");
1258 return MMSYSERR_NOTSUPPORTED;
1262 /*-----------------------------------------------------------------------*/
1264 /**************************************************************************
1265 * widGetDevCaps [internal]
1267 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
1269 int audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
1271 TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1272 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1273 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1274 audio = open (SOUND_DEV, O_RDONLY, 0);
1275 if (audio == -1) return MMSYSERR_ALLOCATED ;
1276 #ifdef EMULATE_SB16
1277 lpCaps->wMid = 0x0002;
1278 lpCaps->wPid = 0x0004;
1279 strcpy(lpCaps->szPname, "SB16 Wave In");
1280 #else
1281 lpCaps->wMid = 0x00FF; /* Manufac ID */
1282 lpCaps->wPid = 0x0001; /* Product ID */
1283 strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
1284 #endif
1285 lpCaps->dwFormats = 0x00000000;
1286 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1287 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1288 smplrate = 44100;
1289 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1290 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1291 if (lpCaps->wChannels > 1)
1292 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1293 if (bytespersmpl > 1) {
1294 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1295 if (lpCaps->wChannels > 1)
1296 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1299 smplrate = 22050;
1300 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1301 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1302 if (lpCaps->wChannels > 1)
1303 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1304 if (bytespersmpl > 1) {
1305 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1306 if (lpCaps->wChannels > 1)
1307 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1310 smplrate = 11025;
1311 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1312 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1313 if (lpCaps->wChannels > 1)
1314 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1315 if (bytespersmpl > 1) {
1316 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1317 if (lpCaps->wChannels > 1)
1318 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1321 close(audio);
1322 TRACE(mciwave, "dwFormats = %08lX\n", lpCaps->dwFormats);
1323 return MMSYSERR_NOERROR;
1327 /**************************************************************************
1328 * widOpen [internal]
1330 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1332 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
1333 LPWAVEFORMAT lpFormat;
1335 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1336 if (lpDesc == NULL) {
1337 WARN(mciwave, "Invalid Parameter !\n");
1338 return MMSYSERR_INVALPARAM;
1340 if (wDevID >= MAX_WAVINDRV) {
1341 TRACE(mciwave,"MAX_WAVINDRV reached !\n");
1342 return MMSYSERR_ALLOCATED;
1344 WInDev[wDevID].unixdev = 0;
1345 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1346 audio = open (SOUND_DEV, O_RDONLY, 0);
1347 if (audio == -1) {
1348 WARN(mciwave,"can't open !\n");
1349 return MMSYSERR_ALLOCATED;
1351 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1352 if (abuf_size < 1024 || abuf_size > 65536) {
1353 if (abuf_size == -1)
1354 WARN(mciwave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1355 else
1356 WARN(mciwave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1357 return MMSYSERR_NOTENABLED;
1359 WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1360 switch(WInDev[wDevID].wFlags) {
1361 case DCB_NULL:
1362 TRACE(mciwave,"CALLBACK_NULL!\n");
1363 break;
1364 case DCB_WINDOW:
1365 TRACE(mciwave,"CALLBACK_WINDOW!\n");
1366 break;
1367 case DCB_TASK:
1368 TRACE(mciwave,"CALLBACK_TASK!\n");
1369 break;
1370 case DCB_FUNCTION:
1371 TRACE(mciwave,"CALLBACK_FUNCTION!\n");
1372 break;
1374 if (WInDev[wDevID].lpQueueHdr) {
1375 HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
1376 WInDev[wDevID].lpQueueHdr = NULL;
1378 WInDev[wDevID].unixdev = audio;
1379 WInDev[wDevID].bufsize = abuf_size;
1380 WInDev[wDevID].dwTotalRecorded = 0;
1381 memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1382 lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat;
1383 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1384 WARN(mciwave, "Bad format %04X !\n",
1385 lpFormat->wFormatTag);
1386 return WAVERR_BADFORMAT;
1388 memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1389 WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1390 if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1391 if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1392 if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1393 WInDev[wDevID].Format.wBitsPerSample = 8 *
1394 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1395 WInDev[wDevID].Format.wf.nSamplesPerSec) /
1396 WInDev[wDevID].Format.wf.nChannels;
1398 samplesize = WInDev[wDevID].Format.wBitsPerSample;
1399 smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1400 dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1401 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1402 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1403 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1404 TRACE(mciwave,"wBitsPerSample=%u !\n",
1405 WInDev[wDevID].Format.wBitsPerSample);
1406 TRACE(mciwave,"nSamplesPerSec=%lu !\n",
1407 WInDev[wDevID].Format.wf.nSamplesPerSec);
1408 TRACE(mciwave,"nChannels=%u !\n",
1409 WInDev[wDevID].Format.wf.nChannels);
1410 TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1411 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1412 if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1413 WARN(mciwave,"can't notify client !\n");
1414 return MMSYSERR_INVALPARAM;
1416 return MMSYSERR_NOERROR;
1419 /**************************************************************************
1420 * widClose [internal]
1422 static DWORD widClose(WORD wDevID)
1424 TRACE(mciwave,"(%u);\n", wDevID);
1425 if (wDevID > MAX_WAVINDRV) return MMSYSERR_INVALPARAM;
1426 if (WInDev[wDevID].unixdev == 0) {
1427 WARN(mciwave,"can't close !\n");
1428 return MMSYSERR_NOTENABLED;
1430 if (WInDev[wDevID].lpQueueHdr != NULL) {
1431 WARN(mciwave, "still buffers open !\n");
1432 return WAVERR_STILLPLAYING;
1434 close(WInDev[wDevID].unixdev);
1435 WInDev[wDevID].unixdev = 0;
1436 WInDev[wDevID].bufsize = 0;
1437 if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1438 WARN(mciwave,"can't notify client !\n");
1439 return MMSYSERR_INVALPARAM;
1441 return MMSYSERR_NOERROR;
1444 /**************************************************************************
1445 * widAddBuffer [internal]
1447 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1449 int count = 1;
1450 LPWAVEHDR lpWIHdr;
1452 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1453 if (WInDev[wDevID].unixdev == 0) {
1454 WARN(mciwave,"can't do it !\n");
1455 return MMSYSERR_NOTENABLED;
1457 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1458 TRACE(mciwave, "never been prepared !\n");
1459 return WAVERR_UNPREPARED;
1461 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1462 TRACE(mciwave, "header already in use !\n");
1463 return WAVERR_STILLPLAYING;
1465 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1466 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1467 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1468 lpWaveHdr->dwBytesRecorded = 0;
1469 if (WInDev[wDevID].lpQueueHdr == NULL) {
1470 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
1471 } else {
1472 lpWIHdr = WInDev[wDevID].lpQueueHdr;
1473 while (lpWIHdr->lpNext != NULL) {
1474 lpWIHdr = lpWIHdr->lpNext;
1475 count++;
1477 lpWIHdr->lpNext = lpWaveHdr;
1478 lpWaveHdr->lpNext = NULL;
1479 count++;
1481 TRACE(mciwave, "buffer added ! (now %u in queue)\n", count);
1482 return MMSYSERR_NOERROR;
1485 /**************************************************************************
1486 * widPrepare [internal]
1488 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1490 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1491 if (WInDev[wDevID].unixdev == 0) {
1492 WARN(mciwave,"can't prepare !\n");
1493 return MMSYSERR_NOTENABLED;
1495 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1496 return WAVERR_STILLPLAYING;
1497 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1498 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1499 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1500 lpWaveHdr->dwBytesRecorded = 0;
1501 TRACE(mciwave,"header prepared !\n");
1502 return MMSYSERR_NOERROR;
1505 /**************************************************************************
1506 * widUnprepare [internal]
1508 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1510 TRACE(mciwave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1511 if (WInDev[wDevID].unixdev == 0) {
1512 WARN(mciwave,"can't unprepare !\n");
1513 return MMSYSERR_NOTENABLED;
1515 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1516 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1517 lpWaveHdr->dwFlags |= WHDR_DONE;
1519 TRACE(mciwave, "all headers unprepared !\n");
1520 return MMSYSERR_NOERROR;
1523 /**************************************************************************
1524 * widStart [internal]
1526 static DWORD widStart(WORD wDevID)
1528 int count = 1;
1529 int bytesRead;
1530 LPWAVEHDR lpWIHdr;
1531 LPWAVEHDR *lpWaveHdr;
1533 TRACE(mciwave,"(%u);\n", wDevID);
1534 if (WInDev[wDevID].unixdev == 0) {
1535 WARN(mciwave, "can't start recording !\n");
1536 return MMSYSERR_NOTENABLED;
1539 lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
1540 TRACE(mciwave,"lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
1541 if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
1542 TRACE(mciwave,"never been prepared !\n");
1543 return WAVERR_UNPREPARED;
1546 while(*lpWaveHdr != NULL) {
1547 lpWIHdr = *lpWaveHdr;
1548 TRACE(mciwave, "recording buf#%u=%p size=%lu \n",
1549 count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1550 fflush(stddeb);
1551 bytesRead = read (WInDev[wDevID].unixdev,
1552 lpWIHdr->lpData,
1553 lpWIHdr->dwBufferLength);
1554 if (bytesRead==-1)
1555 perror("read from audio device");
1556 TRACE(mciwave,"bytesread=%d (%ld)\n",
1557 bytesRead,lpWIHdr->dwBufferLength);
1558 lpWIHdr->dwBytesRecorded = bytesRead;
1559 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1560 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1561 lpWIHdr->dwFlags |= WHDR_DONE;
1563 /* FIXME: should pass segmented pointer here, do we need that?*/
1564 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
1565 WARN(mciwave, "can't notify client !\n");
1566 return MMSYSERR_INVALPARAM;
1568 /* removes the current block from the queue */
1569 *lpWaveHdr = lpWIHdr->lpNext;
1570 count++;
1572 TRACE(mciwave,"end of recording !\n");
1573 fflush(stddeb);
1574 return MMSYSERR_NOERROR;
1577 /**************************************************************************
1578 * widStop [internal]
1580 static DWORD widStop(WORD wDevID)
1582 TRACE(mciwave,"(%u);\n", wDevID);
1583 if (WInDev[wDevID].unixdev == 0) {
1584 WARN(mciwave,"can't stop !\n");
1585 return MMSYSERR_NOTENABLED;
1587 return MMSYSERR_NOERROR;
1590 /**************************************************************************
1591 * widReset [internal]
1593 static DWORD widReset(WORD wDevID)
1595 TRACE(mciwave,"(%u);\n", wDevID);
1596 if (WInDev[wDevID].unixdev == 0) {
1597 WARN(mciwave,"can't reset !\n");
1598 return MMSYSERR_NOTENABLED;
1600 return MMSYSERR_NOERROR;
1603 /**************************************************************************
1604 * widGetPosition [internal]
1606 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1608 int time;
1610 TRACE(mciwave, "(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1611 if (WInDev[wDevID].unixdev == 0) {
1612 WARN(mciwave,"can't get pos !\n");
1613 return MMSYSERR_NOTENABLED;
1615 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1616 TRACE(mciwave,"wType=%04X !\n",
1617 lpTime->wType);
1618 TRACE(mciwave,"wBitsPerSample=%u\n",
1619 WInDev[wDevID].Format.wBitsPerSample);
1620 TRACE(mciwave,"nSamplesPerSec=%lu\n",
1621 WInDev[wDevID].Format.wf.nSamplesPerSec);
1622 TRACE(mciwave,"nChannels=%u\n",
1623 WInDev[wDevID].Format.wf.nChannels);
1624 TRACE(mciwave,"nAvgBytesPerSec=%lu\n",
1625 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1626 fflush(stddeb);
1627 switch(lpTime->wType) {
1628 case TIME_BYTES:
1629 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1630 TRACE(mciwave,"TIME_BYTES=%lu\n", lpTime->u.cb);
1631 break;
1632 case TIME_SAMPLES:
1633 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1634 WInDev[wDevID].Format.wBitsPerSample;
1635 TRACE(mciwave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
1636 break;
1637 case TIME_SMPTE:
1638 time = WInDev[wDevID].dwTotalRecorded /
1639 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1640 lpTime->u.smpte.hour = time / 108000;
1641 time -= lpTime->u.smpte.hour * 108000;
1642 lpTime->u.smpte.min = time / 1800;
1643 time -= lpTime->u.smpte.min * 1800;
1644 lpTime->u.smpte.sec = time / 30;
1645 time -= lpTime->u.smpte.sec * 30;
1646 lpTime->u.smpte.frame = time;
1647 lpTime->u.smpte.fps = 30;
1648 TRACE(mciwave,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1649 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1650 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1651 break;
1652 default:
1653 FIXME(mciwave, "format not supported ! use TIME_MS !\n");
1654 lpTime->wType = TIME_MS;
1655 case TIME_MS:
1656 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1657 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1658 TRACE(mciwave, "TIME_MS=%lu\n", lpTime->u.ms);
1659 break;
1661 return MMSYSERR_NOERROR;
1664 /**************************************************************************
1665 * widMessage [sample driver]
1667 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1668 DWORD dwParam1, DWORD dwParam2)
1670 int audio;
1671 TRACE(mciwave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1672 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1673 switch(wMsg) {
1674 case WIDM_OPEN:
1675 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1676 case WIDM_CLOSE:
1677 return widClose(wDevID);
1678 case WIDM_ADDBUFFER:
1679 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1680 case WIDM_PREPARE:
1681 return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1682 case WIDM_UNPREPARE:
1683 return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1684 case WIDM_GETDEVCAPS:
1685 return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1686 case WIDM_GETNUMDEVS:
1687 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1688 audio = open (SOUND_DEV, O_RDONLY, 0);
1689 if (audio == -1)
1691 if (errno == EBUSY)
1692 return 1;
1693 else
1694 return 0;
1696 close (audio);
1697 return 1;
1698 case WIDM_GETPOS:
1699 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1700 case WIDM_RESET:
1701 return widReset(wDevID);
1702 case WIDM_START:
1703 return widStart(wDevID);
1704 case WIDM_PAUSE:
1705 return widStop(wDevID);
1706 case WIDM_STOP:
1707 return widStop(wDevID);
1708 default:
1709 WARN(mciwave,"unknown message !\n");
1711 return MMSYSERR_NOTSUPPORTED;
1715 /**************************************************************************
1716 * WAVE_DriverProc16 [sample driver]
1718 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1719 DWORD dwParam1, DWORD dwParam2)
1721 TRACE(mciwave,"(%08lX, %04X, %04X, %08lX, %08lX)\n",
1722 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1723 switch(wMsg) {
1724 case DRV_LOAD: return 1;
1725 case DRV_FREE: return 1;
1726 case DRV_OPEN: return 1;
1727 case DRV_CLOSE: return 1;
1728 case DRV_ENABLE: return 1;
1729 case DRV_DISABLE: return 1;
1730 case DRV_QUERYCONFIGURE: return 1;
1731 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1732 case DRV_INSTALL: return DRVCNF_RESTART;
1733 case DRV_REMOVE: return DRVCNF_RESTART;
1734 case MCI_OPEN_DRIVER:
1735 case MCI_OPEN: return WAVE_mciOpen(dwDevID, dwParam1, PTR_SEG_TO_LIN(dwParam2), FALSE);
1736 case MCI_CUE: return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1737 case MCI_CLOSE_DRIVER:
1738 case MCI_CLOSE: return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1739 case MCI_PLAY: return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1740 case MCI_RECORD: return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1741 case MCI_STOP: return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1742 case MCI_SET: return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1743 case MCI_PAUSE: return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1744 case MCI_RESUME: return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1745 case MCI_STATUS: return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1746 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1747 case MCI_INFO: return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1748 case MCI_LOAD: return MMSYSERR_NOTSUPPORTED;
1749 case MCI_SAVE: return MMSYSERR_NOTSUPPORTED;
1750 case MCI_SEEK: return MMSYSERR_NOTSUPPORTED;
1751 case MCI_FREEZE: return MMSYSERR_NOTSUPPORTED;
1752 case MCI_PUT: return MMSYSERR_NOTSUPPORTED;
1753 case MCI_REALIZE: return MMSYSERR_NOTSUPPORTED;
1754 case MCI_UNFREEZE: return MMSYSERR_NOTSUPPORTED;
1755 case MCI_UPDATE: return MMSYSERR_NOTSUPPORTED;
1756 case MCI_WHERE: return MMSYSERR_NOTSUPPORTED;
1757 case MCI_WINDOW: return MMSYSERR_NOTSUPPORTED;
1758 case MCI_STEP: return MMSYSERR_NOTSUPPORTED;
1759 case MCI_SPIN: return MMSYSERR_NOTSUPPORTED;
1760 case MCI_ESCAPE: return MMSYSERR_NOTSUPPORTED;
1761 case MCI_COPY: return MMSYSERR_NOTSUPPORTED;
1762 case MCI_CUT: return MMSYSERR_NOTSUPPORTED;
1763 case MCI_DELETE: return MMSYSERR_NOTSUPPORTED;
1764 case MCI_PASTE: return MMSYSERR_NOTSUPPORTED;
1766 default:
1767 return DefDriverProc16(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1769 return MMSYSERR_NOTENABLED;
1771 /**************************************************************************
1772 * WAVE_DriverProc32 [sample driver]
1774 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1775 DWORD dwParam1, DWORD dwParam2)
1777 TRACE(mciwave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n",
1778 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1779 switch(wMsg) {
1780 case DRV_LOAD: return 1;
1781 case DRV_FREE: return 1;
1782 case DRV_OPEN: return 1;
1783 case DRV_CLOSE: return 1;
1784 case DRV_ENABLE: return 1;
1785 case DRV_DISABLE: return 1;
1786 case DRV_QUERYCONFIGURE: return 1;
1787 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1788 case DRV_INSTALL: return DRVCNF_RESTART;
1789 case DRV_REMOVE: return DRVCNF_RESTART;
1790 case MCI_OPEN_DRIVER:
1791 case MCI_OPEN: return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS32A)dwParam2, TRUE);
1792 case MCI_CUE: return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1793 case MCI_CLOSE_DRIVER:
1794 case MCI_CLOSE: return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1795 case MCI_PLAY: return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
1796 case MCI_RECORD: return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)dwParam2);
1797 case MCI_STOP: return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1798 case MCI_SET: return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
1799 case MCI_PAUSE: return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1800 case MCI_RESUME: return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1801 case MCI_STATUS: return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
1802 case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1803 case MCI_INFO: return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)dwParam2);
1804 case MCI_LOAD: return MMSYSERR_NOTSUPPORTED;
1805 case MCI_SAVE: return MMSYSERR_NOTSUPPORTED;
1806 case MCI_SEEK: return MMSYSERR_NOTSUPPORTED;
1807 case MCI_FREEZE: return MMSYSERR_NOTSUPPORTED;
1808 case MCI_PUT: return MMSYSERR_NOTSUPPORTED;
1809 case MCI_REALIZE: return MMSYSERR_NOTSUPPORTED;
1810 case MCI_UNFREEZE: return MMSYSERR_NOTSUPPORTED;
1811 case MCI_UPDATE: return MMSYSERR_NOTSUPPORTED;
1812 case MCI_WHERE: return MMSYSERR_NOTSUPPORTED;
1813 case MCI_WINDOW: return MMSYSERR_NOTSUPPORTED;
1814 case MCI_STEP: return MMSYSERR_NOTSUPPORTED;
1815 case MCI_SPIN: return MMSYSERR_NOTSUPPORTED;
1816 case MCI_ESCAPE: return MMSYSERR_NOTSUPPORTED;
1817 case MCI_COPY: return MMSYSERR_NOTSUPPORTED;
1818 case MCI_CUT: return MMSYSERR_NOTSUPPORTED;
1819 case MCI_DELETE: return MMSYSERR_NOTSUPPORTED;
1820 case MCI_PASTE: return MMSYSERR_NOTSUPPORTED;
1822 default:
1823 FIXME(mciwave, "is probably wrong\n");
1824 return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1826 return MMSYSERR_NOTENABLED;
1829 #else /* !HAVE_OSS */
1831 /**************************************************************************
1832 * wodMessage [sample driver]
1834 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1835 DWORD dwParam1, DWORD dwParam2)
1837 FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1838 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1839 return MMSYSERR_NOTENABLED;
1842 /**************************************************************************
1843 * widMessage [sample driver]
1845 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1846 DWORD dwParam1, DWORD dwParam2)
1848 FIXME(mciwave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n",
1849 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1850 return MMSYSERR_NOTENABLED;
1853 /**************************************************************************
1854 * WAVE_DriverProc16 [sample driver]
1856 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1857 DWORD dwParam1, DWORD dwParam2)
1859 return MMSYSERR_NOTENABLED;
1862 /**************************************************************************
1863 * WAVE_DriverProc32 [sample driver]
1865 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1866 DWORD dwParam1, DWORD dwParam2)
1868 return MMSYSERR_NOTENABLED;
1870 #endif /* HAVE_OSS */