Release 971221
[wine/multimedia.git] / multimedia / audio.c
blob58d8365497baa208745b40372b539912a38c93a9
1 /*
2 * Sample Wine Driver for Linux
4 * Copyright 1994 Martin Ayotte
5 */
6 /*
7 * FIXME:
8 * - record/play should and must be done asynchronous
9 * - segmented/linear pointer problems (lpData in waveheaders,W*_DONE cbs)
12 #define EMULATE_SB16
14 #define DEBUG_MCIWAVE
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/ioctl.h>
21 #include "windows.h"
22 #include "user.h"
23 #include "driver.h"
24 #include "mmsystem.h"
25 #include "heap.h"
26 #include "ldt.h"
28 #ifdef linux
29 #include <linux/soundcard.h>
30 #elif __FreeBSD__
31 #include <machine/soundcard.h>
32 #endif
34 #include "stddebug.h"
35 #include "debug.h"
37 #if defined(linux) || defined(__FreeBSD__)
38 #define SOUND_DEV "/dev/dsp"
39 #define MIXER_DEV "/dev/mixer"
41 #ifdef SOUND_VERSION
42 #define IOCTL(a,b,c) ((-1==ioctl(a,b,&c))&&(perror("ioctl:"#b":"#c),0))
43 #else
44 #define IOCTL(a,b,c) (c = ioctl(a,b,c) )
45 #endif
47 #define MAX_WAVOUTDRV (1)
48 #define MAX_WAVINDRV (1)
49 #define MAX_MCIWAVDRV (1)
51 typedef struct {
52 int unixdev;
53 int state;
54 DWORD bufsize;
55 WAVEOPENDESC waveDesc;
56 WORD wFlags;
57 PCMWAVEFORMAT Format;
58 LPWAVEHDR lpQueueHdr;
59 DWORD dwTotalPlayed;
60 } LINUX_WAVEOUT;
62 typedef struct {
63 int unixdev;
64 int state;
65 DWORD bufsize; /* Linux '/dev/dsp' give us that size */
66 WAVEOPENDESC waveDesc;
67 WORD wFlags;
68 PCMWAVEFORMAT Format;
69 LPWAVEHDR lpQueueHdr;
70 DWORD dwTotalRecorded;
71 } LINUX_WAVEIN;
73 typedef struct {
74 int nUseCount; /* Incremented for each shared open */
75 BOOL16 fShareable; /* TRUE if first open was shareable */
76 WORD wNotifyDeviceID;/* MCI device ID with a pending notification */
77 HANDLE16 hCallback; /* Callback handle for pending notification */
78 HMMIO16 hFile; /* mmio file handle open as Element */
79 MCI_WAVE_OPEN_PARMS16 openParms;
80 PCMWAVEFORMAT WaveFormat;
81 WAVEHDR WaveHdr;
82 BOOL16 fInput; /* FALSE = Output, TRUE = Input */
83 } LINUX_MCIWAVE;
85 static LINUX_WAVEOUT WOutDev[MAX_WAVOUTDRV];
86 static LINUX_WAVEIN WInDev[MAX_WAVOUTDRV];
87 static LINUX_MCIWAVE MCIWavDev[MAX_MCIWAVDRV];
90 /**************************************************************************
91 * WAVE_NotifyClient [internal]
93 static DWORD WAVE_NotifyClient(UINT16 wDevID, WORD wMsg,
94 DWORD dwParam1, DWORD dwParam2)
96 dprintf_mciwave(stddeb,"WAVE_NotifyClient // 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 dprintf_mciwave(stddeb,"WAVE_NotifyClient // 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 dprintf_mciwave(stddeb,"WAVE_NotifyClient // can't notify client !\n");
127 return MMSYSERR_NOERROR;
129 break;
131 return 0;
135 /**************************************************************************
136 * WAVE_mciOpen [internal]
138 static DWORD WAVE_mciOpen(UINT16 wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMS16 lpParms)
140 LPPCMWAVEFORMAT lpWaveFormat;
141 WAVEOPENDESC waveDesc;
142 LPSTR lpstrElementName;
143 DWORD dwRet;
144 char str[128];
146 dprintf_mciwave(stddeb,"WAVE_mciOpen(%04X, %08lX, %p)\n",
147 wDevID, dwFlags, lpParms);
148 if (lpParms == NULL) return MCIERR_INTERNAL;
150 if (MCIWavDev[wDevID].nUseCount > 0) {
151 /* The driver already open on this channel */
152 /* If the driver was opened shareable before and this open specifies */
153 /* shareable then increment the use count */
154 if (MCIWavDev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
155 ++MCIWavDev[wDevID].nUseCount;
156 else
157 return MCIERR_MUST_USE_SHAREABLE;
158 } else {
159 MCIWavDev[wDevID].nUseCount = 1;
160 MCIWavDev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
163 MCIWavDev[wDevID].fInput = FALSE;
165 dprintf_mciwave(stddeb,"WAVE_mciOpen // wDevID=%04X\n", wDevID);
166 dprintf_mciwave(stddeb,"WAVE_mciOpen // before OPEN_ELEMENT\n");
167 if (dwFlags & MCI_OPEN_ELEMENT) {
168 lpstrElementName = (LPSTR)PTR_SEG_TO_LIN(lpParms->lpstrElementName);
169 dprintf_mciwave(stddeb,"WAVE_mciOpen // MCI_OPEN_ELEMENT '%s' !\n",
170 lpstrElementName);
171 if ( lpstrElementName && (strlen(lpstrElementName) > 0)) {
172 strcpy(str, lpstrElementName);
173 CharUpper32A(str);
174 MCIWavDev[wDevID].hFile = mmioOpen16(str, NULL,
175 MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_EXCLUSIVE);
176 if (MCIWavDev[wDevID].hFile == 0) {
177 dprintf_mciwave(stddeb,"WAVE_mciOpen // can't find file='%s' !\n", str);
178 return MCIERR_FILE_NOT_FOUND;
181 else
182 MCIWavDev[wDevID].hFile = 0;
184 dprintf_mciwave(stddeb,"WAVE_mciOpen // hFile=%u\n", MCIWavDev[wDevID].hFile);
185 memcpy(&MCIWavDev[wDevID].openParms, lpParms, sizeof(MCI_WAVE_OPEN_PARMS16));
186 MCIWavDev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
187 lpWaveFormat = &MCIWavDev[wDevID].WaveFormat;
189 waveDesc.hWave = 0;
191 lpWaveFormat->wf.wFormatTag = WAVE_FORMAT_PCM;
192 lpWaveFormat->wBitsPerSample = 8;
193 lpWaveFormat->wf.nChannels = 1;
194 lpWaveFormat->wf.nSamplesPerSec = 11025;
195 lpWaveFormat->wf.nAvgBytesPerSec = 11025;
196 lpWaveFormat->wf.nBlockAlign = 1;
198 if (MCIWavDev[wDevID].hFile != 0) {
199 MMCKINFO mmckInfo;
200 MMCKINFO ckMainRIFF;
201 if (mmioDescend(MCIWavDev[wDevID].hFile, &ckMainRIFF, NULL, 0) != 0)
202 return MCIERR_INTERNAL;
203 dprintf_mciwave(stddeb,
204 "WAVE_mciOpen // ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
205 (LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType,
206 ckMainRIFF.cksize);
207 if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
208 (ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
209 return MCIERR_INTERNAL;
210 mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
211 if (mmioDescend(MCIWavDev[wDevID].hFile, &mmckInfo, &ckMainRIFF, MMIO_FINDCHUNK) != 0)
212 return MCIERR_INTERNAL;
213 dprintf_mciwave(stddeb,
214 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
215 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
216 mmckInfo.cksize);
217 if (mmioRead(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 dprintf_mciwave(stddeb,
224 "WAVE_mciOpen // Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
225 (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType,
226 mmckInfo.cksize);
227 dprintf_mciwave(stddeb,
228 "WAVE_mciOpen // nChannels=%d nSamplesPerSec=%ld\n",
229 lpWaveFormat->wf.nChannels, lpWaveFormat->wf.nSamplesPerSec);
230 lpWaveFormat->wBitsPerSample = 0;
232 lpWaveFormat->wf.nAvgBytesPerSec =
233 lpWaveFormat->wf.nSamplesPerSec * lpWaveFormat->wf.nBlockAlign;
234 waveDesc.lpFormat = (LPWAVEFORMAT)lpWaveFormat;
237 By default the device will be opened for output, the MCI_CUE function is there to
238 change from output to input and back
241 dwRet=wodMessage(wDevID,WODM_OPEN,0,(DWORD)&waveDesc,CALLBACK_NULL);
242 return 0;
245 /**************************************************************************
246 * WAVE_mciCue [internal]
249 static DWORD WAVE_mciCue(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
252 FIXME
254 This routine is far from complete. At the moment only a check is done on the
255 MCI_WAVE_INPUT flag. No explicit check on MCI_WAVE_OUTPUT is done since that
256 is the default.
258 The flags MCI_NOTIFY (and the callback parameter in lpParms) and MCI_WAIT
259 are ignored
262 DWORD dwRet;
263 WAVEOPENDESC waveDesc;
265 dprintf_mciwave(stddeb,"WAVE_mciCue(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
267 /* always close elements ? */
269 if (MCIWavDev[wDevID].hFile != 0) {
270 mmioClose(MCIWavDev[wDevID].hFile, 0);
271 MCIWavDev[wDevID].hFile = 0;
274 dwRet = MMSYSERR_NOERROR; /* assume success */
275 if ((dwParam & MCI_WAVE_INPUT) && !MCIWavDev[wDevID].fInput) {
276 /* FIXME this is just a hack WOutDev should be hidden here */
277 memcpy(&waveDesc,&WOutDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
279 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
280 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
281 dwRet = widMessage(wDevID, WIDM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
282 MCIWavDev[wDevID].fInput = TRUE;
284 else if (MCIWavDev[wDevID].fInput) {
285 /* FIXME this is just a hack WInDev should be hidden here */
286 memcpy(&waveDesc,&WInDev[wDevID].waveDesc,sizeof(WAVEOPENDESC));
288 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
289 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
290 dwRet = wodMessage(wDevID, WODM_OPEN, 0, (DWORD)&waveDesc, CALLBACK_NULL);
291 MCIWavDev[wDevID].fInput = FALSE;
293 return dwRet;
296 /**************************************************************************
297 * WAVE_mciClose [internal]
299 static DWORD WAVE_mciClose(UINT16 wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
301 DWORD dwRet;
303 dprintf_mciwave(stddeb,
304 "WAVE_mciClose(%u, %08lX, %p);\n", wDevID, dwParam, lpParms);
305 MCIWavDev[wDevID].nUseCount--;
306 if (MCIWavDev[wDevID].nUseCount == 0) {
307 if (MCIWavDev[wDevID].hFile != 0) {
308 mmioClose(MCIWavDev[wDevID].hFile, 0);
309 MCIWavDev[wDevID].hFile = 0;
311 if (MCIWavDev[wDevID].fInput)
312 dwRet = widMessage(wDevID, WIDM_CLOSE, 0, 0L, 0L);
313 else
314 dwRet = wodMessage(wDevID, WODM_CLOSE, 0, 0L, 0L);
316 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
318 return 0;
322 /**************************************************************************
323 * WAVE_mciPlay [internal]
325 static DWORD WAVE_mciPlay(UINT16 wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
327 int start, end;
328 LONG bufsize, count;
329 HGLOBAL16 hData;
330 LPWAVEHDR lpWaveHdr;
331 DWORD dwRet;
333 dprintf_mciwave(stddeb,
334 "WAVE_mciPlay(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
336 if (MCIWavDev[wDevID].fInput) {
337 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot play on input device\n");
338 return MCIERR_NONAPPLICABLE_FUNCTION;
341 if (MCIWavDev[wDevID].hFile == 0) {
342 dprintf_mciwave(stddeb,"WAVE_mciPlay // can't find file='%08lx' !\n",
343 MCIWavDev[wDevID].openParms.lpstrElementName);
344 return MCIERR_FILE_NOT_FOUND;
346 start = 1; end = 99999;
347 if (dwFlags & MCI_FROM) {
348 start = lpParms->dwFrom;
349 dprintf_mciwave(stddeb,
350 "WAVE_mciPlay // MCI_FROM=%d \n", start);
352 if (dwFlags & MCI_TO) {
353 end = lpParms->dwTo;
354 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_TO=%d \n", end);
356 #if 0
357 if (dwFlags & MCI_NOTIFY) {
358 dprintf_mciwave(stddeb,
359 "WAVE_mciPlay // MCI_NOTIFY %08lX !\n", lpParms->dwCallback);
360 switch(fork()) {
361 case -1:
362 dprintf_mciwave(stddeb,
363 "WAVE_mciPlay // Can't 'fork' process !\n");
364 break;
365 case 0:
366 break;
367 default:
368 dprintf_mciwave(stddeb,"WAVE_mciPlay // process started ! return to caller...\n");
369 return 0;
372 #endif
373 bufsize = 64000;
374 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
375 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
376 lpWaveHdr->lpData = (LPSTR) GlobalLock16(hData);
377 lpWaveHdr->dwUser = 0L;
378 lpWaveHdr->dwFlags = 0L;
379 lpWaveHdr->dwLoops = 0L;
380 dwRet=wodMessage(wDevID,WODM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
381 while(TRUE) {
382 count = mmioRead(MCIWavDev[wDevID].hFile, lpWaveHdr->lpData, bufsize);
383 dprintf_mciwave(stddeb,"WAVE_mciPlay // mmioRead bufsize=%ld count=%ld\n", bufsize, count);
384 if (count < 1) break;
385 lpWaveHdr->dwBufferLength = count;
386 /* lpWaveHdr->dwBytesRecorded = count; */
387 dprintf_mciwave(stddeb,"WAVE_mciPlay // before WODM_WRITE lpWaveHdr=%p dwBufferLength=%lu dwBytesRecorded=%lu\n",
388 lpWaveHdr, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
389 dwRet=wodMessage(wDevID,WODM_WRITE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
391 dwRet = wodMessage(wDevID,WODM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
392 if (lpWaveHdr->lpData != NULL) {
393 GlobalUnlock16(hData);
394 GlobalFree16(hData);
395 lpWaveHdr->lpData = NULL;
397 if (dwFlags & MCI_NOTIFY) {
398 dprintf_mciwave(stddeb,"WAVE_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
399 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
400 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
402 return 0;
406 /**************************************************************************
407 * WAVE_mciRecord [internal]
409 static DWORD WAVE_mciRecord(UINT16 wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
411 int start, end;
412 LONG bufsize;
413 HGLOBAL16 hData;
414 LPWAVEHDR lpWaveHdr;
415 DWORD dwRet;
417 dprintf_mciwave(stddeb,
418 "WAVE_mciRecord(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
420 if (!MCIWavDev[wDevID].fInput) {
421 dprintf_mciwave(stddeb,"WAVE_mciPlay // cannot record on output device\n");
422 return MCIERR_NONAPPLICABLE_FUNCTION;
425 if (MCIWavDev[wDevID].hFile == 0) {
426 dprintf_mciwave(stddeb,"WAVE_mciRecord // can't find file='%08lx' !\n",
427 MCIWavDev[wDevID].openParms.lpstrElementName);
428 return MCIERR_FILE_NOT_FOUND;
430 start = 1; end = 99999;
431 if (dwFlags & MCI_FROM) {
432 start = lpParms->dwFrom;
433 dprintf_mciwave(stddeb,
434 "WAVE_mciRecord // MCI_FROM=%d \n", start);
436 if (dwFlags & MCI_TO) {
437 end = lpParms->dwTo;
438 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_TO=%d \n", end);
440 bufsize = 64000;
441 lpWaveHdr = &MCIWavDev[wDevID].WaveHdr;
442 hData = GlobalAlloc16(GMEM_MOVEABLE, bufsize);
443 lpWaveHdr->lpData = (LPSTR)GlobalLock16(hData);
444 lpWaveHdr->dwBufferLength = bufsize;
445 lpWaveHdr->dwUser = 0L;
446 lpWaveHdr->dwFlags = 0L;
447 lpWaveHdr->dwLoops = 0L;
448 dwRet=widMessage(wDevID,WIDM_PREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
449 dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_PREPARE \n");
450 while(TRUE) {
451 lpWaveHdr->dwBytesRecorded = 0;
452 dwRet = widMessage(wDevID, WIDM_START, 0, 0L, 0L);
453 dprintf_mciwave(stddeb,
454 "WAVE_mciRecord // after WIDM_START lpWaveHdr=%p dwBytesRecorded=%lu\n",
455 lpWaveHdr, lpWaveHdr->dwBytesRecorded);
456 if (lpWaveHdr->dwBytesRecorded == 0) break;
458 dprintf_mciwave(stddeb,"WAVE_mciRecord // before WIDM_UNPREPARE \n");
459 dwRet = widMessage(wDevID,WIDM_UNPREPARE,0,(DWORD)lpWaveHdr,sizeof(WAVEHDR));
460 dprintf_mciwave(stddeb,"WAVE_mciRecord // after WIDM_UNPREPARE \n");
461 if (lpWaveHdr->lpData != NULL) {
462 GlobalUnlock16(hData);
463 GlobalFree16(hData);
464 lpWaveHdr->lpData = NULL;
466 if (dwFlags & MCI_NOTIFY) {
467 dprintf_mciwave(stddeb,"WAVE_mciRecord // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
468 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
469 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
471 return 0;
475 /**************************************************************************
476 * WAVE_mciStop [internal]
478 static DWORD WAVE_mciStop(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
480 DWORD dwRet;
482 dprintf_mciwave(stddeb,
483 "WAVE_mciStop(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
484 if (lpParms == NULL) return MCIERR_INTERNAL;
485 if (MCIWavDev[wDevID].fInput)
486 dwRet = widMessage(wDevID, WIDM_STOP, 0, dwFlags, (DWORD)lpParms);
487 else
488 dwRet = wodMessage(wDevID, WODM_STOP, 0, dwFlags, (DWORD)lpParms);
490 return dwRet;
494 /**************************************************************************
495 * WAVE_mciPause [internal]
497 static DWORD WAVE_mciPause(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
499 DWORD dwRet;
501 dprintf_mciwave(stddeb,
502 "WAVE_mciPause(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
503 if (lpParms == NULL) return MCIERR_INTERNAL;
504 if (MCIWavDev[wDevID].fInput)
505 dwRet = widMessage(wDevID, WIDM_PAUSE, 0, dwFlags, (DWORD)lpParms);
506 else
507 dwRet = wodMessage(wDevID, WODM_PAUSE, 0, dwFlags, (DWORD)lpParms);
509 return dwRet;
513 /**************************************************************************
514 * WAVE_mciResume [internal]
516 static DWORD WAVE_mciResume(UINT16 wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
518 dprintf_mciwave(stddeb,
519 "WAVE_mciResume(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
520 if (lpParms == NULL) return MCIERR_INTERNAL;
521 return 0;
525 /**************************************************************************
526 * WAVE_mciSet [internal]
528 static DWORD WAVE_mciSet(UINT16 wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
530 dprintf_mciwave(stddeb,
531 "WAVE_mciSet(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
532 if (lpParms == NULL) return MCIERR_INTERNAL;
533 dprintf_mciwave(stddeb,
534 "WAVE_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
535 dprintf_mciwave(stddeb,
536 "WAVE_mciSet // dwAudio=%08lX\n", lpParms->dwAudio);
537 if (dwFlags & MCI_SET_TIME_FORMAT) {
538 switch (lpParms->dwTimeFormat) {
539 case MCI_FORMAT_MILLISECONDS:
540 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_MILLISECONDS !\n");
541 break;
542 case MCI_FORMAT_BYTES:
543 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_BYTES !\n");
544 break;
545 case MCI_FORMAT_SAMPLES:
546 dprintf_mciwave(stddeb, "WAVE_mciSet // MCI_FORMAT_SAMPLES !\n");
547 break;
548 default:
549 dprintf_mciwave(stddeb, "WAVE_mciSet // bad time format !\n");
550 return MCIERR_BAD_TIME_FORMAT;
553 if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
554 if (dwFlags & MCI_SET_DOOR_OPEN) return MCIERR_UNSUPPORTED_FUNCTION;
555 if (dwFlags & MCI_SET_DOOR_CLOSED) return MCIERR_UNSUPPORTED_FUNCTION;
556 if (dwFlags & MCI_SET_AUDIO)
557 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO !\n");
558 if (dwFlags && MCI_SET_ON) {
559 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_ON !\n");
560 if (dwFlags && MCI_SET_AUDIO_LEFT)
561 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_LEFT !\n");
562 if (dwFlags && MCI_SET_AUDIO_RIGHT)
563 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_AUDIO_RIGHT !\n");
565 if (dwFlags & MCI_SET_OFF)
566 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_SET_OFF !\n");
567 if (dwFlags & MCI_WAVE_INPUT)
568 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_INPUT !\n");
569 if (dwFlags & MCI_WAVE_OUTPUT)
570 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_OUTPUT !\n");
571 if (dwFlags & MCI_WAVE_SET_ANYINPUT)
572 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYINPUT !\n");
573 if (dwFlags & MCI_WAVE_SET_ANYOUTPUT)
574 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_ANYOUTPUT !\n");
575 if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC)
576 dprintf_mciwave(stddeb,
577 "WAVE_mciSet // MCI_WAVE_SET_AVGBYTESPERSEC !\n");
578 if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE)
579 dprintf_mciwave(stddeb,
580 "WAVE_mciSet // MCI_WAVE_SET_BITSPERSAMPLE !\n");
581 if (dwFlags & MCI_WAVE_SET_BLOCKALIGN)
582 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_BLOCKALIGN !\n");
583 if (dwFlags & MCI_WAVE_SET_CHANNELS)
584 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_CHANNELS !\n");
585 if (dwFlags & MCI_WAVE_SET_FORMATTAG)
586 dprintf_mciwave(stddeb,"WAVE_mciSet // MCI_WAVE_SET_FORMATTAG !\n");
587 if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC)
588 dprintf_mciwave(stddeb,
589 "WAVE_mciSet // MCI_WAVE_SET_SAMPLESPERSEC !\n");
590 return 0;
594 /**************************************************************************
595 * WAVE_mciStatus [internal]
597 static DWORD WAVE_mciStatus(UINT16 wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
599 dprintf_mciwave(stddeb,
600 "WAVE_mciStatus(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
601 if (lpParms == NULL) return MCIERR_INTERNAL;
602 if (dwFlags & MCI_STATUS_ITEM) {
603 switch(lpParms->dwItem) {
604 case MCI_STATUS_CURRENT_TRACK:
605 lpParms->dwReturn = 1;
606 break;
607 case MCI_STATUS_LENGTH:
608 lpParms->dwReturn = 5555;
609 if (dwFlags & MCI_TRACK) {
610 lpParms->dwTrack = 1;
611 lpParms->dwReturn = 2222;
613 break;
614 case MCI_STATUS_MODE:
615 lpParms->dwReturn = MCI_MODE_STOP;
616 break;
617 case MCI_STATUS_MEDIA_PRESENT:
618 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n");
619 lpParms->dwReturn = TRUE;
620 break;
621 case MCI_STATUS_NUMBER_OF_TRACKS:
622 lpParms->dwReturn = 1;
623 break;
624 case MCI_STATUS_POSITION:
625 lpParms->dwReturn = 3333;
626 if (dwFlags & MCI_STATUS_START)
627 lpParms->dwItem = 1;
628 if (dwFlags & MCI_TRACK) {
629 lpParms->dwTrack = 1;
630 lpParms->dwReturn = 777;
632 break;
633 case MCI_STATUS_READY:
634 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_READY !\n");
635 lpParms->dwReturn = TRUE;
636 break;
637 case MCI_STATUS_TIME_FORMAT:
638 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
639 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
640 break;
641 case MCI_WAVE_INPUT:
642 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_INPUT !\n");
643 lpParms->dwReturn = 0;
644 break;
645 case MCI_WAVE_OUTPUT:
646 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_OUTPUT !\n");
647 lpParms->dwReturn = 0;
648 break;
649 case MCI_WAVE_STATUS_AVGBYTESPERSEC:
650 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_AVGBYTESPERSEC !\n");
651 lpParms->dwReturn = 22050;
652 break;
653 case MCI_WAVE_STATUS_BITSPERSAMPLE:
654 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BITSPERSAMPLE !\n");
655 lpParms->dwReturn = 8;
656 break;
657 case MCI_WAVE_STATUS_BLOCKALIGN:
658 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_BLOCKALIGN !\n");
659 lpParms->dwReturn = 1;
660 break;
661 case MCI_WAVE_STATUS_CHANNELS:
662 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_CHANNELS !\n");
663 lpParms->dwReturn = 1;
664 break;
665 case MCI_WAVE_STATUS_FORMATTAG:
666 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_FORMATTAG !\n");
667 lpParms->dwReturn = WAVE_FORMAT_PCM;
668 break;
669 case MCI_WAVE_STATUS_LEVEL:
670 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_LEVEL !\n");
671 lpParms->dwReturn = 0xAAAA5555;
672 break;
673 case MCI_WAVE_STATUS_SAMPLESPERSEC:
674 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_WAVE_STATUS_SAMPLESPERSEC !\n");
675 lpParms->dwReturn = 22050;
676 break;
677 default:
678 dprintf_mciwave(stddeb,"WAVE_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
679 return MCIERR_UNRECOGNIZED_COMMAND;
682 if (dwFlags & MCI_NOTIFY) {
683 dprintf_mciwave(stddeb,"WAVE_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms->dwCallback);
684 mciDriverNotify((HWND16)LOWORD(lpParms->dwCallback),
685 MCIWavDev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
687 return 0;
690 /**************************************************************************
691 * WAVE_mciGetDevCaps [internal]
693 static DWORD WAVE_mciGetDevCaps(UINT16 wDevID, DWORD dwFlags,
694 LPMCI_GETDEVCAPS_PARMS lpParms)
696 dprintf_mciwave(stddeb,
697 "WAVE_mciGetDevCaps(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
698 if (lpParms == NULL) return MCIERR_INTERNAL;
699 if (dwFlags & MCI_GETDEVCAPS_ITEM) {
700 switch(lpParms->dwItem) {
701 case MCI_GETDEVCAPS_CAN_RECORD:
702 lpParms->dwReturn = TRUE;
703 break;
704 case MCI_GETDEVCAPS_HAS_AUDIO:
705 lpParms->dwReturn = TRUE;
706 break;
707 case MCI_GETDEVCAPS_HAS_VIDEO:
708 lpParms->dwReturn = FALSE;
709 break;
710 case MCI_GETDEVCAPS_DEVICE_TYPE:
711 lpParms->dwReturn = MCI_DEVTYPE_WAVEFORM_AUDIO;
712 break;
713 case MCI_GETDEVCAPS_USES_FILES:
714 lpParms->dwReturn = TRUE;
715 break;
716 case MCI_GETDEVCAPS_COMPOUND_DEVICE:
717 lpParms->dwReturn = TRUE;
718 break;
719 case MCI_GETDEVCAPS_CAN_EJECT:
720 lpParms->dwReturn = FALSE;
721 break;
722 case MCI_GETDEVCAPS_CAN_PLAY:
723 lpParms->dwReturn = TRUE;
724 break;
725 case MCI_GETDEVCAPS_CAN_SAVE:
726 lpParms->dwReturn = TRUE;
727 break;
728 case MCI_WAVE_GETDEVCAPS_INPUTS:
729 lpParms->dwReturn = 1;
730 break;
731 case MCI_WAVE_GETDEVCAPS_OUTPUTS:
732 lpParms->dwReturn = 1;
733 break;
734 default:
735 return MCIERR_UNRECOGNIZED_COMMAND;
738 return 0;
741 /**************************************************************************
742 * WAVE_mciInfo [internal]
744 static DWORD WAVE_mciInfo(UINT16 wDevID, DWORD dwFlags, LPMCI_INFO_PARMS16 lpParms)
746 dprintf_mciwave(stddeb,
747 "WAVE_mciInfo(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
748 if (lpParms == NULL) return MCIERR_INTERNAL;
749 lpParms->lpstrReturn = NULL;
750 switch(dwFlags) {
751 case MCI_INFO_PRODUCT:
752 lpParms->lpstrReturn = "Linux Sound System 0.5";
753 break;
754 case MCI_INFO_FILE:
755 lpParms->lpstrReturn =
756 (LPSTR)MCIWavDev[wDevID].openParms.lpstrElementName;
757 break;
758 case MCI_WAVE_INPUT:
759 lpParms->lpstrReturn = "Linux Sound System 0.5";
760 break;
761 case MCI_WAVE_OUTPUT:
762 lpParms->lpstrReturn = "Linux Sound System 0.5";
763 break;
764 default:
765 return MCIERR_UNRECOGNIZED_COMMAND;
767 if (lpParms->lpstrReturn != NULL)
768 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
769 else
770 lpParms->dwRetSize = 0;
771 return 0;
775 /*-----------------------------------------------------------------------*/
778 /**************************************************************************
779 * wodGetDevCaps [internal]
781 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPS16 lpCaps, DWORD dwSize)
783 int audio;
784 int smplrate;
785 int samplesize = 16;
786 int dsp_stereo = 1;
787 int bytespersmpl;
789 dprintf_mciwave(stddeb,
790 "wodGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
791 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
792 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
793 audio = open (SOUND_DEV, O_WRONLY, 0);
794 if (audio == -1) return MMSYSERR_ALLOCATED ;
795 #ifdef EMULATE_SB16
796 lpCaps->wMid = 0x0002;
797 lpCaps->wPid = 0x0104;
798 strcpy(lpCaps->szPname, "SB16 Wave Out");
799 #else
800 lpCaps->wMid = 0x00FF; /* Manufac ID */
801 lpCaps->wPid = 0x0001; /* Product ID */
802 strcpy(lpCaps->szPname, "Linux WAVOUT Driver");
803 #endif
804 lpCaps->vDriverVersion = 0x0100;
805 lpCaps->dwFormats = 0x00000000;
806 lpCaps->dwSupport = WAVECAPS_VOLUME;
807 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
808 if (lpCaps->wChannels > 1) lpCaps->dwSupport |= WAVECAPS_LRVOLUME;
809 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
810 smplrate = 44100;
811 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
812 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
813 if (lpCaps->wChannels > 1)
814 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
815 if (bytespersmpl > 1) {
816 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
817 if (lpCaps->wChannels > 1)
818 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
821 smplrate = 22050;
822 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
823 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
824 if (lpCaps->wChannels > 1)
825 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
826 if (bytespersmpl > 1) {
827 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
828 if (lpCaps->wChannels > 1)
829 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
832 smplrate = 11025;
833 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
834 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
835 if (lpCaps->wChannels > 1)
836 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
837 if (bytespersmpl > 1) {
838 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
839 if (lpCaps->wChannels > 1)
840 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
843 close(audio);
844 dprintf_mciwave(stddeb,
845 "wodGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
846 return MMSYSERR_NOERROR;
850 /**************************************************************************
851 * wodOpen [internal]
853 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
855 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
856 LPWAVEFORMAT lpFormat;
858 dprintf_mciwave(stddeb,
859 "wodOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
860 if (lpDesc == NULL) {
861 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Invalid Parameter !\n");
862 return MMSYSERR_INVALPARAM;
864 if (wDevID >= MAX_WAVOUTDRV) {
865 dprintf_mciwave(stddeb,"Linux 'wodOpen' // MAX_WAVOUTDRV reached !\n");
866 return MMSYSERR_ALLOCATED;
868 WOutDev[wDevID].unixdev = 0;
869 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
870 audio = open (SOUND_DEV, O_WRONLY, 0);
871 if (audio == -1) {
872 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't open !\n");
873 return MMSYSERR_ALLOCATED ;
875 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
876 if (abuf_size < 1024 || abuf_size > 65536) {
877 if (abuf_size == -1)
878 dprintf_mciwave(stddeb,"Linux 'wodOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
879 else
880 dprintf_mciwave(stddeb,"Linux 'wodOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
881 return MMSYSERR_NOTENABLED;
883 WOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
884 switch(WOutDev[wDevID].wFlags) {
885 case DCB_NULL:
886 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_NULL !\n");
887 break;
888 case DCB_WINDOW:
889 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_WINDOW !\n");
890 break;
891 case DCB_TASK:
892 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_TASK !\n");
893 break;
894 case DCB_FUNCTION:
895 dprintf_mciwave(stddeb, "Linux 'wodOpen' // CALLBACK_FUNCTION !\n");
896 break;
898 WOutDev[wDevID].lpQueueHdr = NULL;
899 WOutDev[wDevID].unixdev = audio;
900 WOutDev[wDevID].dwTotalPlayed = 0;
901 WOutDev[wDevID].bufsize = abuf_size;
902 /* FIXME: copy lpFormat too? */
903 memcpy(&WOutDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
904 dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpDesc->lpFormat = %p\n",lpDesc->lpFormat);
905 lpFormat = lpDesc->lpFormat;
906 dprintf_mciwave(stddeb,"Linux 'wodOpen' // lpFormat = %p\n",lpFormat);
907 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
908 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad format %04X !\n",
909 lpFormat->wFormatTag);
910 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nChannels %d !\n",
911 lpFormat->nChannels);
912 dprintf_mciwave(stddeb,"Linux 'wodOpen' // Bad nSamplesPerSec %ld !\n",
913 lpFormat->nSamplesPerSec);
914 return WAVERR_BADFORMAT;
916 memcpy(&WOutDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
917 if (WOutDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
918 if (WOutDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
919 dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
920 WOutDev[wDevID].Format.wBitsPerSample);
921 if (WOutDev[wDevID].Format.wBitsPerSample == 0) {
922 WOutDev[wDevID].Format.wBitsPerSample = 8 *
923 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec /
924 WOutDev[wDevID].Format.wf.nSamplesPerSec) /
925 WOutDev[wDevID].Format.wf.nChannels;
927 samplesize = WOutDev[wDevID].Format.wBitsPerSample;
928 smplrate = WOutDev[wDevID].Format.wf.nSamplesPerSec;
929 dsp_stereo = (WOutDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
930 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
931 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
932 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
933 dprintf_mciwave(stddeb,"Linux 'wodOpen' // wBitsPerSample=%u !\n",
934 WOutDev[wDevID].Format.wBitsPerSample);
935 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nAvgBytesPerSec=%lu !\n",
936 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
937 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nSamplesPerSec=%lu !\n",
938 WOutDev[wDevID].Format.wf.nSamplesPerSec);
939 dprintf_mciwave(stddeb,"Linux 'wodOpen' // nChannels=%u !\n",
940 WOutDev[wDevID].Format.wf.nChannels);
941 if (WAVE_NotifyClient(wDevID, WOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
942 dprintf_mciwave(stddeb,"Linux 'wodOpen' // can't notify client !\n");
943 return MMSYSERR_INVALPARAM;
945 return MMSYSERR_NOERROR;
948 /**************************************************************************
949 * wodClose [internal]
951 static DWORD wodClose(WORD wDevID)
953 dprintf_mciwave(stddeb,"wodClose(%u);\n", wDevID);
954 if (wDevID > MAX_WAVOUTDRV) return MMSYSERR_INVALPARAM;
955 if (WOutDev[wDevID].unixdev == 0) {
956 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't close !\n");
957 return MMSYSERR_NOTENABLED;
959 if (WOutDev[wDevID].lpQueueHdr != NULL) {
960 dprintf_mciwave(stddeb,"linux 'wodclose' // still buffers open !\n");
961 /* Don't care. Who needs those buffers anyway */
962 /*return WAVERR_STILLPLAYING; */
964 close(WOutDev[wDevID].unixdev);
965 WOutDev[wDevID].unixdev = 0;
966 WOutDev[wDevID].bufsize = 0;
967 WOutDev[wDevID].lpQueueHdr = NULL;
968 if (WAVE_NotifyClient(wDevID, WOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
969 dprintf_mciwave(stddeb,"Linux 'wodClose' // can't notify client !\n");
970 return MMSYSERR_INVALPARAM;
972 return MMSYSERR_NOERROR;
975 /**************************************************************************
976 * wodWrite [internal]
977 * FIXME: this should _APPEND_ the lpWaveHdr to the output queue of the
978 * device, and initiate async playing.
980 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
982 int count;
983 LPSTR lpData;
984 LPWAVEHDR xwavehdr;
986 dprintf_mciwave(stddeb,"wodWrite(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
987 if (WOutDev[wDevID].unixdev == 0) {
988 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't play !\n");
989 return MMSYSERR_NOTENABLED;
991 if (lpWaveHdr->lpData == NULL) return WAVERR_UNPREPARED;
992 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) return WAVERR_UNPREPARED;
993 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) return WAVERR_STILLPLAYING;
994 lpWaveHdr->dwFlags &= ~WHDR_DONE;
995 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
996 dprintf_mciwave(stddeb,
997 "wodWrite() // dwBufferLength %lu !\n", lpWaveHdr->dwBufferLength);
998 dprintf_mciwave(stddeb,
999 "wodWrite() // WOutDev[%u].unixdev %u !\n", wDevID, WOutDev[wDevID].unixdev);
1000 lpData = lpWaveHdr->lpData;
1001 count = write (WOutDev[wDevID].unixdev, lpData, lpWaveHdr->dwBufferLength);
1002 dprintf_mciwave(stddeb,"wodWrite()//write returned count %u !\n",count);
1003 if (count != lpWaveHdr->dwBufferLength) {
1004 dprintf_mciwave(stddeb,"Linux 'wodWrite' // error writting !\n");
1005 return MMSYSERR_NOTENABLED;
1007 WOutDev[wDevID].dwTotalPlayed += count;
1008 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1009 lpWaveHdr->dwFlags |= WHDR_DONE;
1010 if ((DWORD)lpWaveHdr->lpData!=lpWaveHdr->reserved) {
1011 /* FIXME: what if it expects it's OWN lpwavehdr back? */
1012 xwavehdr = SEGPTR_NEW(WAVEHDR);
1013 memcpy(xwavehdr,lpWaveHdr,sizeof(WAVEHDR));
1014 xwavehdr->lpData = (LPBYTE)xwavehdr->reserved;
1015 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)SEGPTR_GET(xwavehdr), count) != MMSYSERR_NOERROR) {
1016 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
1017 SEGPTR_FREE(xwavehdr);
1018 return MMSYSERR_INVALPARAM;
1020 SEGPTR_FREE(xwavehdr);
1021 } else {
1022 if (WAVE_NotifyClient(wDevID, WOM_DONE, (DWORD)lpWaveHdr, count) != MMSYSERR_NOERROR) {
1023 dprintf_mciwave(stddeb,"Linux 'wodWrite' // can't notify client !\n");
1024 return MMSYSERR_INVALPARAM;
1027 return MMSYSERR_NOERROR;
1030 /**************************************************************************
1031 * wodPrepare [internal]
1033 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1035 dprintf_mciwave(stddeb,
1036 "wodPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1037 if (WOutDev[wDevID].unixdev == 0) {
1038 dprintf_mciwave(stddeb,"Linux 'wodPrepare' // can't prepare !\n");
1039 return MMSYSERR_NOTENABLED;
1041 /* don't append to queue, wodWrite does that */
1042 WOutDev[wDevID].dwTotalPlayed = 0;
1043 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1044 return WAVERR_STILLPLAYING;
1045 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1046 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1047 return MMSYSERR_NOERROR;
1050 /**************************************************************************
1051 * wodUnprepare [internal]
1053 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1055 dprintf_mciwave(stddeb,
1056 "wodUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1057 if (WOutDev[wDevID].unixdev == 0) {
1058 dprintf_mciwave(stddeb,"Linux 'wodUnprepare' // can't unprepare !\n");
1059 return MMSYSERR_NOTENABLED;
1061 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1062 return WAVERR_STILLPLAYING;
1064 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1065 lpWaveHdr->dwFlags |= WHDR_DONE;
1066 dprintf_mciwave(stddeb,
1067 "Linux 'wodUnprepare' // all headers unprepared !\n");
1068 return MMSYSERR_NOERROR;
1071 /**************************************************************************
1072 * wodRestart [internal]
1074 static DWORD wodRestart(WORD wDevID)
1076 dprintf_mciwave(stddeb,"wodRestart(%u);\n", wDevID);
1077 if (WOutDev[wDevID].unixdev == 0) {
1078 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't restart !\n");
1079 return MMSYSERR_NOTENABLED;
1081 /* FIXME: is NotifyClient with WOM_DONE right ? (Comet Busters 1.3.3 needs this notification) */
1082 if (WAVE_NotifyClient(wDevID, WOM_DONE, 0L, 0L) != MMSYSERR_NOERROR) {
1083 dprintf_mciwave(stddeb,"Linux 'wodRestart' // can't notify client !\n");
1084 return MMSYSERR_INVALPARAM;
1087 return MMSYSERR_NOERROR;
1090 /**************************************************************************
1091 * wodReset [internal]
1093 static DWORD wodReset(WORD wDevID)
1095 dprintf_mciwave(stddeb,"wodReset(%u);\n", wDevID);
1096 if (WOutDev[wDevID].unixdev == 0) {
1097 dprintf_mciwave(stddeb,"Linux 'wodReset' // can't reset !\n");
1098 return MMSYSERR_NOTENABLED;
1100 return MMSYSERR_NOERROR;
1104 /**************************************************************************
1105 * wodGetPosition [internal]
1107 static DWORD wodGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1109 int time;
1110 dprintf_mciwave(stddeb,"wodGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1111 if (WOutDev[wDevID].unixdev == 0) {
1112 dprintf_mciwave(stddeb,"Linux 'wodGetPosition' // can't get pos !\n");
1113 return MMSYSERR_NOTENABLED;
1115 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1116 dprintf_mciwave(stddeb,"wodGetPosition // wType=%04X !\n",
1117 lpTime->wType);
1118 dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n",
1119 WOutDev[wDevID].Format.wBitsPerSample);
1120 dprintf_mciwave(stddeb,"wodGetPosition // nSamplesPerSec=%lu\n",
1121 WOutDev[wDevID].Format.wf.nSamplesPerSec);
1122 dprintf_mciwave(stddeb,"wodGetPosition // nChannels=%u\n",
1123 WOutDev[wDevID].Format.wf.nChannels);
1124 dprintf_mciwave(stddeb,"wodGetPosition // nAvgBytesPerSec=%lu\n",
1125 WOutDev[wDevID].Format.wf.nAvgBytesPerSec);
1126 switch(lpTime->wType) {
1127 case TIME_BYTES:
1128 lpTime->u.cb = WOutDev[wDevID].dwTotalPlayed;
1129 dprintf_mciwave(stddeb,"wodGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1130 break;
1131 case TIME_SAMPLES:
1132 dprintf_mciwave(stddeb,"wodGetPosition // dwTotalPlayed=%lu\n",
1133 WOutDev[wDevID].dwTotalPlayed);
1134 dprintf_mciwave(stddeb,"wodGetPosition // wBitsPerSample=%u\n",
1135 WOutDev[wDevID].Format.wBitsPerSample);
1136 lpTime->u.sample = WOutDev[wDevID].dwTotalPlayed * 8 /
1137 WOutDev[wDevID].Format.wBitsPerSample;
1138 dprintf_mciwave(stddeb,"wodGetPosition // TIME_SAMPLES=%lu\n", lpTime->u.sample);
1139 break;
1140 case TIME_SMPTE:
1141 time = WOutDev[wDevID].dwTotalPlayed /
1142 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1143 lpTime->u.smpte.hour = time / 108000;
1144 time -= lpTime->u.smpte.hour * 108000;
1145 lpTime->u.smpte.min = time / 1800;
1146 time -= lpTime->u.smpte.min * 1800;
1147 lpTime->u.smpte.sec = time / 30;
1148 time -= lpTime->u.smpte.sec * 30;
1149 lpTime->u.smpte.frame = time;
1150 lpTime->u.smpte.fps = 30;
1151 dprintf_mciwave(stddeb,
1152 "wodGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1153 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1154 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1155 break;
1156 default:
1157 dprintf_mciwave(stddeb,"wodGetPosition() format not supported ! use TIME_MS !\n");
1158 lpTime->wType = TIME_MS;
1159 case TIME_MS:
1160 lpTime->u.ms = WOutDev[wDevID].dwTotalPlayed /
1161 (WOutDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1162 dprintf_mciwave(stddeb,"wodGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1163 break;
1165 return MMSYSERR_NOERROR;
1168 /**************************************************************************
1169 * wodGetVolume [internal]
1171 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1173 int mixer;
1174 int volume, left, right;
1175 dprintf_mciwave(stddeb,"wodGetVolume(%u, %p);\n", wDevID, lpdwVol);
1176 if (lpdwVol == NULL) return MMSYSERR_NOTENABLED;
1177 if ((mixer = open(MIXER_DEV, O_RDONLY)) < 0) {
1178 dprintf_mciwave(stddeb, "Linux 'wodGetVolume' // mixer device not available !\n");
1179 return MMSYSERR_NOTENABLED;
1181 if (ioctl(mixer, SOUND_MIXER_READ_PCM, &volume) == -1) {
1182 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // unable read mixer !\n");
1183 return MMSYSERR_NOTENABLED;
1185 close(mixer);
1186 left = volume & 0x7F;
1187 right = (volume >> 8) & 0x7F;
1188 dprintf_mciwave(stddeb,"Linux 'wodGetVolume' // left=%d right=%d !\n", left, right);
1189 *lpdwVol = MAKELONG(left << 9, right << 9);
1190 return MMSYSERR_NOERROR;
1194 /**************************************************************************
1195 * wodSetVolume [internal]
1197 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1199 int mixer;
1200 int volume;
1201 dprintf_mciwave(stddeb,"wodSetVolume(%u, %08lX);\n", wDevID, dwParam);
1202 volume = (LOWORD(dwParam) >> 9 & 0x7F) +
1203 ((HIWORD(dwParam) >> 9 & 0x7F) << 8);
1204 if ((mixer = open(MIXER_DEV, O_WRONLY)) < 0) {
1205 dprintf_mciwave(stddeb, "Linux 'wodSetVolume' // mixer device not available !\n");
1206 return MMSYSERR_NOTENABLED;
1208 if (ioctl(mixer, SOUND_MIXER_WRITE_PCM, &volume) == -1) {
1209 dprintf_mciwave(stddeb,"Linux 'wodSetVolume' // unable set mixer !\n");
1210 return MMSYSERR_NOTENABLED;
1212 close(mixer);
1213 return MMSYSERR_NOERROR;
1216 #endif /* linux || __FreeBSD__*/
1218 /**************************************************************************
1219 * wodMessage [sample driver]
1221 DWORD wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1222 DWORD dwParam1, DWORD dwParam2)
1224 dprintf_mciwave(stddeb,"wodMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1225 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1226 #if defined(linux) || defined(__FreeBSD__)
1227 switch(wMsg) {
1228 case WODM_OPEN:
1229 return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1230 case WODM_CLOSE:
1231 return wodClose(wDevID);
1232 case WODM_WRITE:
1233 return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1234 case WODM_PAUSE:
1235 return MMSYSERR_NOTSUPPORTED;
1236 case WODM_STOP:
1237 return MMSYSERR_NOTSUPPORTED;
1238 case WODM_GETPOS:
1239 return wodGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1240 case WODM_BREAKLOOP:
1241 return MMSYSERR_NOTSUPPORTED;
1242 case WODM_PREPARE:
1243 return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1244 case WODM_UNPREPARE:
1245 return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1246 case WODM_GETDEVCAPS:
1247 return wodGetDevCaps(wDevID,(LPWAVEOUTCAPS16)dwParam1,dwParam2);
1248 case WODM_GETNUMDEVS:
1249 return 1L;
1250 case WODM_GETPITCH:
1251 return MMSYSERR_NOTSUPPORTED;
1252 case WODM_SETPITCH:
1253 return MMSYSERR_NOTSUPPORTED;
1254 case WODM_GETPLAYBACKRATE:
1255 return MMSYSERR_NOTSUPPORTED;
1256 case WODM_SETPLAYBACKRATE:
1257 return MMSYSERR_NOTSUPPORTED;
1258 case WODM_GETVOLUME:
1259 return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1260 case WODM_SETVOLUME:
1261 return wodSetVolume(wDevID, dwParam1);
1262 case WODM_RESTART:
1263 return wodRestart(wDevID);
1264 case WODM_RESET:
1265 return wodReset(wDevID);
1266 default:
1267 dprintf_mciwave(stddeb,"wodMessage // unknown message !\n");
1269 return MMSYSERR_NOTSUPPORTED;
1270 #else
1271 return MMSYSERR_NOTENABLED;
1272 #endif
1276 /*-----------------------------------------------------------------------*/
1278 #if defined(linux) || defined(__FreeBSD__)
1280 /**************************************************************************
1281 * widGetDevCaps [internal]
1283 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPS16 lpCaps, DWORD dwSize)
1285 int audio,smplrate,samplesize=16,dsp_stereo=1,bytespersmpl;
1287 dprintf_mciwave(stddeb,
1288 "widGetDevCaps(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1289 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1290 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1291 audio = open (SOUND_DEV, O_RDONLY, 0);
1292 if (audio == -1) return MMSYSERR_ALLOCATED ;
1293 #ifdef EMULATE_SB16
1294 lpCaps->wMid = 0x0002;
1295 lpCaps->wPid = 0x0004;
1296 strcpy(lpCaps->szPname, "SB16 Wave In");
1297 #else
1298 lpCaps->wMid = 0x00FF; /* Manufac ID */
1299 lpCaps->wPid = 0x0001; /* Product ID */
1300 strcpy(lpCaps->szPname, "Linux WAVIN Driver");
1301 #endif
1302 lpCaps->dwFormats = 0x00000000;
1303 lpCaps->wChannels = (IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo) != 0) ? 1 : 2;
1304 bytespersmpl = (IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize) != 0) ? 1 : 2;
1305 smplrate = 44100;
1306 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1307 lpCaps->dwFormats |= WAVE_FORMAT_4M08;
1308 if (lpCaps->wChannels > 1)
1309 lpCaps->dwFormats |= WAVE_FORMAT_4S08;
1310 if (bytespersmpl > 1) {
1311 lpCaps->dwFormats |= WAVE_FORMAT_4M16;
1312 if (lpCaps->wChannels > 1)
1313 lpCaps->dwFormats |= WAVE_FORMAT_4S16;
1316 smplrate = 22050;
1317 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1318 lpCaps->dwFormats |= WAVE_FORMAT_2M08;
1319 if (lpCaps->wChannels > 1)
1320 lpCaps->dwFormats |= WAVE_FORMAT_2S08;
1321 if (bytespersmpl > 1) {
1322 lpCaps->dwFormats |= WAVE_FORMAT_2M16;
1323 if (lpCaps->wChannels > 1)
1324 lpCaps->dwFormats |= WAVE_FORMAT_2S16;
1327 smplrate = 11025;
1328 if (IOCTL(audio, SNDCTL_DSP_SPEED, smplrate) == 0) {
1329 lpCaps->dwFormats |= WAVE_FORMAT_1M08;
1330 if (lpCaps->wChannels > 1)
1331 lpCaps->dwFormats |= WAVE_FORMAT_1S08;
1332 if (bytespersmpl > 1) {
1333 lpCaps->dwFormats |= WAVE_FORMAT_1M16;
1334 if (lpCaps->wChannels > 1)
1335 lpCaps->dwFormats |= WAVE_FORMAT_1S16;
1338 close(audio);
1339 dprintf_mciwave(stddeb,
1340 "widGetDevCaps // dwFormats = %08lX\n", lpCaps->dwFormats);
1341 return MMSYSERR_NOERROR;
1345 /**************************************************************************
1346 * widOpen [internal]
1348 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1350 int audio,abuf_size,smplrate,samplesize,dsp_stereo;
1351 LPWAVEFORMAT lpFormat;
1353 dprintf_mciwave(stddeb, "widOpen(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1354 if (lpDesc == NULL) {
1355 dprintf_mciwave(stddeb,"Linux 'widOpen' // Invalid Parameter !\n");
1356 return MMSYSERR_INVALPARAM;
1358 if (wDevID >= MAX_WAVINDRV) {
1359 dprintf_mciwave(stddeb,"Linux 'widOpen' // MAX_WAVINDRV reached !\n");
1360 return MMSYSERR_ALLOCATED;
1362 WInDev[wDevID].unixdev = 0;
1363 if (access(SOUND_DEV,0) != 0) return MMSYSERR_NOTENABLED;
1364 audio = open (SOUND_DEV, O_RDONLY, 0);
1365 if (audio == -1) {
1366 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't open !\n");
1367 return MMSYSERR_ALLOCATED;
1369 IOCTL(audio, SNDCTL_DSP_GETBLKSIZE, abuf_size);
1370 if (abuf_size < 1024 || abuf_size > 65536) {
1371 if (abuf_size == -1)
1372 dprintf_mciwave(stddeb,"Linux 'widOpen' // IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
1373 else
1374 dprintf_mciwave(stddeb,"Linux 'widOpen' // SNDCTL_DSP_GETBLKSIZE Invalid bufsize !\n");
1375 return MMSYSERR_NOTENABLED;
1377 WInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1378 switch(WInDev[wDevID].wFlags) {
1379 case DCB_NULL:
1380 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_NULL!\n");
1381 break;
1382 case DCB_WINDOW:
1383 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_WINDOW!\n");
1384 break;
1385 case DCB_TASK:
1386 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_TASK!\n");
1387 break;
1388 case DCB_FUNCTION:
1389 dprintf_mciwave(stddeb,"Linux 'widOpen' // CALLBACK_FUNCTION!\n");
1390 break;
1392 if (WInDev[wDevID].lpQueueHdr) {
1393 HeapFree(GetProcessHeap(),0,WInDev[wDevID].lpQueueHdr);
1394 WInDev[wDevID].lpQueueHdr = NULL;
1396 WInDev[wDevID].unixdev = audio;
1397 WInDev[wDevID].bufsize = abuf_size;
1398 WInDev[wDevID].dwTotalRecorded = 0;
1399 memcpy(&WInDev[wDevID].waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1400 lpFormat = (LPWAVEFORMAT) lpDesc->lpFormat;
1401 if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
1402 dprintf_mciwave(stddeb,"Linux 'widOpen' // Bad format %04X !\n",
1403 lpFormat->wFormatTag);
1404 return WAVERR_BADFORMAT;
1406 memcpy(&WInDev[wDevID].Format, lpFormat, sizeof(PCMWAVEFORMAT));
1407 WInDev[wDevID].Format.wBitsPerSample = 8; /* <-------------- */
1408 if (WInDev[wDevID].Format.wf.nChannels == 0) return WAVERR_BADFORMAT;
1409 if (WInDev[wDevID].Format.wf.nSamplesPerSec == 0) return WAVERR_BADFORMAT;
1410 if (WInDev[wDevID].Format.wBitsPerSample == 0) {
1411 WInDev[wDevID].Format.wBitsPerSample = 8 *
1412 (WInDev[wDevID].Format.wf.nAvgBytesPerSec /
1413 WInDev[wDevID].Format.wf.nSamplesPerSec) /
1414 WInDev[wDevID].Format.wf.nChannels;
1416 samplesize = WInDev[wDevID].Format.wBitsPerSample;
1417 smplrate = WInDev[wDevID].Format.wf.nSamplesPerSec;
1418 dsp_stereo = (WInDev[wDevID].Format.wf.nChannels > 1) ? TRUE : FALSE;
1419 IOCTL(audio, SNDCTL_DSP_SPEED, smplrate);
1420 IOCTL(audio, SNDCTL_DSP_SAMPLESIZE, samplesize);
1421 IOCTL(audio, SNDCTL_DSP_STEREO, dsp_stereo);
1422 dprintf_mciwave(stddeb,"Linux 'widOpen' // wBitsPerSample=%u !\n",
1423 WInDev[wDevID].Format.wBitsPerSample);
1424 dprintf_mciwave(stddeb,"Linux 'widOpen' // nSamplesPerSec=%lu !\n",
1425 WInDev[wDevID].Format.wf.nSamplesPerSec);
1426 dprintf_mciwave(stddeb,"Linux 'widOpen' // nChannels=%u !\n",
1427 WInDev[wDevID].Format.wf.nChannels);
1428 dprintf_mciwave(stddeb,"Linux 'widOpen' // nAvgBytesPerSec=%lu\n",
1429 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1430 if (WAVE_NotifyClient(wDevID, WIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1431 dprintf_mciwave(stddeb,"Linux 'widOpen' // can't notify client !\n");
1432 return MMSYSERR_INVALPARAM;
1434 return MMSYSERR_NOERROR;
1437 /**************************************************************************
1438 * widClose [internal]
1440 static DWORD widClose(WORD wDevID)
1442 dprintf_mciwave(stddeb,"widClose(%u);\n", wDevID);
1443 if (wDevID > MAX_WAVINDRV) return MMSYSERR_INVALPARAM;
1444 if (WInDev[wDevID].unixdev == 0) {
1445 dprintf_mciwave(stddeb,"Linux 'widClose' // can't close !\n");
1446 return MMSYSERR_NOTENABLED;
1448 if (WInDev[wDevID].lpQueueHdr != NULL) {
1449 dprintf_mciwave(stddeb,"linux 'widclose' // still buffers open !\n");
1450 return WAVERR_STILLPLAYING;
1452 close(WInDev[wDevID].unixdev);
1453 WInDev[wDevID].unixdev = 0;
1454 WInDev[wDevID].bufsize = 0;
1455 if (WAVE_NotifyClient(wDevID, WIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1456 dprintf_mciwave(stddeb,"Linux 'widClose' // can't notify client !\n");
1457 return MMSYSERR_INVALPARAM;
1459 return MMSYSERR_NOERROR;
1462 /**************************************************************************
1463 * widAddBuffer [internal]
1465 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1467 int count = 1;
1468 LPWAVEHDR lpWIHdr;
1470 dprintf_mciwave(stddeb,
1471 "widAddBuffer(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1472 if (WInDev[wDevID].unixdev == 0) {
1473 dprintf_mciwave(stddeb,"Linux 'widAddBuffer' // can't do it !\n");
1474 return MMSYSERR_NOTENABLED;
1476 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
1477 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // never been prepared !\n");
1478 return WAVERR_UNPREPARED;
1480 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
1481 dprintf_mciwave(stddeb, "Linux 'widAddBuffer' // header already in use !\n");
1482 return WAVERR_STILLPLAYING;
1484 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1485 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1486 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1487 lpWaveHdr->dwBytesRecorded = 0;
1488 if (WInDev[wDevID].lpQueueHdr == NULL) {
1489 WInDev[wDevID].lpQueueHdr = lpWaveHdr;
1490 } else {
1491 lpWIHdr = WInDev[wDevID].lpQueueHdr;
1492 while (lpWIHdr->lpNext != NULL) {
1493 lpWIHdr = lpWIHdr->lpNext;
1494 count++;
1496 lpWIHdr->lpNext = lpWaveHdr;
1497 lpWaveHdr->lpNext = NULL;
1498 count++;
1500 dprintf_mciwave(stddeb,
1501 "widAddBuffer // buffer added ! (now %u in queue)\n", count);
1502 return MMSYSERR_NOERROR;
1505 /**************************************************************************
1506 * widPrepare [internal]
1508 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1510 dprintf_mciwave(stddeb,
1511 "widPrepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1512 if (WInDev[wDevID].unixdev == 0) {
1513 dprintf_mciwave(stddeb,"Linux 'widPrepare' // can't prepare !\n");
1514 return MMSYSERR_NOTENABLED;
1516 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1517 return WAVERR_STILLPLAYING;
1518 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1519 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1520 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1521 lpWaveHdr->dwBytesRecorded = 0;
1522 dprintf_mciwave(stddeb,"Linux 'widPrepare' // header prepared !\n");
1523 return MMSYSERR_NOERROR;
1526 /**************************************************************************
1527 * widUnprepare [internal]
1529 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1531 dprintf_mciwave(stddeb,
1532 "widUnprepare(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1533 if (WInDev[wDevID].unixdev == 0) {
1534 dprintf_mciwave(stddeb,"Linux 'widUnprepare' // can't unprepare !\n");
1535 return MMSYSERR_NOTENABLED;
1537 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1538 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1539 lpWaveHdr->dwFlags |= WHDR_DONE;
1541 dprintf_mciwave(stddeb, "Linux 'widUnprepare' // all headers unprepared !\n");
1542 return MMSYSERR_NOERROR;
1545 /**************************************************************************
1546 * widStart [internal]
1548 static DWORD widStart(WORD wDevID)
1550 int count = 1;
1551 int bytesRead;
1552 LPWAVEHDR lpWIHdr;
1553 LPWAVEHDR *lpWaveHdr;
1555 dprintf_mciwave(stddeb,"widStart(%u);\n", wDevID);
1556 if (WInDev[wDevID].unixdev == 0) {
1557 dprintf_mciwave(stddeb, "Linux 'widStart' // can't start recording !\n");
1558 return MMSYSERR_NOTENABLED;
1561 lpWaveHdr = &(WInDev[wDevID].lpQueueHdr);
1562 dprintf_mciwave(stddeb,"Linux 'widstart'// lpWaveHdr = %08lx\n",(DWORD)lpWaveHdr);
1563 if (!*lpWaveHdr || !(*lpWaveHdr)->lpData) {
1564 dprintf_mciwave(stddeb,"Linux 'widStart' // never been prepared !\n");
1565 return WAVERR_UNPREPARED;
1568 while(*lpWaveHdr != NULL) {
1569 lpWIHdr = *lpWaveHdr;
1570 dprintf_mciwave(stddeb,
1571 "widStart // recording buf#%u=%p size=%lu \n",
1572 count, lpWIHdr->lpData, lpWIHdr->dwBufferLength);
1573 fflush(stddeb);
1574 bytesRead = read (WInDev[wDevID].unixdev,
1575 lpWIHdr->lpData,
1576 lpWIHdr->dwBufferLength);
1577 if (bytesRead==-1)
1578 perror("read from audio device");
1579 fprintf(stderr,"bytesread = %d (%ld)\n",bytesRead,lpWIHdr->dwBufferLength);
1580 lpWIHdr->dwBytesRecorded = bytesRead;
1581 WInDev[wDevID].dwTotalRecorded += lpWIHdr->dwBytesRecorded;
1582 lpWIHdr->dwFlags &= ~WHDR_INQUEUE;
1583 lpWIHdr->dwFlags |= WHDR_DONE;
1585 /* FIXME: should pass segmented pointer here, do we need that?*/
1586 if (WAVE_NotifyClient(wDevID, WIM_DATA, (DWORD)lpWaveHdr, lpWIHdr->dwBytesRecorded) != MMSYSERR_NOERROR) {
1587 dprintf_mciwave(stddeb, "Linux 'widStart' // can't notify client !\n");
1588 return MMSYSERR_INVALPARAM;
1590 /* removes the current block from the queue */
1591 *lpWaveHdr = lpWIHdr->lpNext;
1592 count++;
1594 dprintf_mciwave(stddeb,"widStart // end of recording !\n");
1595 fflush(stddeb);
1596 return MMSYSERR_NOERROR;
1599 /**************************************************************************
1600 * widStop [internal]
1602 static DWORD widStop(WORD wDevID)
1604 dprintf_mciwave(stddeb,"widStop(%u);\n", wDevID);
1605 if (WInDev[wDevID].unixdev == 0) {
1606 dprintf_mciwave(stddeb,"Linux 'widStop' // can't stop !\n");
1607 return MMSYSERR_NOTENABLED;
1609 return MMSYSERR_NOERROR;
1612 /**************************************************************************
1613 * widReset [internal]
1615 static DWORD widReset(WORD wDevID)
1617 dprintf_mciwave(stddeb,"widReset(%u);\n", wDevID);
1618 if (WInDev[wDevID].unixdev == 0) {
1619 dprintf_mciwave(stddeb,"Linux 'widReset' // can't reset !\n");
1620 return MMSYSERR_NOTENABLED;
1622 return MMSYSERR_NOERROR;
1625 /**************************************************************************
1626 * widGetPosition [internal]
1628 static DWORD widGetPosition(WORD wDevID, LPMMTIME16 lpTime, DWORD uSize)
1630 int time;
1632 dprintf_mciwave(stddeb,
1633 "widGetPosition(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1634 if (WInDev[wDevID].unixdev == 0) {
1635 dprintf_mciwave(stddeb,"Linux 'widGetPosition' // can't get pos !\n");
1636 return MMSYSERR_NOTENABLED;
1638 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1639 dprintf_mciwave(stddeb,"widGetPosition // wType=%04X !\n",
1640 lpTime->wType);
1641 dprintf_mciwave(stddeb,"widGetPosition // wBitsPerSample=%u\n",
1642 WInDev[wDevID].Format.wBitsPerSample);
1643 dprintf_mciwave(stddeb,"widGetPosition // nSamplesPerSec=%lu\n",
1644 WInDev[wDevID].Format.wf.nSamplesPerSec);
1645 dprintf_mciwave(stddeb,"widGetPosition // nChannels=%u\n",
1646 WInDev[wDevID].Format.wf.nChannels);
1647 dprintf_mciwave(stddeb,"widGetPosition // nAvgBytesPerSec=%lu\n",
1648 WInDev[wDevID].Format.wf.nAvgBytesPerSec);
1649 fflush(stddeb);
1650 switch(lpTime->wType) {
1651 case TIME_BYTES:
1652 lpTime->u.cb = WInDev[wDevID].dwTotalRecorded;
1653 dprintf_mciwave(stddeb,
1654 "widGetPosition // TIME_BYTES=%lu\n", lpTime->u.cb);
1655 break;
1656 case TIME_SAMPLES:
1657 lpTime->u.sample = WInDev[wDevID].dwTotalRecorded * 8 /
1658 WInDev[wDevID].Format.wBitsPerSample;
1659 dprintf_mciwave(stddeb,
1660 "widGetPosition // TIME_SAMPLES=%lu\n",
1661 lpTime->u.sample);
1662 break;
1663 case TIME_SMPTE:
1664 time = WInDev[wDevID].dwTotalRecorded /
1665 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1666 lpTime->u.smpte.hour = time / 108000;
1667 time -= lpTime->u.smpte.hour * 108000;
1668 lpTime->u.smpte.min = time / 1800;
1669 time -= lpTime->u.smpte.min * 1800;
1670 lpTime->u.smpte.sec = time / 30;
1671 time -= lpTime->u.smpte.sec * 30;
1672 lpTime->u.smpte.frame = time;
1673 lpTime->u.smpte.fps = 30;
1674 dprintf_mciwave(stddeb,"widGetPosition // TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1675 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1676 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1677 break;
1678 default:
1679 dprintf_mciwave(stddeb,"widGetPosition() format not supported ! use TIME_MS !\n");
1680 lpTime->wType = TIME_MS;
1681 case TIME_MS:
1682 lpTime->u.ms = WInDev[wDevID].dwTotalRecorded /
1683 (WInDev[wDevID].Format.wf.nAvgBytesPerSec / 1000);
1684 dprintf_mciwave(stddeb,
1685 "widGetPosition // TIME_MS=%lu\n", lpTime->u.ms);
1686 break;
1688 return MMSYSERR_NOERROR;
1691 #endif /* linux || __FreeBSD__ */
1693 /**************************************************************************
1694 * widMessage [sample driver]
1696 DWORD widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1697 DWORD dwParam1, DWORD dwParam2)
1699 dprintf_mciwave(stddeb,"widMessage(%u, %04X, %08lX, %08lX, %08lX);\n",
1700 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1701 #if defined(linux) || defined(__FreeBSD__)
1702 switch(wMsg) {
1703 case WIDM_OPEN:
1704 return widOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1705 case WIDM_CLOSE:
1706 return widClose(wDevID);
1707 case WIDM_ADDBUFFER:
1708 return widAddBuffer(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1709 case WIDM_PREPARE:
1710 return widPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1711 case WIDM_UNPREPARE:
1712 return widUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1713 case WIDM_GETDEVCAPS:
1714 return widGetDevCaps(wDevID, (LPWAVEINCAPS16)dwParam1,dwParam2);
1715 case WIDM_GETNUMDEVS:
1716 return 1;
1717 case WIDM_GETPOS:
1718 return widGetPosition(wDevID, (LPMMTIME16)dwParam1, dwParam2);
1719 case WIDM_RESET:
1720 return widReset(wDevID);
1721 case WIDM_START:
1722 return widStart(wDevID);
1723 case WIDM_PAUSE:
1724 return widStop(wDevID);
1725 case WIDM_STOP:
1726 return widStop(wDevID);
1727 default:
1728 dprintf_mciwave(stddeb,"widMessage // unknown message !\n");
1730 return MMSYSERR_NOTSUPPORTED;
1731 #else
1732 return MMSYSERR_NOTENABLED;
1733 #endif
1737 /**************************************************************************
1738 * AUDIO_DriverProc [sample driver]
1740 LONG WAVE_DriverProc(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1741 DWORD dwParam1, DWORD dwParam2)
1743 #if defined(linux) || defined(__FreeBSD__)
1744 dprintf_mciwave(stddeb,"WAVE_DriverProc(%08lX, %04X, %04X, %08lX, %08lX)\n",
1745 dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1746 switch(wMsg) {
1747 case DRV_LOAD:
1748 return 1;
1749 case DRV_FREE:
1750 return 1;
1751 case DRV_OPEN:
1752 return 1;
1753 case DRV_CLOSE:
1754 return 1;
1755 case DRV_ENABLE:
1756 return 1;
1757 case DRV_DISABLE:
1758 return 1;
1759 case DRV_QUERYCONFIGURE:
1760 return 1;
1761 case DRV_CONFIGURE:
1762 MessageBox16(0, "Sample MultiMedia Linux Driver !",
1763 "MMLinux Driver", MB_OK);
1764 return 1;
1765 case DRV_INSTALL:
1766 return DRVCNF_RESTART;
1767 case DRV_REMOVE:
1768 return DRVCNF_RESTART;
1769 case MCI_OPEN_DRIVER:
1770 case MCI_OPEN:
1771 return WAVE_mciOpen(dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1772 case MCI_CUE:
1773 return WAVE_mciCue(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1774 case MCI_CLOSE_DRIVER:
1775 case MCI_CLOSE:
1776 return WAVE_mciClose(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1777 case MCI_PLAY:
1778 return WAVE_mciPlay(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)PTR_SEG_TO_LIN(dwParam2));
1779 case MCI_RECORD:
1780 return WAVE_mciRecord(dwDevID, dwParam1, (LPMCI_RECORD_PARMS)PTR_SEG_TO_LIN(dwParam2));
1781 case MCI_STOP:
1782 return WAVE_mciStop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1783 case MCI_SET:
1784 return WAVE_mciSet(dwDevID, dwParam1, (LPMCI_SET_PARMS)PTR_SEG_TO_LIN(dwParam2));
1785 case MCI_PAUSE:
1786 return WAVE_mciPause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1787 case MCI_RESUME:
1788 return WAVE_mciResume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)PTR_SEG_TO_LIN(dwParam2));
1789 case MCI_STATUS:
1790 return WAVE_mciStatus(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1791 case MCI_GETDEVCAPS:
1792 return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)PTR_SEG_TO_LIN(dwParam2));
1793 case MCI_INFO:
1794 return WAVE_mciInfo(dwDevID, dwParam1, (LPMCI_INFO_PARMS16)PTR_SEG_TO_LIN(dwParam2));
1796 case MCI_LOAD:
1797 return MMSYSERR_NOTSUPPORTED;
1798 case MCI_SAVE:
1799 return MMSYSERR_NOTSUPPORTED;
1800 case MCI_SEEK:
1801 return MMSYSERR_NOTSUPPORTED;
1802 case MCI_FREEZE:
1803 return MMSYSERR_NOTSUPPORTED;
1804 case MCI_PUT:
1805 return MMSYSERR_NOTSUPPORTED;
1806 case MCI_REALIZE:
1807 return MMSYSERR_NOTSUPPORTED;
1808 case MCI_UNFREEZE:
1809 return MMSYSERR_NOTSUPPORTED;
1810 case MCI_UPDATE:
1811 return MMSYSERR_NOTSUPPORTED;
1812 case MCI_WHERE:
1813 return MMSYSERR_NOTSUPPORTED;
1814 case MCI_WINDOW:
1815 return MMSYSERR_NOTSUPPORTED;
1816 case MCI_STEP:
1817 return MMSYSERR_NOTSUPPORTED;
1818 case MCI_SPIN:
1819 return MMSYSERR_NOTSUPPORTED;
1820 case MCI_ESCAPE:
1821 return MMSYSERR_NOTSUPPORTED;
1822 case MCI_COPY:
1823 return MMSYSERR_NOTSUPPORTED;
1824 case MCI_CUT:
1825 return MMSYSERR_NOTSUPPORTED;
1826 case MCI_DELETE:
1827 return MMSYSERR_NOTSUPPORTED;
1828 case MCI_PASTE:
1829 return MMSYSERR_NOTSUPPORTED;
1831 default:
1832 return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1834 #else
1835 return MMSYSERR_NOTENABLED;
1836 #endif