- Better handling when settimeofday is not available.
[wine] / dlls / winmm / wavemap / wavemap.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*                                 
3  * Wine Wave mapper driver
4  *
5  * Copyright    1999,2001 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* TODOs
23  *      + better protection against evilish dwUser parameters
24  *      + use asynchronous ACM conversion
25  *      + don't use callback functions when none is required in open
26  *      + the buffer sizes may not be accurate, so there may be some
27  *        remaining bytes in src and dst buffers after ACM conversions...
28  *              those should be taken care of...
29  */
30
31 #include <string.h>
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "mmddk.h"
37 #include "msacm.h"
38 #include "wine/debug.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(msacm);
41
42 typedef struct tagWAVEMAPDATA {
43     struct tagWAVEMAPDATA*      self;
44     HWAVE       hOuterWave;
45     HWAVE       hInnerWave;
46     HACMSTREAM  hAcmStream;
47     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
48     DWORD       dwCallback;
49     DWORD       dwClientInstance;
50     DWORD       dwFlags;
51 } WAVEMAPDATA;
52
53 static  BOOL    WAVEMAP_IsData(WAVEMAPDATA* wm)
54 {
55     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
56 }
57
58 /*======================================================================*
59  *                  WAVE OUT part                                       *
60  *======================================================================*/
61
62 static void     CALLBACK wodCallback(HWAVE hWave, UINT uMsg, DWORD dwInstance, 
63                                      DWORD dwParam1, DWORD dwParam2)
64 {
65     WAVEMAPDATA*        wom = (WAVEMAPDATA*)dwInstance;
66
67     TRACE("(0x%x %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
68
69     if (!WAVEMAP_IsData(wom)) {
70         ERR("Bad data\n");
71         return;
72     }
73
74     if (hWave != wom->hInnerWave && uMsg != WOM_OPEN) 
75         ERR("Shouldn't happen (%08x %08x)\n", hWave, wom->hInnerWave);
76
77     switch (uMsg) {
78     case WOM_OPEN:
79     case WOM_CLOSE:
80         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
81         break;
82     case WOM_DONE:
83         if (wom->hAcmStream) {
84             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)dwParam1;
85             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
86             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
87
88             lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
89             lpWaveHdrSrc->dwFlags |= WHDR_DONE;
90             dwParam1 = (DWORD)lpWaveHdrSrc;
91         }
92         break;
93     default:
94         ERR("Unknown msg %u\n", uMsg);
95     }
96
97     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), wom->hOuterWave, uMsg, 
98                    wom->dwClientInstance, dwParam1, dwParam2);
99 }
100
101 static  DWORD   wodOpenHelper(WAVEMAPDATA* wom, UINT idx, 
102                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 
103                               DWORD dwFlags)
104 {
105     DWORD       ret;
106
107     /* destination is always PCM, so the formulas below apply */
108     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
109     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
110     if (dwFlags & WAVE_FORMAT_QUERY) {
111         ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
112     } else {
113         ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
114     }
115     if (ret == MMSYSERR_NOERROR) {
116         ret = waveOutOpen(&wom->hInnerWave, idx, lpwfx, (DWORD)wodCallback, 
117                           (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
118         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
119             acmStreamClose(wom->hAcmStream, 0);
120             wom->hAcmStream = 0;
121         }
122     }
123     return ret;
124 }
125
126 static  DWORD   wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
127 {
128     UINT                ndlo, ndhi;
129     UINT                i;
130     WAVEMAPDATA*        wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
131     WAVEFORMATEX        wfx;
132
133     TRACE("(%p %p %08lx\n", lpdwUser, lpDesc, dwFlags);
134
135     if (!wom)
136         return MMSYSERR_NOMEM;
137
138     ndhi = waveOutGetNumDevs();
139     if (dwFlags & WAVE_MAPPED) {
140         if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
141         ndlo = lpDesc->uMappedDeviceID;
142         ndhi = ndlo + 1;
143         dwFlags &= ~WAVE_MAPPED;
144     } else {
145         ndlo = 0;
146     }
147     wom->self = wom;
148     wom->dwCallback = lpDesc->dwCallback;
149     wom->dwFlags = dwFlags;
150     wom->dwClientInstance = lpDesc->dwInstance;
151     wom->hOuterWave = lpDesc->hWave;
152
153     for (i = ndlo; i < ndhi; i++) {
154         /* if no ACM stuff is involved, no need to handle callbacks at this
155          * level, this will be done transparently
156          */
157         if (waveOutOpen(&wom->hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback, 
158                         (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION) == MMSYSERR_NOERROR) {
159             wom->hAcmStream = 0;
160             goto found;
161         }
162     }
163
164     wfx.wFormatTag = WAVE_FORMAT_PCM;
165     wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
166     /* try some ACM stuff */
167
168 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
169                         if (wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags) == MMSYSERR_NOERROR) goto found;
170
171     for (i = ndlo; i < ndhi; i++) {
172         /* first try with same stereo/mono option as source */
173         wfx.nChannels = lpDesc->lpFormat->nChannels;
174         TRY(44100, 16);
175         TRY(22050, 16);
176         TRY(11025, 16);
177
178         /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
179         wfx.nChannels ^= 3; 
180         TRY(44100, 16);
181         TRY(22050, 16);
182         TRY(11025, 16);
183
184         /* first try with same stereo/mono option as source */
185         wfx.nChannels = lpDesc->lpFormat->nChannels;
186         TRY(44100, 8);
187         TRY(22050, 8);
188         TRY(11025, 8);
189
190         /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
191         wfx.nChannels ^= 3; 
192         TRY(44100, 8);
193         TRY(22050, 8);
194         TRY(11025, 8);
195     }
196 #undef TRY
197                       
198     HeapFree(GetProcessHeap(), 0, wom);
199     return MMSYSERR_ALLOCATED;
200 found:
201     if (dwFlags & WAVE_FORMAT_QUERY) {
202         *lpdwUser = 0L;
203         HeapFree(GetProcessHeap(), 0, wom);
204     } else {
205         *lpdwUser = (DWORD)wom;
206     }
207     return MMSYSERR_NOERROR;
208 }
209
210 static  DWORD   wodClose(WAVEMAPDATA* wom)
211 {
212     DWORD ret = waveOutClose(wom->hInnerWave);
213
214     if (ret == MMSYSERR_NOERROR) {
215         if (wom->hAcmStream) {
216             ret = acmStreamClose(wom->hAcmStream, 0);
217         }
218         if (ret == MMSYSERR_NOERROR) {
219             HeapFree(GetProcessHeap(), 0, wom);
220         }
221     }
222     return ret;
223 }
224
225 static  DWORD   wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
226 {
227     PACMSTREAMHEADER    ash;
228     LPWAVEHDR           lpWaveHdrDst;
229
230     if (!wom->hAcmStream) {
231         return waveOutWrite(wom->hInnerWave, lpWaveHdrSrc, dwParam2);
232     }
233     
234     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
235     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
236     if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR)
237         return MMSYSERR_ERROR;
238     
239     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
240     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
241     return waveOutWrite(wom->hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
242 }
243
244 static  DWORD   wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
245 {
246     PACMSTREAMHEADER    ash;
247     DWORD               size;
248     DWORD               dwRet;
249     LPWAVEHDR           lpWaveHdrDst;
250
251     if (!wom->hAcmStream) {
252         return waveOutPrepareHeader(wom->hInnerWave, lpWaveHdrSrc, dwParam2);
253     }
254     if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR)
255         return MMSYSERR_ERROR;
256
257     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
258     if (ash == NULL)
259         return MMSYSERR_NOMEM;
260
261     ash->cbStruct = sizeof(*ash);
262     ash->fdwStatus = 0L;
263     ash->dwUser = (DWORD)lpWaveHdrSrc;
264     ash->pbSrc = lpWaveHdrSrc->lpData;
265     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
266     /* ash->cbSrcLengthUsed */
267     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
268     ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
269     ash->cbDstLength = size;
270     /* ash->cbDstLengthUsed */
271     ash->dwDstUser = 0; /* FIXME ? */
272     dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
273     if (dwRet != MMSYSERR_NOERROR)
274         goto errCleanUp;
275
276     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
277     lpWaveHdrDst->lpData = ash->pbDst;
278     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
279     lpWaveHdrDst->dwFlags = 0;
280     lpWaveHdrDst->dwLoops = 0;
281     dwRet = waveOutPrepareHeader(wom->hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
282     if (dwRet != MMSYSERR_NOERROR)
283         goto errCleanUp;
284
285     lpWaveHdrSrc->reserved = (DWORD)ash;
286     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
287     TRACE("=> (0)\n");
288     return MMSYSERR_NOERROR;
289 errCleanUp:
290     TRACE("=> (%ld)\n", dwRet);
291     HeapFree(GetProcessHeap(), 0, ash);
292     return dwRet;
293 }
294
295 static  DWORD   wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
296 {
297     PACMSTREAMHEADER    ash;
298     LPWAVEHDR           lpWaveHdrDst;
299     DWORD               dwRet1, dwRet2;
300
301     if (!wom->hAcmStream) {
302         return waveOutUnprepareHeader(wom->hInnerWave, lpWaveHdrSrc, dwParam2);
303     }
304     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
305     dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
306     
307     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
308     dwRet2 = waveOutUnprepareHeader(wom->hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
309
310     HeapFree(GetProcessHeap(), 0, ash);
311     
312     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
313     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
314 }
315
316 static  DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
317 {
318     if (wom->hAcmStream)
319         FIXME("No position conversion done for PCM => non-PCM, returning PCM position\n");
320     return waveOutGetPosition(wom->hInnerWave, lpTime, dwParam2);
321 }
322
323 static  DWORD   wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSA lpWaveCaps, DWORD dwParam2)
324 {
325     /* if opened low driver, forward message */
326     if (WAVEMAP_IsData(wom))
327         return waveOutGetDevCapsA(wom->hInnerWave, lpWaveCaps, dwParam2);
328     /* otherwise, return caps of mapper itself */
329     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
330         lpWaveCaps->wMid = 0x00FF;
331         lpWaveCaps->wPid = 0x0001;
332         lpWaveCaps->vDriverVersion = 0x0100;
333         strcpy(lpWaveCaps->szPname, "Wine wave out mapper");
334         lpWaveCaps->dwFormats = 
335             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
336             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
337             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
338         lpWaveCaps->wChannels = 2;
339         lpWaveCaps->dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
340
341         return MMSYSERR_NOERROR;
342     }
343     ERR("This shouldn't happen\n");
344     return MMSYSERR_ERROR; 
345 }
346
347 static  DWORD   wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
348 {
349     if (WAVEMAP_IsData(wom))
350         return waveOutGetVolume(wom->hInnerWave, lpVol);
351     return MMSYSERR_NOERROR;
352 }
353
354 static  DWORD   wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
355 {
356     if (WAVEMAP_IsData(wom))
357         return waveOutSetVolume(wom->hInnerWave, vol);
358     return MMSYSERR_NOERROR;
359 }
360
361 static  DWORD   wodPause(WAVEMAPDATA* wom)
362 {
363     return waveOutPause(wom->hInnerWave);
364 }
365
366 static  DWORD   wodRestart(WAVEMAPDATA* wom)
367 {
368     return waveOutRestart(wom->hInnerWave);
369 }
370
371 static  DWORD   wodReset(WAVEMAPDATA* wom)
372 {
373     return waveOutReset(wom->hInnerWave);
374 }
375
376 static  DWORD   wodBreakLoop(WAVEMAPDATA* wom)
377 {
378     return waveOutBreakLoop(wom->hInnerWave);
379 }
380
381 static  DWORD   wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
382 {
383     UINT        id;
384     DWORD       ret = MMSYSERR_NOTSUPPORTED;
385
386     switch (flags) {
387     case WAVEOUT_MAPPER_STATUS_DEVICE:  
388         ret = waveOutGetID(wom->hInnerWave, &id);
389         *(LPDWORD)ptr = id;
390         break;
391     case WAVEOUT_MAPPER_STATUS_MAPPED:
392         FIXME("Unsupported flag=%ld\n", flags);
393         *(LPDWORD)ptr = 0; /* FIXME ?? */       
394         break;
395     case WAVEOUT_MAPPER_STATUS_FORMAT:
396         FIXME("Unsupported flag=%ld\n", flags);
397         /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
398         *(LPDWORD)ptr = 0;
399         break;
400     default:
401         FIXME("Unsupported flag=%ld\n", flags);
402         *(LPDWORD)ptr = 0;
403         break;
404     }
405     return ret;
406 }
407
408 /**************************************************************************
409  *                              wodMessage (MSACMMAP.@)
410  */
411 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, 
412                                 DWORD dwParam1, DWORD dwParam2)
413 {
414     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
415           wDevID, wMsg, dwUser, dwParam1, dwParam2);
416     
417     switch (wMsg) {
418     case DRVM_INIT:
419     case DRVM_EXIT:
420     case DRVM_ENABLE:
421     case DRVM_DISABLE:
422         /* FIXME: Pretend this is supported */
423         return 0;
424     case WODM_OPEN:             return wodOpen          ((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
425     case WODM_CLOSE:            return wodClose         ((WAVEMAPDATA*)dwUser);
426     case WODM_WRITE:            return wodWrite         ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
427     case WODM_PAUSE:            return wodPause         ((WAVEMAPDATA*)dwUser);
428     case WODM_GETPOS:           return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
429     case WODM_BREAKLOOP:        return wodBreakLoop     ((WAVEMAPDATA*)dwUser);
430     case WODM_PREPARE:          return wodPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
431     case WODM_UNPREPARE:        return wodUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
432     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSA)dwParam1,dwParam2);
433     case WODM_GETNUMDEVS:       return 1;
434     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
435     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
436     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
437     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
438     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
439     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
440     case WODM_RESTART:          return wodRestart       ((WAVEMAPDATA*)dwUser);
441     case WODM_RESET:            return wodReset         ((WAVEMAPDATA*)dwUser);
442     case WODM_MAPPER_STATUS:    return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
443     default:
444         FIXME("unknown message %d!\n", wMsg);
445     }
446     return MMSYSERR_NOTSUPPORTED;
447 }
448
449 /*======================================================================*
450  *                  WAVE IN part                                        *
451  *======================================================================*/
452
453 static void     CALLBACK widCallback(HWAVE hWave, UINT uMsg, DWORD dwInstance, 
454                                      DWORD dwParam1, DWORD dwParam2)
455 {
456     WAVEMAPDATA*        wim = (WAVEMAPDATA*)dwInstance;
457
458     TRACE("(0x%x %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
459
460     if (!WAVEMAP_IsData(wim)) {
461         ERR("Bad data\n");
462         return;
463     }
464
465     if (hWave != wim->hInnerWave && uMsg != WIM_OPEN) 
466         ERR("Shouldn't happen (%08x %08x)\n", hWave, wim->hInnerWave);
467
468     switch (uMsg) {
469     case WIM_OPEN:
470     case WIM_CLOSE:
471         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
472         break;
473     case WIM_DATA:
474         if (wim->hAcmStream) {
475             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
476             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
477             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
478
479             /* convert data just gotten from waveIn into requested format */
480             if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
481                 ERR("ACM conversion failed\n");
482                 return;
483             } else {
484                 TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
485             }
486             /* and setup the wavehdr to return accordingly */
487             lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
488             lpWaveHdrDst->dwFlags |= WHDR_DONE;
489             lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
490             dwParam1 = (DWORD)lpWaveHdrDst;
491         }
492         break;
493     default:
494         ERR("Unknown msg %u\n", uMsg);
495     }
496
497     DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), wim->hOuterWave, uMsg, 
498                    wim->dwClientInstance, dwParam1, dwParam2);
499 }
500
501 static  DWORD   widOpenHelper(WAVEMAPDATA* wim, UINT idx, 
502                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx, 
503                               DWORD dwFlags)
504 {
505     DWORD       ret;
506
507     /* source is always PCM, so the formulas below apply */
508     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
509     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
510     if (dwFlags & WAVE_FORMAT_QUERY) {
511         ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
512     } else {
513         ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
514     }
515     if (ret == MMSYSERR_NOERROR) {
516         ret = waveInOpen(&wim->hInnerWave, idx, lpwfx, (DWORD)widCallback, 
517                          (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
518         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
519             acmStreamClose(wim->hAcmStream, 0);
520             wim->hAcmStream = 0;
521         }
522     }
523     return ret;
524 }
525
526 static  DWORD   widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
527 {
528     UINT                ndlo, ndhi;
529     UINT                i;
530     WAVEMAPDATA*        wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
531     WAVEFORMATEX        wfx;
532
533     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
534
535     if (!wim)
536         return MMSYSERR_NOMEM;
537
538     wim->self = wim;
539     wim->dwCallback = lpDesc->dwCallback;
540     wim->dwFlags = dwFlags;
541     wim->dwClientInstance = lpDesc->dwInstance;
542     wim->hOuterWave = lpDesc->hWave;
543     
544     ndhi = waveOutGetNumDevs();
545     if (dwFlags & WAVE_MAPPED) {
546         if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
547         ndlo = lpDesc->uMappedDeviceID;
548         ndhi = ndlo + 1;
549         dwFlags &= ~WAVE_MAPPED;
550     } else {
551         ndlo = 0;
552     }
553
554     for (i = ndlo; i < ndhi; i++) {
555         if (waveInOpen(&wim->hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback, 
556                         (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION) == MMSYSERR_NOERROR) {
557             wim->hAcmStream = 0;
558             goto found;
559         }
560     }
561     wfx.wFormatTag = WAVE_FORMAT_PCM;
562     wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
563     /* try some ACM stuff */
564
565 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
566                         if (widOpenHelper(wim, i, lpDesc, &wfx, dwFlags) == MMSYSERR_NOERROR) goto found;
567
568     for (i = ndlo; i < ndhi; i++) {
569         /* first try with same stereo/mono option as source */
570         wfx.nChannels = lpDesc->lpFormat->nChannels;
571         TRY(44100, 8);
572         TRY(22050, 8);
573         TRY(11025, 8);
574
575         /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
576         wfx.nChannels ^= 3; 
577         TRY(44100, 8);
578         TRY(22050, 8);
579         TRY(11025, 8);
580     }
581 #undef TRY
582
583     HeapFree(GetProcessHeap(), 0, wim);
584     return MMSYSERR_ALLOCATED;
585 found:
586     if (dwFlags & WAVE_FORMAT_QUERY) {
587         *lpdwUser = 0L;
588         HeapFree(GetProcessHeap(), 0, wim);
589     } else {
590         *lpdwUser = (DWORD)wim;
591     }
592     TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream);
593     return MMSYSERR_NOERROR;
594 }
595
596 static  DWORD   widClose(WAVEMAPDATA* wim)
597 {
598     DWORD ret = waveInClose(wim->hInnerWave);
599
600     if (ret == MMSYSERR_NOERROR) {
601         if (wim->hAcmStream) {
602             ret = acmStreamClose(wim->hAcmStream, 0);
603         }
604         if (ret == MMSYSERR_NOERROR) {
605             HeapFree(GetProcessHeap(), 0, wim);
606         }
607     }
608     return ret;
609 }
610
611 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
612 {
613     PACMSTREAMHEADER    ash;
614     LPWAVEHDR           lpWaveHdrSrc;
615
616     if (!wim->hAcmStream) {
617         return waveInAddBuffer(wim->hInnerWave, lpWaveHdrDst, dwParam2);
618     }
619
620     lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
621     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
622     
623     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
624     return waveInAddBuffer(wim->hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
625 }
626
627 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
628 {
629     PACMSTREAMHEADER    ash;
630     DWORD               size;
631     DWORD               dwRet;
632     LPWAVEHDR           lpWaveHdrSrc;
633
634     if (!wim->hAcmStream) {
635         return waveInPrepareHeader(wim->hInnerWave, lpWaveHdrDst, dwParam2);
636     }
637     if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size, 
638                       ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR)
639         return MMSYSERR_ERROR;
640
641     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
642     if (ash == NULL)
643         return MMSYSERR_NOMEM;
644
645     ash->cbStruct = sizeof(*ash);
646     ash->fdwStatus = 0L;
647     ash->dwUser = (DWORD)lpWaveHdrDst;
648     ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
649     ash->cbSrcLength = size;
650     /* ash->cbSrcLengthUsed */
651     ash->dwSrcUser = 0L; /* FIXME ? */
652     ash->pbDst = lpWaveHdrDst->lpData;
653     ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
654     /* ash->cbDstLengthUsed */
655     ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
656     dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
657     if (dwRet != MMSYSERR_NOERROR)
658         goto errCleanUp;
659
660     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
661     lpWaveHdrSrc->lpData = ash->pbSrc;
662     lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
663     lpWaveHdrSrc->dwFlags = 0;
664     lpWaveHdrSrc->dwLoops = 0;
665     dwRet = waveInPrepareHeader(wim->hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
666     if (dwRet != MMSYSERR_NOERROR)
667         goto errCleanUp;
668
669     lpWaveHdrDst->reserved = (DWORD)ash;
670     lpWaveHdrDst->dwFlags = WHDR_PREPARED;
671     TRACE("=> (0)\n");
672     return MMSYSERR_NOERROR;
673 errCleanUp:
674     TRACE("=> (%ld)\n", dwRet);
675     HeapFree(GetProcessHeap(), 0, ash);
676     return dwRet;
677 }
678
679 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
680 {
681     PACMSTREAMHEADER    ash;
682     LPWAVEHDR           lpWaveHdrSrc;
683     DWORD               dwRet1, dwRet2;
684
685     if (!wim->hAcmStream) {
686         return waveInUnprepareHeader(wim->hInnerWave, lpWaveHdrDst, dwParam2);
687     }
688     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
689     dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
690     
691     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
692     dwRet2 = waveInUnprepareHeader(wim->hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
693
694     HeapFree(GetProcessHeap(), 0, ash);
695     
696     lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
697     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
698 }
699
700 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
701 {
702     if (wim->hAcmStream)
703         FIXME("No position conversion done for PCM => non-PCM, returning PCM position\n");
704     return waveInGetPosition(wim->hInnerWave, lpTime, dwParam2);
705 }
706
707 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSA lpWaveCaps, DWORD dwParam2)
708 {
709     /* if opened low driver, forward message */
710     if (WAVEMAP_IsData(wim))
711         return waveInGetDevCapsA(wim->hInnerWave, lpWaveCaps, dwParam2);
712     /* otherwise, return caps of mapper itself */
713     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
714         lpWaveCaps->wMid = 0x00FF;
715         lpWaveCaps->wPid = 0x0001;
716         lpWaveCaps->vDriverVersion = 0x0001;
717         strcpy(lpWaveCaps->szPname, "Wine wave in mapper");
718         lpWaveCaps->dwFormats = 
719             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
720             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
721             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;    
722         lpWaveCaps->wChannels = 2;
723         return MMSYSERR_NOERROR;
724     }
725     ERR("This shouldn't happen\n");
726     return MMSYSERR_ERROR; 
727 }
728
729 static  DWORD   widStop(WAVEMAPDATA* wim)
730 {
731     return waveInStop(wim->hInnerWave);
732 }
733
734 static  DWORD   widStart(WAVEMAPDATA* wim)
735 {
736     return waveInStart(wim->hInnerWave);
737 }
738
739 static  DWORD   widReset(WAVEMAPDATA* wim)
740 {
741     return waveInReset(wim->hInnerWave);
742 }
743
744 static  DWORD   widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
745 {
746     UINT        id;
747     DWORD       ret = MMSYSERR_NOTSUPPORTED;
748
749     switch (flags) {
750     case WAVEIN_MAPPER_STATUS_DEVICE:   
751         ret = waveInGetID(wim->hInnerWave, &id);
752         *(LPDWORD)ptr = id;
753         break;
754     case WAVEIN_MAPPER_STATUS_MAPPED:
755         FIXME("Unsupported yet flag=%ld\n", flags);
756         *(LPDWORD)ptr = 0; /* FIXME ?? */       
757         break;
758     case WAVEIN_MAPPER_STATUS_FORMAT:
759         FIXME("Unsupported flag=%ld\n", flags);
760         /* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
761         *(LPDWORD)ptr = 0; /* FIXME ?? */       
762         break;
763     default:
764         FIXME("Unsupported flag=%ld\n", flags);
765         *(LPDWORD)ptr = 0;
766         break;
767     }
768     return ret;
769 }
770
771 /**************************************************************************
772  *                              widMessage (MSACMMAP.@)
773  */
774 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
775                                 DWORD dwParam1, DWORD dwParam2)
776 {
777     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
778           wDevID, wMsg, dwUser, dwParam1, dwParam2);
779
780     switch (wMsg) {
781     case DRVM_INIT:
782     case DRVM_EXIT:
783     case DRVM_ENABLE:
784     case DRVM_DISABLE:
785         /* FIXME: Pretend this is supported */
786         return 0;
787
788     case WIDM_OPEN:             return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
789     case WIDM_CLOSE:            return widClose         ((WAVEMAPDATA*)dwUser);
790
791     case WIDM_ADDBUFFER:        return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
792     case WIDM_PREPARE:          return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
793     case WIDM_UNPREPARE:        return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
794     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSA)dwParam1, dwParam2);
795     case WIDM_GETNUMDEVS:       return 1;
796     case WIDM_GETPOS:           return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
797     case WIDM_RESET:            return widReset         ((WAVEMAPDATA*)dwUser);
798     case WIDM_START:            return widStart         ((WAVEMAPDATA*)dwUser);
799     case WIDM_STOP:             return widStop          ((WAVEMAPDATA*)dwUser);
800     case WIDM_MAPPER_STATUS:    return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
801     default:
802         FIXME("unknown message %u!\n", wMsg);
803     }
804     return MMSYSERR_NOTSUPPORTED;
805 }
806
807 /*======================================================================*
808  *                  Driver part                                         *
809  *======================================================================*/
810
811 static  struct WINE_WAVEMAP* oss = NULL;
812
813 /**************************************************************************
814  *                              WAVEMAP_drvOpen                 [internal]      
815  */
816 static  DWORD   WAVEMAP_drvOpen(LPSTR str)
817 {
818     if (oss)
819         return 0;
820     
821     /* I know, this is ugly, but who cares... */
822     oss = (struct WINE_WAVEMAP*)1;
823     return 1;
824 }
825
826 /**************************************************************************
827  *                              WAVEMAP_drvClose                [internal]      
828  */
829 static  DWORD   WAVEMAP_drvClose(DWORD dwDevID)
830 {
831     if (oss) {
832         oss = NULL;
833         return 1;
834     }
835     return 0;
836 }
837
838 /**************************************************************************
839  *                              DriverProc (MSACMMAP.@)
840  */
841 LONG CALLBACK   WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg, 
842                                    DWORD dwParam1, DWORD dwParam2)
843 {
844     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",
845           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
846     
847     switch(wMsg) {
848     case DRV_LOAD:              return 1;
849     case DRV_FREE:              return 1;
850     case DRV_OPEN:              return WAVEMAP_drvOpen((LPSTR)dwParam1);
851     case DRV_CLOSE:             return WAVEMAP_drvClose(dwDevID);
852     case DRV_ENABLE:            return 1;
853     case DRV_DISABLE:           return 1;
854     case DRV_QUERYCONFIGURE:    return 1;
855     case DRV_CONFIGURE:         MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "OSS Driver", MB_OK);     return 1;
856     case DRV_INSTALL:           return DRVCNF_RESTART;
857     case DRV_REMOVE:            return DRVCNF_RESTART;
858     default:
859         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
860     }
861 }
862
863