Re-implemented using a real semaphore.
[wine/multimedia.git] / multimedia / audio.c
blob38e08b9ec9acd5e7b62efd876777102a1981a8f2
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 "multimedia.h"
26 #include "heap.h"
27 #include "ldt.h"
28 #include "debug.h"
30 #ifdef HAVE_OSS
32 #define SOUND_DEV "/dev/dsp"
33 #define MIXER_DEV "/dev/mixer"
35 #ifdef SOUND_VERSION
36 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
37 #else
38 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
39 #endif
41 #define MAX_WAVEOUTDRV (1)
42 #define MAX_WAVEINDRV (1)
44 typedef struct {
45 int unixdev;
46 int state;
47 DWORD bufsize;
48 WAVEOPENDESC waveDesc;
49 WORD wFlags;
50 PCMWAVEFORMAT Format;
51 LPWAVEHDR lpQueueHdr;
52 DWORD dwTotalPlayed;
53 } WINE_WAVEOUT;
55 typedef struct {
56 int unixdev;
57 int state;
58 DWORD bufsize; /* OpenSound '/dev/dsp' give us that size */
59 WAVEOPENDESC waveDesc;
60 WORD wFlags;
61 PCMWAVEFORMAT Format;
62 LPWAVEHDR lpQueueHdr;
63 DWORD dwTotalRecorded;
64 } WINE_WAVEIN;
66 static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
67 static WINE_WAVEIN WInDev [MAX_WAVEOUTDRV];
69 /*======================================================================*
70 * Low level WAVE implemantation *
71 *======================================================================*/
73 /**************************************************************************
74 * WAVE_NotifyClient [internal]
76 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg,
77 DWORD dwParam1, DWORD dwParam2)
79 TRACE(wave,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",wDevID, wMsg, dwParam1, dwParam2);
81 switch (wMsg) {
82 case WOM_OPEN:
83 case WOM_CLOSE:
84 case WOM_DONE:
85 if (wDevID > MAX_WAVEOUTDRV) return MCIERR_INTERNAL;
87 if (WOutDev[wDevID].wFlags != DCB_NULL &&
88 !DriverCallback(
89 WOutDev[wDevID].waveDesc.dwCallBack,
90 WOutDev[wDevID].wFlags,
91 WOutDev[wDevID].waveDesc.hWave,
92 wMsg,
93 WOutDev[wDevID].waveDesc.dwInstance,
94 dwParam1,
95 dwParam2)) {
96 WARN(wave, "can't notify client !\n");
97 return MMSYSERR_NOERROR;
99 break;
101 case WIM_OPEN:
102 case WIM_CLOSE:
103 case WIM_DATA:
104 if (wDevID > MAX_WAVEINDRV) return MCIERR_INTERNAL;
106 if (WInDev[wDevID].wFlags != DCB_NULL &&
107 !DriverCallback(
108 WInDev[wDevID].waveDesc.dwCallBack,
109 WInDev[wDevID].wFlags,
110 WInDev[wDevID].waveDesc.hWave,
111 wMsg,
112 WInDev[wDevID].waveDesc.dwInstance,
113 dwParam1,
114 dwParam2)) {
115 WARN(wave, "can't notify client !\n");
116 return MMSYSERR_NOERROR;
118 break;
120 return 0;
123 /**************************************************************************
124 * wodGetDevCaps [internal]
126 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
128 int audio;
129 int smplrate;
130 int samplesize = 16;
131 int dsp_stereo = 1;
132 int bytespersmpl;
134 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
135 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
136 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
137 audio = open (SOUND_DEV, O_WRONLY, 0);
138 if (audio == -1) return MMSYSERR_ALLOCATED ;
139 #ifdef EMULATE_SB16
140 lpCaps->wMid = 0x0002;
141 lpCaps->wPid = 0x0104;
142 strcpy(lpCaps->szPname, "SB16 Wave Out");
143 #else
144 lpCaps->wMid = 0x00FF; /* Manufac ID */
145 lpCaps->wPid = 0x0001; /* Product ID */
146 strcpy(lpCaps->szPname, "OpenSoundSystem WAVOUT Driver");
147 #endif
148 lpCaps->vDriverVersion = 0x0100;
149 lpCaps->dwFormats = 0x00000000;
150 lpCaps->dwSupport = WAVECAPS_VOLUME;
152 /* First bytespersampl, then stereo */
153 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
155 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
156 if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
158 smplrate = 44100;
159 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
160 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
161 if (lpCaps->wChannels > 1)
162 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
163 if (bytespersmpl > 1) {
164 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
165 if (lpCaps->wChannels > 1)
166 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
169 smplrate = 22050;
170 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
171 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
172 if (lpCaps->wChannels > 1)
173 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
174 if (bytespersmpl > 1) {
175 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
176 if (lpCaps->wChannels > 1)
177 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
180 smplrate = 11025;
181 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
182 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
183 if (lpCaps->wChannels > 1)
184 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
185 if (bytespersmpl > 1) {
186 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
187 if (lpCaps->wChannels > 1)
188 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
191 close(audio);
192 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
193 return MMSYSERR_NOERROR;
197 /**************************************************************************
198 * wodOpen [internal]
200 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
202 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
203 LPWAVEFORMAT lpFormat;
205 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
206 if (lpDesc == NULL) {
207 WARN(wave, "Invalid Parameter !\n");
208 return MMSYSERR_INVALPARAM;
210 if (wDevID >= MAX_WAVEOUTDRV) {
211 TRACE(wave,"MAX_WAVOUTDRV reached !\n");
212 return MMSYSERR_ALLOCATED;
214 WOutDev[wDevID].unixdev = 0;
215 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
216 audio = open (SOUND_DEV, O_WRONLY, 0);
217 if (audio == -1) {
218 WARN(wave, "can't open !\n");
219 return MMSYSERR_ALLOCATED ;
221 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
222 if (abuf_size < 1024 || abuf_size > 65536) {
223 if (abuf_size == -1)
224 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
225 else
226 WARN(wave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
227 return MMSYSERR_NOTENABLED;
229 WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
230 switch(WOutDev[wDevID].wFlags) {
231 case DCB_NULL:
232 TRACE(wave, "CALLBACK_NULL !\n");
233 break;
234 case DCB_WINDOW:
235 TRACE(wave, "CALLBACK_WINDOW !\n");
236 break;
237 case DCB_TASK:
238 TRACE(wave, "CALLBACK_TASK !\n");
239 break;
240 case DCB_FUNCTION:
241 TRACE(wave, "CALLBACK_FUNCTION !\n");
242 break;
244 WOutDev[wDevID].lpQueueHdr = NULL;
245 WOutDev[wDevID].unixdev = audio;
246 WOutDev[wDevID].dwTotalPlayed = 0;
247 WOutDev[wDevID].bufsize = abuf_size;
248 /* FIXME: copy lpFormat too? */
249 memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
250 TRACE(wave,"lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
251 lpFormat = lpDesc->lpFormat;
252 TRACE(wave,"lpFormat = %p\n",lpFormat);
253 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
254 WARN(wave,"Bad format %04X !\n", lpFormat->wFormatTag);
255 WARN(wave,"Bad nChannels %d !\n", lpFormat->nChannels);
256 WARN(wave,"Bad nSamplesPerSec %ld !\n", lpFormat->nSamplesPerSec);
257 return WAVERR_BADFORMAT;
259 memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
260 if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
261 if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
262 TRACE(wave,"wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample);
263 if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
264 WOutDev[wDevID].Format.wBitsPerSample = 8 *
265 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
266 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
267 WOutDev[wDevID].Format.wf.nChannels;
269 samplesize = WOutDev[wDevID].Format.wBitsPerSample;
270 smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
271 dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
273 /* First size and stereo then samplerate */
274 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
275 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
276 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
278 TRACE(wave,"wBitsPerSample=%u !\n", WOutDev[wDevID].Format.wBitsPerSample);
279 TRACE(wave,"nAvgBytesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
280 TRACE(wave,"nSamplesPerSec=%lu !\n", WOutDev[wDevID].Format.wf.nSamplesPerSec);
281 TRACE(wave,"nChannels=%u !\n", WOutDev[wDevID].Format.wf.nChannels);
282 if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
283 WARN(wave, "can't notify client !\n");
284 return MMSYSERR_INVALPARAM;
286 return MMSYSERR_NOERROR;
289 /**************************************************************************
290 * wodClose [internal]
292 static DWORD wodClose(WORD wDevID)
294 TRACE(wave,"(%u);\n", wDevID);
296 if (wDevID > MAX_WAVEOUTDRV) return MMSYSERR_INVALPARAM;
297 if (WOutDev[wDevID].unixdev == 0) {
298 WARN(wave, "can't close !\n");
299 return MMSYSERR_NOTENABLED;
301 if (WOutDev[wDevID].lpQueueHdr != NULL) {
302 WARN(wave, "still buffers open !\n");
303 /* Don't care. Who needs those buffers anyway */
304 /*return WAVERR_STILLPLAYING; */
306 close(WOutDev[wDevID].unixdev);
307 WOutDev[wDevID].unixdev = 0;
308 WOutDev[wDevID].bufsize = 0;
309 WOutDev[wDevID].lpQueueHdr = NULL;
310 if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
311 WARN(wave, "can't notify client !\n");
312 return MMSYSERR_INVALPARAM;
314 return MMSYSERR_NOERROR;
317 /**************************************************************************
318 * wodWrite [internal]
319 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
320 * device, and initiate async playing.
322 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
324 int count;
325 LPSTR lpData;
326 LPWAVEHDR xwavehdr;
328 TRACE(wave,"(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
329 if (WOutDev[wDevID].unixdev == 0) {
330 WARN(wave, "can't play !\n");
331 return MMSYSERR_NOTENABLED;
333 if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
334 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
335 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
336 lpWaveHdr->dwFlags &= ~WHDR_DONE;
337 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
338 TRACE(wave, "dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
339 TRACE(wave, "WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
340 lpData = lpWaveHdr->lpData;
341 count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
342 TRACE(wave,"write returned count %u !\n",count);
343 if (count != lpWaveHdr->dwBufferLength) {
344 WARN(wave, " error writting !\n");
345 return MMSYSERR_NOTENABLED;
347 WOutDev[wDevID].dwTotalPlayed += count;
348 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
349 lpWaveHdr->dwFlags |= WHDR_DONE;
350 if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
351 /* FIXME: what if it expects it's OWN lpwavehdr back? */
352 xwavehdr = SEGPTR_NEW(WAVEHDR);
353 memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
354 xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
355 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
356 WARN(wave, "can't notify client !\n");
357 SEGPTR_FREE(xwavehdr);
358 return MMSYSERR_INVALPARAM;
360 SEGPTR_FREE(xwavehdr);
361 } else {
362 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
363 WARN(wave, "can't notify client !\n");
364 return MMSYSERR_INVALPARAM;
367 return MMSYSERR_NOERROR;
370 /**************************************************************************
371 * wodPrepare [internal]
373 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
375 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
376 if (WOutDev[wDevID].unixdev == 0) {
377 WARN(wave, "can't prepare !\n");
378 return MMSYSERR_NOTENABLED;
380 /* don't append to queue, wodWrite does that */
381 WOutDev[wDevID].dwTotalPlayed = 0;
382 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
383 return WAVERR_STILLPLAYING;
384 lpWaveHdr->dwFlags |= WHDR_PREPARED;
385 lpWaveHdr->dwFlags &= ~WHDR_DONE;
386 return MMSYSERR_NOERROR;
389 /**************************************************************************
390 * wodUnprepare [internal]
392 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
394 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
395 if (WOutDev[wDevID].unixdev == 0) {
396 WARN(wave, "can't unprepare !\n");
397 return MMSYSERR_NOTENABLED;
399 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
400 return WAVERR_STILLPLAYING;
402 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
403 lpWaveHdr->dwFlags |= WHDR_DONE;
404 TRACE(wave, "all headers unprepared !\n");
405 return MMSYSERR_NOERROR;
408 /**************************************************************************
409 * wodRestart [internal]
411 static DWORD wodRestart(WORD wDevID)
413 TRACE(wave,"(%u);\n", wDevID);
414 if (WOutDev[wDevID].unixdev == 0) {
415 WARN(wave, "can't restart !\n");
416 return MMSYSERR_NOTENABLED;
418 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
419 /* FIXME: Myst crashes with this ... hmm -MM
420 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
421 WARN(wave, "can't notify client !\n");
422 return MMSYSERR_INVALPARAM;
426 return MMSYSERR_NOERROR;
429 /**************************************************************************
430 * wodReset [internal]
432 static DWORD wodReset(WORD wDevID)
434 TRACE(wave,"(%u);\n", wDevID);
435 if (WOutDev[wDevID].unixdev == 0) {
436 WARN(wave, "can't reset !\n");
437 return MMSYSERR_NOTENABLED;
439 return MMSYSERR_NOERROR;
443 /**************************************************************************
444 * wodGetPosition [internal]
446 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
448 int time;
449 TRACE(wave,"(%u, %p, %lu);\n", wDevID, lpTime, uSize);
450 if (WOutDev[wDevID].unixdev == 0) {
451 WARN(wave, "can't get pos !\n");
452 return MMSYSERR_NOTENABLED;
454 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
455 TRACE(wave,"wType=%04X !\n", lpTime->wType);
456 TRACE(wave,"wBitsPerSample=%u\n", WOutDev[wDevID].Format.wBitsPerSample);
457 TRACE(wave,"nSamplesPerSec=%lu\n", WOutDev[wDevID].Format.wf.nSamplesPerSec);
458 TRACE(wave,"nChannels=%u\n", WOutDev[wDevID].Format.wf.nChannels);
459 TRACE(wave,"nAvgBytesPerSec=%lu\n", WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
460 switch(lpTime->wType) {
461 case TIME_BYTES:
462 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
463 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
464 break;
465 case TIME_SAMPLES:
466 TRACE(wave,"dwTotalPlayed=%lu\n", WOutDev[wDevID].dwTotalPlayed);
467 TRACE(wave,"wBitsPerSample=%u\n", WOutDev[wDevID].Format.wBitsPerSample);
468 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
469 WOutDev[wDevID].Format.wBitsPerSample;
470 TRACE(wave,"TIME_SAMPLES=%lu\n", lpTime->u.sample);
471 break;
472 case TIME_SMPTE:
473 time = WOutDev[wDevID].dwTotalPlayed /
474 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
475 lpTime->u.smpte.hour = time / 108000;
476 time -= lpTime->u.smpte.hour * 108000;
477 lpTime->u.smpte.min = time / 1800;
478 time -= lpTime->u.smpte.min * 1800;
479 lpTime->u.smpte.sec = time / 30;
480 time -= lpTime->u.smpte.sec * 30;
481 lpTime->u.smpte.frame = time;
482 lpTime->u.smpte.fps = 30;
483 TRACE(wave, "wodGetPosition , TIME_SMPTE=%02u:%02u:%02u:%02u\n",
484 lpTime->u.smpte.hour, lpTime->u.smpte.min,
485 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
486 break;
487 default:
488 FIXME(wave, "wodGetPosition() format %d not supported ! use TIME_MS !\n",lpTime->wType);
489 lpTime->wType = TIME_MS;
490 case TIME_MS:
491 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
492 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
493 TRACE(wave,"wodGetPosition , TIME_MS=%lu\n", lpTime->u.ms);
494 break;
496 return MMSYSERR_NOERROR;
499 /**************************************************************************
500 * wodGetVolume [internal]
502 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
504 int mixer;
505 int volume, left, right;
506 TRACE(wave,"(%u, %p);\n", wDevID, lpdwVol);
507 if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
508 if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
509 WARN(wave, "mixer device not available !\n");
510 return MMSYSERR_NOTENABLED;
512 if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
513 WARN(wave, "unable read mixer !\n");
514 return MMSYSERR_NOTENABLED;
516 close(mixer);
517 left = volume & 0x7F;
518 right = (volume >> 8) & 0x7F;
519 TRACE(wave,"left=%d right=%d !\n", left, right);
520 *lpdwVol = MAKELONG(left << 9, right << 9);
521 return MMSYSERR_NOERROR;
525 /**************************************************************************
526 * wodSetVolume [internal]
528 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
530 int mixer;
531 int volume;
532 TRACE(wave,"(%u, %08lX);\n", wDevID, dwParam);
533 volume = (LOWORD(dwParam) >> 9 & 0x7F) +
534 ((HIWORD(dwParam) >> 9 & 0x7F) << 8);
535 if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
536 WARN(wave, "mixer device not available !\n");
537 return MMSYSERR_NOTENABLED;
539 if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
540 WARN(wave, "unable set mixer !\n");
541 return MMSYSERR_NOTENABLED;
543 close(mixer);
544 return MMSYSERR_NOERROR;
547 /**************************************************************************
548 * wodMessage [sample driver]
550 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
551 DWORD dwParam1, DWORD dwParam2)
553 int audio;
554 TRACE(wave,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
555 wDevID, wMsg, dwUser, dwParam1, dwParam2);
556 switch(wMsg) {
557 case WODM_OPEN:
558 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
559 case WODM_CLOSE:
560 return wodClose(wDevID);
561 case WODM_WRITE:
562 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
563 case WODM_PAUSE:
564 return MMSYSERR_NOTSUPPORTED;
565 case WODM_STOP:
566 return MMSYSERR_NOTSUPPORTED;
567 case WODM_GETPOS:
568 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
569 case WODM_BREAKLOOP:
570 return MMSYSERR_NOTSUPPORTED;
571 case WODM_PREPARE:
572 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
573 case WODM_UNPREPARE:
574 return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
575 case WODM_GETDEVCAPS:
576 return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
577 case WODM_GETNUMDEVS:
578 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
579 audio = open (SOUND_DEV, O_WRONLY, 0);
580 if (audio == -1)
582 if (errno == EBUSY)
583 return 1;
584 else
585 return 0;
587 close (audio);
588 return 1;
589 case WODM_GETPITCH:
590 return MMSYSERR_NOTSUPPORTED;
591 case WODM_SETPITCH:
592 return MMSYSERR_NOTSUPPORTED;
593 case WODM_GETPLAYBACKRATE:
594 return MMSYSERR_NOTSUPPORTED;
595 case WODM_SETPLAYBACKRATE:
596 return MMSYSERR_NOTSUPPORTED;
597 case WODM_GETVOLUME:
598 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
599 case WODM_SETVOLUME:
600 return wodSetVolume(wDevID, dwParam1);
601 case WODM_RESTART:
602 return wodRestart(wDevID);
603 case WODM_RESET:
604 return wodReset(wDevID);
605 default:
606 WARN(wave,"unknown message !\n");
608 return MMSYSERR_NOTSUPPORTED;
612 /*-----------------------------------------------------------------------*/
614 /**************************************************************************
615 * widGetDevCaps [internal]
617 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
619 int audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
621 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
622 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
623 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
624 audio = open (SOUND_DEV, O_RDONLY, 0);
625 if (audio == -1) return MMSYSERR_ALLOCATED ;
626 #ifdef EMULATE_SB16
627 lpCaps->wMid = 0x0002;
628 lpCaps->wPid = 0x0004;
629 strcpy(lpCaps->szPname, "SB16 Wave In");
630 #else
631 lpCaps->wMid = 0x00FF; /* Manufac ID */
632 lpCaps->wPid = 0x0001; /* Product ID */
633 strcpy(lpCaps->szPname, "OpenSoundSystem WAVIN Driver");
634 #endif
635 lpCaps->dwFormats = 0x00000000;
636 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
637 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
638 smplrate = 44100;
639 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
640 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
641 if (lpCaps->wChannels > 1)
642 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
643 if (bytespersmpl > 1) {
644 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
645 if (lpCaps->wChannels > 1)
646 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
649 smplrate = 22050;
650 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
651 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
652 if (lpCaps->wChannels > 1)
653 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
654 if (bytespersmpl > 1) {
655 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
656 if (lpCaps->wChannels > 1)
657 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
660 smplrate = 11025;
661 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
662 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
663 if (lpCaps->wChannels > 1)
664 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
665 if (bytespersmpl > 1) {
666 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
667 if (lpCaps->wChannels > 1)
668 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
671 close(audio);
672 TRACE(wave, "dwFormats = %08lX\n", lpCaps->dwFormats);
673 return MMSYSERR_NOERROR;
677 /**************************************************************************
678 * widOpen [internal]
680 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
682 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
683 LPWAVEFORMAT lpFormat;
685 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
686 if (lpDesc == NULL) {
687 WARN(wave, "Invalid Parameter !\n");
688 return MMSYSERR_INVALPARAM;
690 if (wDevID >= MAX_WAVEINDRV) {
691 TRACE(wave,"MAX_WAVINDRV reached !\n");
692 return MMSYSERR_ALLOCATED;
694 WInDev[wDevID].unixdev = 0;
695 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
696 audio = open (SOUND_DEV, O_RDONLY, 0);
697 if (audio == -1) {
698 WARN(wave,"can't open !\n");
699 return MMSYSERR_ALLOCATED;
701 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
702 if (abuf_size < 1024 || abuf_size > 65536) {
703 if (abuf_size == -1)
704 WARN(wave, "IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
705 else
706 WARN(wave, "SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
707 return MMSYSERR_NOTENABLED;
709 WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
710 switch(WInDev[wDevID].wFlags) {
711 case DCB_NULL:
712 TRACE(wave,"CALLBACK_NULL!\n");
713 break;
714 case DCB_WINDOW:
715 TRACE(wave,"CALLBACK_WINDOW!\n");
716 break;
717 case DCB_TASK:
718 TRACE(wave,"CALLBACK_TASK!\n");
719 break;
720 case DCB_FUNCTION:
721 TRACE(wave,"CALLBACK_FUNCTION!\n");
722 break;
724 if (WInDev[wDevID].lpQueueHdr) {
725 HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
726 WInDev[wDevID].lpQueueHdr = NULL;
728 WInDev[wDevID].unixdev = audio;
729 WInDev[wDevID].bufsize = abuf_size;
730 WInDev[wDevID].dwTotalRecorded = 0;
731 memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
732 lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat;
733 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
734 WARN(wave, "Bad format %04X !\n",
735 lpFormat->wFormatTag);
736 return WAVERR_BADFORMAT;
738 memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
739 WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
740 if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
741 if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
742 if (WInDev[wDevID].Format.wBitsPerSample == 0) {
743 WInDev[wDevID].Format.wBitsPerSample = 8 *
744 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
745 WInDev[wDevID].Format.wf.nSamplesPerSec) /
746 WInDev[wDevID].Format.wf.nChannels;
748 samplesize = WInDev[wDevID].Format.wBitsPerSample;
749 smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
750 dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
751 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
752 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
753 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
754 TRACE(wave,"wBitsPerSample=%u !\n", WInDev[wDevID].Format.wBitsPerSample);
755 TRACE(wave,"nSamplesPerSec=%lu !\n", WInDev[wDevID].Format.wf.nSamplesPerSec);
756 TRACE(wave,"nChannels=%u !\n", WInDev[wDevID].Format.wf.nChannels);
757 TRACE(wave,"nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec);
758 if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
759 WARN(wave,"can't notify client !\n");
760 return MMSYSERR_INVALPARAM;
762 return MMSYSERR_NOERROR;
765 /**************************************************************************
766 * widClose [internal]
768 static DWORD widClose(WORD wDevID)
770 TRACE(wave,"(%u);\n", wDevID);
771 if (wDevID > MAX_WAVEINDRV) return MMSYSERR_INVALPARAM;
772 if (WInDev[wDevID].unixdev == 0) {
773 WARN(wave,"can't close !\n");
774 return MMSYSERR_NOTENABLED;
776 if (WInDev[wDevID].lpQueueHdr != NULL) {
777 WARN(wave, "still buffers open !\n");
778 return WAVERR_STILLPLAYING;
780 close(WInDev[wDevID].unixdev);
781 WInDev[wDevID].unixdev = 0;
782 WInDev[wDevID].bufsize = 0;
783 if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
784 WARN(wave,"can't notify client !\n");
785 return MMSYSERR_INVALPARAM;
787 return MMSYSERR_NOERROR;
790 /**************************************************************************
791 * widAddBuffer [internal]
793 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
795 int count = 1;
796 LPWAVEHDR lpWIHdr;
798 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
799 if (WInDev[wDevID].unixdev == 0) {
800 WARN(wave,"can't do it !\n");
801 return MMSYSERR_NOTENABLED;
803 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
804 TRACE(wave, "never been prepared !\n");
805 return WAVERR_UNPREPARED;
807 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
808 TRACE(wave, "header already in use !\n");
809 return WAVERR_STILLPLAYING;
811 lpWaveHdr->dwFlags |= WHDR_PREPARED;
812 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
813 lpWaveHdr->dwFlags &= ~WHDR_DONE;
814 lpWaveHdr->dwBytesRecorded = 0;
815 if (WInDev[wDevID].lpQueueHdr == NULL) {
816 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
817 } else {
818 lpWIHdr = WInDev[wDevID].lpQueueHdr;
819 while (lpWIHdr->lpNext != NULL) {
820 lpWIHdr = lpWIHdr->lpNext;
821 count++;
823 lpWIHdr->lpNext = lpWaveHdr;
824 lpWaveHdr->lpNext = NULL;
825 count++;
827 TRACE(wave, "buffer added ! (now %u in queue)\n", count);
828 return MMSYSERR_NOERROR;
831 /**************************************************************************
832 * widPrepare [internal]
834 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
836 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
837 if (WInDev[wDevID].unixdev == 0) {
838 WARN(wave,"can't prepare !\n");
839 return MMSYSERR_NOTENABLED;
841 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
842 return WAVERR_STILLPLAYING;
843 lpWaveHdr->dwFlags |= WHDR_PREPARED;
844 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
845 lpWaveHdr->dwFlags &= ~WHDR_DONE;
846 lpWaveHdr->dwBytesRecorded = 0;
847 TRACE(wave,"header prepared !\n");
848 return MMSYSERR_NOERROR;
851 /**************************************************************************
852 * widUnprepare [internal]
854 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
856 TRACE(wave, "(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
857 if (WInDev[wDevID].unixdev == 0) {
858 WARN(wave,"can't unprepare !\n");
859 return MMSYSERR_NOTENABLED;
861 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
862 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
863 lpWaveHdr->dwFlags |= WHDR_DONE;
865 TRACE(wave, "all headers unprepared !\n");
866 return MMSYSERR_NOERROR;
869 /**************************************************************************
870 * widStart [internal]
872 static DWORD widStart(WORD wDevID)
874 int count = 1;
875 int bytesRead;
876 LPWAVEHDR lpWIHdr;
877 LPWAVEHDR *lpWaveHdr;
879 TRACE(wave,"(%u);\n", wDevID);
880 if (WInDev[wDevID].unixdev == 0) {
881 WARN(wave, "can't start recording !\n");
882 return MMSYSERR_NOTENABLED;
885 lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
886 TRACE(wave,"lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
887 if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
888 TRACE(wave,"never been prepared !\n");
889 return WAVERR_UNPREPARED;
892 while(*lpWaveHdr != NULL) {
893 lpWIHdr = *lpWaveHdr;
894 TRACE(wave, "recording buf#%u=%p size=%lu \n",
895 count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
896 fflush(stddeb);
897 bytesRead = read (WInDev[wDevID].unixdev,
898 lpWIHdr->lpData,
899 lpWIHdr->dwBufferLength);
900 if (bytesRead==-1)
901 perror("read from audio device");
902 TRACE(wave,"bytesread=%d (%ld)\n", bytesRead, lpWIHdr->dwBufferLength);
903 lpWIHdr->dwBytesRecorded = bytesRead;
904 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
905 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
906 lpWIHdr->dwFlags |= WHDR_DONE;
908 /* FIXME: should pass segmented pointer here, do we need that?*/
909 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
910 WARN(wave, "can't notify client !\n");
911 return MMSYSERR_INVALPARAM;
913 /* removes the current block from the queue */
914 *lpWaveHdr = lpWIHdr->lpNext;
915 count++;
917 TRACE(wave,"end of recording !\n");
918 fflush(stddeb);
919 return MMSYSERR_NOERROR;
922 /**************************************************************************
923 * widStop [internal]
925 static DWORD widStop(WORD wDevID)
927 TRACE(wave,"(%u);\n", wDevID);
928 if (WInDev[wDevID].unixdev == 0) {
929 WARN(wave,"can't stop !\n");
930 return MMSYSERR_NOTENABLED;
932 return MMSYSERR_NOERROR;
935 /**************************************************************************
936 * widReset [internal]
938 static DWORD widReset(WORD wDevID)
940 TRACE(wave,"(%u);\n", wDevID);
941 if (WInDev[wDevID].unixdev == 0) {
942 WARN(wave,"can't reset !\n");
943 return MMSYSERR_NOTENABLED;
945 return MMSYSERR_NOERROR;
948 /**************************************************************************
949 * widGetPosition [internal]
951 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
953 int time;
955 TRACE(wave, "(%u, %p, %lu);\n", wDevID, lpTime, uSize);
956 if (WInDev[wDevID].unixdev == 0) {
957 WARN(wave,"can't get pos !\n");
958 return MMSYSERR_NOTENABLED;
960 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
961 TRACE(wave,"wType=%04X !\n", lpTime->wType);
962 TRACE(wave,"wBitsPerSample=%u\n", WInDev[wDevID].Format.wBitsPerSample);
963 TRACE(wave,"nSamplesPerSec=%lu\n", WInDev[wDevID].Format.wf.nSamplesPerSec);
964 TRACE(wave,"nChannels=%u\n", WInDev[wDevID].Format.wf.nChannels);
965 TRACE(wave,"nAvgBytesPerSec=%lu\n", WInDev[wDevID].Format.wf.nAvgBytesPerSec);
966 fflush(stddeb);
967 switch(lpTime->wType) {
968 case TIME_BYTES:
969 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
970 TRACE(wave,"TIME_BYTES=%lu\n", lpTime->u.cb);
971 break;
972 case TIME_SAMPLES:
973 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
974 WInDev[wDevID].Format.wBitsPerSample;
975 TRACE(wave, "TIME_SAMPLES=%lu\n", lpTime->u.sample);
976 break;
977 case TIME_SMPTE:
978 time = WInDev[wDevID].dwTotalRecorded /
979 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
980 lpTime->u.smpte.hour = time / 108000;
981 time -= lpTime->u.smpte.hour * 108000;
982 lpTime->u.smpte.min = time / 1800;
983 time -= lpTime->u.smpte.min * 1800;
984 lpTime->u.smpte.sec = time / 30;
985 time -= lpTime->u.smpte.sec * 30;
986 lpTime->u.smpte.frame = time;
987 lpTime->u.smpte.fps = 30;
988 TRACE(wave,"TIME_SMPTE=%02u:%02u:%02u:%02u\n",
989 lpTime->u.smpte.hour, lpTime->u.smpte.min,
990 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
991 break;
992 case TIME_MS:
993 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
994 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
995 TRACE(wave, "TIME_MS=%lu\n", lpTime->u.ms);
996 break;
997 default:
998 FIXME(wave, "format not supported ! use TIME_MS !\n");
999 lpTime->wType = TIME_MS;
1001 return MMSYSERR_NOERROR;
1004 /**************************************************************************
1005 * widMessage [sample driver]
1007 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1008 DWORD dwParam1, DWORD dwParam2)
1010 int audio;
1011 TRACE(wave,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1012 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1013 switch(wMsg) {
1014 case WIDM_OPEN:
1015 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1016 case WIDM_CLOSE:
1017 return widClose(wDevID);
1018 case WIDM_ADDBUFFER:
1019 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1020 case WIDM_PREPARE:
1021 return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1022 case WIDM_UNPREPARE:
1023 return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1024 case WIDM_GETDEVCAPS:
1025 return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1026 case WIDM_GETNUMDEVS:
1027 /* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
1028 audio = open (SOUND_DEV, O_RDONLY, 0);
1029 if (audio == -1)
1031 if (errno == EBUSY)
1032 return 1;
1033 else
1034 return 0;
1036 close (audio);
1037 return 1;
1038 case WIDM_GETPOS:
1039 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1040 case WIDM_RESET:
1041 return widReset(wDevID);
1042 case WIDM_START:
1043 return widStart(wDevID);
1044 case WIDM_PAUSE:
1045 return widStop(wDevID);
1046 case WIDM_STOP:
1047 return widStop(wDevID);
1048 default:
1049 WARN(wave,"unknown message !\n");
1051 return MMSYSERR_NOTSUPPORTED;
1055 /**************************************************************************
1056 * WAVE_DriverProc16 [sample driver]
1058 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1059 DWORD dwParam1, DWORD dwParam2)
1061 TRACE(wave,"(%08lX, %04X, %04X, %08lX, %08lX)\n", dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1063 switch(wMsg) {
1064 case DRV_LOAD: return 1;
1065 case DRV_FREE: return 1;
1066 case DRV_OPEN: return 1;
1067 case DRV_CLOSE: return 1;
1068 case DRV_ENABLE: return 1;
1069 case DRV_DISABLE: return 1;
1070 case DRV_QUERYCONFIGURE: return 1;
1071 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1072 case DRV_INSTALL: return DRVCNF_RESTART;
1073 case DRV_REMOVE: return DRVCNF_RESTART;
1074 default:
1075 FIXME(wave, "is probably wrong msg=0x%04x\n", wMsg);
1076 return DefDriverProc16(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1078 return MMSYSERR_NOTENABLED;
1081 /**************************************************************************
1082 * WAVE_DriverProc32 [sample driver]
1084 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1085 DWORD dwParam1, DWORD dwParam2)
1087 TRACE(wave,"(%08lX, %04X, %08lX, %08lX, %08lX)\n", dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1088 switch(wMsg) {
1089 case DRV_LOAD: return 1;
1090 case DRV_FREE: return 1;
1091 case DRV_OPEN: return 1;
1092 case DRV_CLOSE: return 1;
1093 case DRV_ENABLE: return 1;
1094 case DRV_DISABLE: return 1;
1095 case DRV_QUERYCONFIGURE: return 1;
1096 case DRV_CONFIGURE: MessageBox16(0, "Sample MultiMedia Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1097 case DRV_INSTALL: return DRVCNF_RESTART;
1098 case DRV_REMOVE: return DRVCNF_RESTART;
1099 default:
1100 FIXME(wave, "is probably wrong msg=0x%04lx\n", wMsg);
1101 return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1103 return MMSYSERR_NOTENABLED;
1106 #else /* !HAVE_OSS */
1108 /**************************************************************************
1109 * wodMessage [sample driver]
1111 DWORD WINAPI wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1112 DWORD dwParam1, DWORD dwParam2)
1114 FIXME(wave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1115 return MMSYSERR_NOTENABLED;
1118 /**************************************************************************
1119 * widMessage [sample driver]
1121 DWORD WINAPI widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1122 DWORD dwParam1, DWORD dwParam2)
1124 FIXME(wave,"(%u, %04X, %08lX, %08lX, %08lX):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1125 return MMSYSERR_NOTENABLED;
1128 /**************************************************************************
1129 * WAVE_DriverProc16 [sample driver]
1131 LONG WAVE_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1132 DWORD dwParam1, DWORD dwParam2)
1134 return MMSYSERR_NOTENABLED;
1137 /**************************************************************************
1138 * WAVE_DriverProc32 [sample driver]
1140 LONG WAVE_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1141 DWORD dwParam1, DWORD dwParam2)
1143 return MMSYSERR_NOTENABLED;
1145 #endif /* HAVE_OSS */