Prevent crash when no URL is specified.
[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 <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "mmddk.h"
38 #include "mmreg.h"
39 #include "msacm.h"
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(wavemap);
44
45 typedef struct tagWAVEMAPDATA {
46     struct tagWAVEMAPDATA*      self;
47     union {
48         struct {
49             HWAVEOUT    hOuterWave;
50             HWAVEOUT    hInnerWave;
51         } out;
52         struct {
53             HWAVEIN     hOuterWave;
54             HWAVEIN     hInnerWave;
55         } in;
56     } u;
57     HACMSTREAM  hAcmStream;
58     /* needed data to filter callbacks. Only needed when hAcmStream is not 0 */
59     DWORD       dwCallback;
60     DWORD       dwClientInstance;
61     DWORD       dwFlags;
62     /* ratio to compute position from a PCM playback to any format */
63     DWORD       avgSpeedOuter;
64     DWORD       avgSpeedInner;
65     /* channel size of inner and outer */
66     DWORD       nSamplesPerSecOuter;
67     DWORD       nSamplesPerSecInner;
68 } WAVEMAPDATA;
69
70 static  BOOL    WAVEMAP_IsData(WAVEMAPDATA* wm)
71 {
72     return (!IsBadReadPtr(wm, sizeof(WAVEMAPDATA)) && wm->self == wm);
73 }
74
75 /*======================================================================*
76  *                  WAVE OUT part                                       *
77  *======================================================================*/
78
79 static void     CALLBACK wodCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance,
80                                      DWORD dwParam1, DWORD dwParam2)
81 {
82     WAVEMAPDATA*        wom = (WAVEMAPDATA*)dwInstance;
83
84     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
85
86     if (!WAVEMAP_IsData(wom)) {
87         ERR("Bad data\n");
88         return;
89     }
90
91     if (hWave != wom->u.out.hInnerWave && uMsg != WOM_OPEN)
92         ERR("Shouldn't happen (%p %p)\n", hWave, wom->u.out.hInnerWave);
93
94     switch (uMsg) {
95     case WOM_OPEN:
96     case WOM_CLOSE:
97         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
98         break;
99     case WOM_DONE:
100         if (wom->hAcmStream) {
101             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)dwParam1;
102             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrDst - sizeof(ACMSTREAMHEADER));
103             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)ash->dwUser;
104
105             lpWaveHdrSrc->dwFlags &= ~WHDR_INQUEUE;
106             lpWaveHdrSrc->dwFlags |= WHDR_DONE;
107             dwParam1 = (DWORD)lpWaveHdrSrc;
108         }
109         break;
110     default:
111         ERR("Unknown msg %u\n", uMsg);
112     }
113
114     DriverCallback(wom->dwCallback, HIWORD(wom->dwFlags), (HDRVR)wom->u.out.hOuterWave,
115                    uMsg, wom->dwClientInstance, dwParam1, dwParam2);
116 }
117
118 /******************************************************************
119  *              wodOpenHelper
120  *
121  *
122  */
123 static  DWORD   wodOpenHelper(WAVEMAPDATA* wom, UINT idx,
124                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
125                               DWORD dwFlags)
126 {
127     DWORD       ret;
128
129     TRACE("(%p %04x %p %p %08lx)\n", wom, idx, lpDesc, lpwfx, dwFlags);
130
131     /* destination is always PCM, so the formulas below apply */
132     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
133     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
134     if (dwFlags & WAVE_FORMAT_QUERY) {
135         ret = acmStreamOpen(NULL, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
136     } else {
137         ret = acmStreamOpen(&wom->hAcmStream, 0, lpDesc->lpFormat, lpwfx, NULL, 0L, 0L, 0L);
138     }
139     if (ret == MMSYSERR_NOERROR) {
140         ret = waveOutOpen(&wom->u.out.hInnerWave, idx, lpwfx, (DWORD)wodCallback,
141                           (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
142         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
143             acmStreamClose(wom->hAcmStream, 0);
144             wom->hAcmStream = 0;
145         }
146     }
147     TRACE("ret = %08lx\n", ret);
148     return ret;
149 }
150
151 static  DWORD   wodOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
152 {
153     UINT                ndlo, ndhi;
154     UINT                i;
155     WAVEMAPDATA*        wom = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
156     DWORD               res;
157
158     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
159
160     if (!wom) {
161         WARN("no memory\n");
162         return MMSYSERR_NOMEM;
163     }
164
165     ndhi = waveOutGetNumDevs();
166     if (dwFlags & WAVE_MAPPED) {
167         if (lpDesc->uMappedDeviceID >= ndhi) {
168             WARN("invalid parameter: dwFlags WAVE_MAPPED\n");
169             HeapFree(GetProcessHeap(), 0, wom);
170             return MMSYSERR_INVALPARAM;
171         }
172         ndlo = lpDesc->uMappedDeviceID;
173         ndhi = ndlo + 1;
174         dwFlags &= ~WAVE_MAPPED;
175     } else {
176         ndlo = 0;
177     }
178     wom->self = wom;
179     wom->dwCallback = lpDesc->dwCallback;
180     wom->dwFlags = dwFlags;
181     wom->dwClientInstance = lpDesc->dwInstance;
182     wom->u.out.hOuterWave = (HWAVEOUT)lpDesc->hWave;
183     wom->avgSpeedOuter = wom->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
184     wom->nSamplesPerSecOuter = wom->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
185
186     for (i = ndlo; i < ndhi; i++) {
187         /* if no ACM stuff is involved, no need to handle callbacks at this
188          * level, this will be done transparently
189          */
190         if (waveOutOpen(&wom->u.out.hInnerWave, i, lpDesc->lpFormat, (DWORD)wodCallback,
191                         (DWORD)wom, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
192             wom->hAcmStream = 0;
193             goto found;
194         }
195     }
196
197     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0 && lpDesc->lpFormat->wFormatTag == WAVE_FORMAT_PCM) {
198         WAVEFORMATEX    wfx;
199
200         wfx.wFormatTag = WAVE_FORMAT_PCM;
201         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
202         /* try some ACM stuff */
203
204 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
205                         switch (res=wodOpenHelper(wom, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
206                             case MMSYSERR_NOERROR: wom->avgSpeedInner = wfx.nAvgBytesPerSec; wom->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
207                             case WAVERR_BADFORMAT: break; \
208                             default: goto error; \
209                         }
210
211         /* Our resampling algorithm is quite primitive so first try
212          * to just change the bit depth and number of channels
213          */
214         for (i = ndlo; i < ndhi; i++) {
215             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
216             wfx.nChannels = lpDesc->lpFormat->nChannels;
217             TRY(wfx.nSamplesPerSec, 16);
218             TRY(wfx.nSamplesPerSec, 8);
219             wfx.nChannels ^= 3;
220             TRY(wfx.nSamplesPerSec, 16);
221             TRY(wfx.nSamplesPerSec, 8);
222         }
223
224         for (i = ndlo; i < ndhi; i++) {
225             /* first try with same stereo/mono option as source */
226             wfx.nChannels = lpDesc->lpFormat->nChannels;
227             TRY(96000, 16);
228             TRY(48000, 16);
229             TRY(44100, 16);
230             TRY(22050, 16);
231             TRY(11025, 16);
232
233             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
234             wfx.nChannels ^= 3;
235             TRY(96000, 16);
236             TRY(48000, 16);
237             TRY(44100, 16);
238             TRY(22050, 16);
239             TRY(11025, 16);
240
241             /* first try with same stereo/mono option as source */
242             wfx.nChannels = lpDesc->lpFormat->nChannels;
243             TRY(96000, 8);
244             TRY(48000, 8);
245             TRY(44100, 8);
246             TRY(22050, 8);
247             TRY(11025, 8);
248
249             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
250             wfx.nChannels ^= 3;
251             TRY(96000, 8);
252             TRY(48000, 8);
253             TRY(44100, 8);
254             TRY(22050, 8);
255             TRY(11025, 8);
256         }
257 #undef TRY
258     }
259
260     HeapFree(GetProcessHeap(), 0, wom);
261     WARN("ret = WAVERR_BADFORMAT\n");
262     return WAVERR_BADFORMAT;
263
264 found:
265     if (dwFlags & WAVE_FORMAT_QUERY) {
266         *lpdwUser = 0L;
267         HeapFree(GetProcessHeap(), 0, wom);
268     } else {
269         *lpdwUser = (DWORD)wom;
270     }
271     return MMSYSERR_NOERROR;
272 error:
273     HeapFree(GetProcessHeap(), 0, wom);
274     if (res==ACMERR_NOTPOSSIBLE) {
275         WARN("ret = WAVERR_BADFORMAT\n");
276         return WAVERR_BADFORMAT;
277     }
278     WARN("ret = 0x%08lx\n", res);
279     return res;
280 }
281
282 static  DWORD   wodClose(WAVEMAPDATA* wom)
283 {
284     DWORD ret;
285
286     TRACE("(%p)\n", wom);
287
288     ret = waveOutClose(wom->u.out.hInnerWave);
289     if (ret == MMSYSERR_NOERROR) {
290         if (wom->hAcmStream) {
291             ret = acmStreamClose(wom->hAcmStream, 0);
292         }
293         if (ret == MMSYSERR_NOERROR) {
294             HeapFree(GetProcessHeap(), 0, wom);
295         }
296     }
297     return ret;
298 }
299
300 static  DWORD   wodWrite(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
301 {
302     PACMSTREAMHEADER    ash;
303     LPWAVEHDR           lpWaveHdrDst;
304
305     TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
306
307     if (!wom->hAcmStream) {
308         return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
309     }
310
311     lpWaveHdrSrc->dwFlags |= WHDR_INQUEUE;
312     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
313     /* acmStreamConvert will actually check that the new size is less than initial size */
314     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
315     if (acmStreamConvert(wom->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
316         WARN("acmStreamConvert failed\n");
317         return MMSYSERR_ERROR;
318     }
319
320     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
321     if (ash->cbSrcLength > ash->cbSrcLengthUsed)
322         FIXME("Not all src buffer has been written, expect bogus sound\n");
323     else if (ash->cbSrcLength < ash->cbSrcLengthUsed)
324         ERR("CoDec has read more data than it is allowed to\n");
325
326     if (ash->cbDstLengthUsed == 0) {
327         /* something went wrong in decoding */
328         FIXME("Got 0 length\n");
329         return MMSYSERR_ERROR;
330     }
331     lpWaveHdrDst->dwBufferLength = ash->cbDstLengthUsed;
332     return waveOutWrite(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
333 }
334
335 static  DWORD   wodPrepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
336 {
337     PACMSTREAMHEADER    ash;
338     DWORD               size;
339     DWORD               dwRet;
340     LPWAVEHDR           lpWaveHdrDst;
341
342     TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
343
344     if (!wom->hAcmStream)
345         return waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
346
347     if (acmStreamSize(wom->hAcmStream, lpWaveHdrSrc->dwBufferLength, &size, ACM_STREAMSIZEF_SOURCE) != MMSYSERR_NOERROR) {
348         WARN("acmStreamSize failed\n");
349         return MMSYSERR_ERROR;
350     }
351
352     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
353     if (ash == NULL) {
354         WARN("no memory\n");
355         return MMSYSERR_NOMEM;
356     }
357
358     ash->cbStruct = sizeof(*ash);
359     ash->fdwStatus = 0L;
360     ash->dwUser = (DWORD)lpWaveHdrSrc;
361     ash->pbSrc = lpWaveHdrSrc->lpData;
362     ash->cbSrcLength = lpWaveHdrSrc->dwBufferLength;
363     /* ash->cbSrcLengthUsed */
364     ash->dwSrcUser = lpWaveHdrSrc->dwUser; /* FIXME ? */
365     ash->pbDst = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
366     ash->cbDstLength = size;
367     /* ash->cbDstLengthUsed */
368     ash->dwDstUser = 0; /* FIXME ? */
369     dwRet = acmStreamPrepareHeader(wom->hAcmStream, ash, 0L);
370     if (dwRet != MMSYSERR_NOERROR) {
371         WARN("acmStreamPrepareHeader failed\n");
372         goto errCleanUp;
373     }
374
375     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
376     lpWaveHdrDst->lpData = ash->pbDst;
377     lpWaveHdrDst->dwBufferLength = size; /* conversion is not done yet */
378     lpWaveHdrDst->dwFlags = 0;
379     lpWaveHdrDst->dwLoops = 0;
380     dwRet = waveOutPrepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
381     if (dwRet != MMSYSERR_NOERROR) {
382         WARN("waveOutPrepareHeader failed\n");
383         goto errCleanUp;
384     }
385
386     lpWaveHdrSrc->reserved = (DWORD)ash;
387     lpWaveHdrSrc->dwFlags = WHDR_PREPARED;
388     TRACE("=> (0)\n");
389     return MMSYSERR_NOERROR;
390 errCleanUp:
391     TRACE("=> (%ld)\n", dwRet);
392     HeapFree(GetProcessHeap(), 0, ash);
393     return dwRet;
394 }
395
396 static  DWORD   wodUnprepare(WAVEMAPDATA* wom, LPWAVEHDR lpWaveHdrSrc, DWORD dwParam2)
397 {
398     PACMSTREAMHEADER    ash;
399     LPWAVEHDR           lpWaveHdrDst;
400     DWORD               dwRet1, dwRet2;
401
402     TRACE("(%p %p %08lx)\n", wom, lpWaveHdrSrc, dwParam2);
403
404     if (!wom->hAcmStream) {
405         return waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrSrc, dwParam2);
406     }
407     ash = (PACMSTREAMHEADER)lpWaveHdrSrc->reserved;
408     dwRet1 = acmStreamUnprepareHeader(wom->hAcmStream, ash, 0L);
409
410     lpWaveHdrDst = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
411     dwRet2 = waveOutUnprepareHeader(wom->u.out.hInnerWave, lpWaveHdrDst, sizeof(*lpWaveHdrDst));
412
413     HeapFree(GetProcessHeap(), 0, ash);
414
415     lpWaveHdrSrc->dwFlags &= ~WHDR_PREPARED;
416     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
417 }
418
419 static  DWORD   wodGetPosition(WAVEMAPDATA* wom, LPMMTIME lpTime, DWORD dwParam2)
420 {
421     DWORD       val;
422     MMTIME      timepos;
423     TRACE("(%p %p %08lx)\n", wom, lpTime, dwParam2);
424
425     memcpy(&timepos, lpTime, sizeof(timepos));
426
427     /* For TIME_MS, we're going to recalculate using TIME_BYTES */
428     if (lpTime->wType == TIME_MS)
429         timepos.wType = TIME_BYTES;
430
431     val = waveOutGetPosition(wom->u.out.hInnerWave, &timepos, dwParam2);
432
433     if (lpTime->wType == TIME_BYTES || lpTime->wType == TIME_MS)
434     {
435         DWORD dwInnerSamplesPerOuter = wom->nSamplesPerSecInner / wom->nSamplesPerSecOuter;
436         if (dwInnerSamplesPerOuter > 0)
437         {
438             DWORD dwInnerBytesPerSample = wom->avgSpeedInner / wom->nSamplesPerSecInner;
439             DWORD dwInnerBytesPerOuterSample = dwInnerBytesPerSample * dwInnerSamplesPerOuter;
440             DWORD remainder = 0;
441
442             /* If we are up sampling (going from lower sample rate to higher),
443             **   we need to make a special accomodation for times when we've
444             **   written a partial output sample.  This happens frequently
445             **   to us because we use msacm to do our up sampling, and it
446             **   will up sample on an unaligned basis.
447             ** For example, if you convert a 2 byte wide 8,000 'outer'
448             **   buffer to a 2 byte wide 48,000 inner device, you would
449             **   expect 2 bytes of input to produce 12 bytes of output.
450             **   Instead, msacm will produce 8 bytes of output.
451             **   But reporting our position as 1 byte of output is
452             **   nonsensical; the output buffer position needs to be
453             **   aligned on outer sample size, and aggressively rounded up.
454             */
455             remainder = timepos.u.cb % dwInnerBytesPerOuterSample;
456             if (remainder > 0)
457             {
458                 timepos.u.cb -= remainder;
459                 timepos.u.cb += dwInnerBytesPerOuterSample;
460             }
461         }
462
463         lpTime->u.cb = MulDiv(timepos.u.cb, wom->avgSpeedOuter, wom->avgSpeedInner);
464
465         /* Once we have the TIME_BYTES right, we can easily convert to TIME_MS */
466         if (lpTime->wType == TIME_MS)
467             lpTime->u.cb = MulDiv(lpTime->u.cb, 1000, wom->avgSpeedOuter);
468     }
469     else if (lpTime->wType == TIME_SAMPLES)
470         lpTime->u.cb = MulDiv(timepos.u.cb, wom->nSamplesPerSecOuter, wom->nSamplesPerSecInner);
471     else
472         /* other time types don't require conversion */
473         lpTime->u = timepos.u;
474
475     return val;
476 }
477
478 static  DWORD   wodGetDevCaps(UINT wDevID, WAVEMAPDATA* wom, LPWAVEOUTCAPSW lpWaveCaps, DWORD dwParam2)
479 {
480     static const WCHAR name[] = {'W','i','n','e',' ','w','a','v','e',' ','o','u','t',' ','m','a','p','p','e','r',0};
481
482     TRACE("(%04x %p %p %08lx)\n",wDevID, wom, lpWaveCaps, dwParam2);
483
484     /* if opened low driver, forward message */
485     if (WAVEMAP_IsData(wom))
486         return waveOutGetDevCapsW((UINT)wom->u.out.hInnerWave, lpWaveCaps, dwParam2);
487     /* else if no drivers, nothing to map so return bad device */
488     if (waveOutGetNumDevs() == 0) {
489         WARN("bad device id\n");
490         return MMSYSERR_BADDEVICEID;
491     }
492     /* otherwise, return caps of mapper itself */
493     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
494         WAVEOUTCAPSW woc;
495         woc.wMid = 0x00FF;
496         woc.wPid = 0x0001;
497         woc.vDriverVersion = 0x0100;
498         lstrcpyW(woc.szPname, name);
499         woc.dwFormats =
500             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
501             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
502             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
503             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
504             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
505         woc.wChannels = 2;
506         woc.dwSupport = WAVECAPS_VOLUME | WAVECAPS_LRVOLUME;
507         memcpy(lpWaveCaps, &woc, min(dwParam2, sizeof(woc)));
508
509         return MMSYSERR_NOERROR;
510     }
511     ERR("This shouldn't happen\n");
512     return MMSYSERR_ERROR;
513 }
514
515 static  DWORD   wodGetVolume(UINT wDevID, WAVEMAPDATA* wom, LPDWORD lpVol)
516 {
517     TRACE("(%04x %p %p)\n",wDevID, wom, lpVol);
518
519     if (WAVEMAP_IsData(wom))
520         return waveOutGetVolume(wom->u.out.hInnerWave, lpVol);
521     return MMSYSERR_NOERROR;
522 }
523
524 static  DWORD   wodSetVolume(UINT wDevID, WAVEMAPDATA* wom, DWORD vol)
525 {
526     TRACE("(%04x %p %08lx)\n",wDevID, wom, vol);
527
528     if (WAVEMAP_IsData(wom))
529         return waveOutSetVolume(wom->u.out.hInnerWave, vol);
530     return MMSYSERR_NOERROR;
531 }
532
533 static  DWORD   wodPause(WAVEMAPDATA* wom)
534 {
535     TRACE("(%p)\n",wom);
536
537     return waveOutPause(wom->u.out.hInnerWave);
538 }
539
540 static  DWORD   wodRestart(WAVEMAPDATA* wom)
541 {
542     TRACE("(%p)\n",wom);
543
544     return waveOutRestart(wom->u.out.hInnerWave);
545 }
546
547 static  DWORD   wodReset(WAVEMAPDATA* wom)
548 {
549     TRACE("(%p)\n",wom);
550
551     return waveOutReset(wom->u.out.hInnerWave);
552 }
553
554 static  DWORD   wodBreakLoop(WAVEMAPDATA* wom)
555 {
556     TRACE("(%p)\n",wom);
557
558     return waveOutBreakLoop(wom->u.out.hInnerWave);
559 }
560
561 static  DWORD   wodMapperStatus(WAVEMAPDATA* wom, DWORD flags, LPVOID ptr)
562 {
563     UINT        id;
564     DWORD       ret = MMSYSERR_NOTSUPPORTED;
565
566     TRACE("(%p %08lx %p)\n",wom, flags, ptr);
567
568     switch (flags) {
569     case WAVEOUT_MAPPER_STATUS_DEVICE:
570         ret = waveOutGetID(wom->u.out.hInnerWave, &id);
571         *(LPDWORD)ptr = id;
572         break;
573     case WAVEOUT_MAPPER_STATUS_MAPPED:
574         FIXME("Unsupported flag=%ld\n", flags);
575         *(LPDWORD)ptr = 0; /* FIXME ?? */
576         break;
577     case WAVEOUT_MAPPER_STATUS_FORMAT:
578         FIXME("Unsupported flag=%ld\n", flags);
579         /* ptr points to a WAVEFORMATEX struct - before or after streaming ? */
580         *(LPDWORD)ptr = 0;
581         break;
582     default:
583         FIXME("Unsupported flag=%ld\n", flags);
584         *(LPDWORD)ptr = 0;
585         break;
586     }
587     return ret;
588 }
589
590 /**************************************************************************
591  *                              wodMessage (MSACM.@)
592  */
593 DWORD WINAPI WAVEMAP_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
594                                 DWORD dwParam1, DWORD dwParam2)
595 {
596     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
597           wDevID, wMsg, dwUser, dwParam1, dwParam2);
598
599     switch (wMsg) {
600     case DRVM_INIT:
601     case DRVM_EXIT:
602     case DRVM_ENABLE:
603     case DRVM_DISABLE:
604         /* FIXME: Pretend this is supported */
605         return 0;
606     case WODM_OPEN:             return wodOpen          ((LPDWORD)dwUser,      (LPWAVEOPENDESC)dwParam1,dwParam2);
607     case WODM_CLOSE:            return wodClose         ((WAVEMAPDATA*)dwUser);
608     case WODM_WRITE:            return wodWrite         ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
609     case WODM_PAUSE:            return wodPause         ((WAVEMAPDATA*)dwUser);
610     case WODM_GETPOS:           return wodGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
611     case WODM_BREAKLOOP:        return wodBreakLoop     ((WAVEMAPDATA*)dwUser);
612     case WODM_PREPARE:          return wodPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
613     case WODM_UNPREPARE:        return wodUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
614     case WODM_GETDEVCAPS:       return wodGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEOUTCAPSW)dwParam1,dwParam2);
615     case WODM_GETNUMDEVS:       return 1;
616     case WODM_GETPITCH:         return MMSYSERR_NOTSUPPORTED;
617     case WODM_SETPITCH:         return MMSYSERR_NOTSUPPORTED;
618     case WODM_GETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
619     case WODM_SETPLAYBACKRATE:  return MMSYSERR_NOTSUPPORTED;
620     case WODM_GETVOLUME:        return wodGetVolume     (wDevID, (WAVEMAPDATA*)dwUser, (LPDWORD)dwParam1);
621     case WODM_SETVOLUME:        return wodSetVolume     (wDevID, (WAVEMAPDATA*)dwUser, dwParam1);
622     case WODM_RESTART:          return wodRestart       ((WAVEMAPDATA*)dwUser);
623     case WODM_RESET:            return wodReset         ((WAVEMAPDATA*)dwUser);
624     case WODM_MAPPER_STATUS:    return wodMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
625     /* known but not supported */
626     case DRV_QUERYDEVICEINTERFACESIZE:
627     case DRV_QUERYDEVICEINTERFACE:
628         return MMSYSERR_NOTSUPPORTED;
629     default:
630         FIXME("unknown message %d!\n", wMsg);
631     }
632     return MMSYSERR_NOTSUPPORTED;
633 }
634
635 /*======================================================================*
636  *                  WAVE IN part                                        *
637  *======================================================================*/
638
639 static void     CALLBACK widCallback(HWAVEIN hWave, UINT uMsg, DWORD dwInstance,
640                                      DWORD dwParam1, DWORD dwParam2)
641 {
642     WAVEMAPDATA*        wim = (WAVEMAPDATA*)dwInstance;
643
644     TRACE("(%p %u %ld %lx %lx);\n", hWave, uMsg, dwInstance, dwParam1, dwParam2);
645
646     if (!WAVEMAP_IsData(wim)) {
647         ERR("Bad data\n");
648         return;
649     }
650
651     if (hWave != wim->u.in.hInnerWave && uMsg != WIM_OPEN)
652         ERR("Shouldn't happen (%p %p)\n", hWave, wim->u.in.hInnerWave);
653
654     switch (uMsg) {
655     case WIM_OPEN:
656     case WIM_CLOSE:
657         /* dwParam1 & dwParam2 are supposed to be 0, nothing to do */
658         break;
659     case WIM_DATA:
660         if (wim->hAcmStream) {
661             LPWAVEHDR           lpWaveHdrSrc = (LPWAVEHDR)dwParam1;
662             PACMSTREAMHEADER    ash = (PACMSTREAMHEADER)((LPSTR)lpWaveHdrSrc - sizeof(ACMSTREAMHEADER));
663             LPWAVEHDR           lpWaveHdrDst = (LPWAVEHDR)ash->dwUser;
664
665             /* convert data just gotten from waveIn into requested format */
666             if (acmStreamConvert(wim->hAcmStream, ash, 0L) != MMSYSERR_NOERROR) {
667                 ERR("ACM conversion failed\n");
668                 return;
669             } else {
670                 TRACE("Converted %ld bytes into %ld\n", ash->cbSrcLengthUsed, ash->cbDstLengthUsed);
671             }
672             /* and setup the wavehdr to return accordingly */
673             lpWaveHdrDst->dwFlags &= ~WHDR_INQUEUE;
674             lpWaveHdrDst->dwFlags |= WHDR_DONE;
675             lpWaveHdrDst->dwBytesRecorded = ash->cbDstLengthUsed;
676             dwParam1 = (DWORD)lpWaveHdrDst;
677         }
678         break;
679     default:
680         ERR("Unknown msg %u\n", uMsg);
681     }
682
683     DriverCallback(wim->dwCallback, HIWORD(wim->dwFlags), (HDRVR)wim->u.in.hOuterWave,
684                    uMsg, wim->dwClientInstance, dwParam1, dwParam2);
685 }
686
687 static  DWORD   widOpenHelper(WAVEMAPDATA* wim, UINT idx,
688                               LPWAVEOPENDESC lpDesc, LPWAVEFORMATEX lpwfx,
689                               DWORD dwFlags)
690 {
691     DWORD       ret;
692
693     TRACE("(%p %04x %p %p %08lx)\n", wim, idx, lpDesc, lpwfx, dwFlags);
694
695     /* source is always PCM, so the formulas below apply */
696     lpwfx->nBlockAlign = (lpwfx->nChannels * lpwfx->wBitsPerSample) / 8;
697     lpwfx->nAvgBytesPerSec = lpwfx->nSamplesPerSec * lpwfx->nBlockAlign;
698     if (dwFlags & WAVE_FORMAT_QUERY) {
699         ret = acmStreamOpen(NULL, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, ACM_STREAMOPENF_QUERY);
700     } else {
701         ret = acmStreamOpen(&wim->hAcmStream, 0, lpwfx, lpDesc->lpFormat, NULL, 0L, 0L, 0L);
702     }
703     if (ret == MMSYSERR_NOERROR) {
704         ret = waveInOpen(&wim->u.in.hInnerWave, idx, lpwfx, (DWORD)widCallback,
705                          (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION);
706         if (ret != MMSYSERR_NOERROR && !(dwFlags & WAVE_FORMAT_QUERY)) {
707             acmStreamClose(wim->hAcmStream, 0);
708             wim->hAcmStream = 0;
709         }
710     }
711     TRACE("ret = %08lx\n", ret);
712     return ret;
713 }
714
715 static  DWORD   widOpen(LPDWORD lpdwUser, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
716 {
717     UINT                ndlo, ndhi;
718     UINT                i;
719     WAVEMAPDATA*        wim = HeapAlloc(GetProcessHeap(), 0, sizeof(WAVEMAPDATA));
720     DWORD               res;
721
722     TRACE("(%p %p %08lx)\n", lpdwUser, lpDesc, dwFlags);
723
724     if (!wim) {
725         WARN("no memory\n");
726         return MMSYSERR_NOMEM;
727     }
728
729     wim->self = wim;
730     wim->dwCallback = lpDesc->dwCallback;
731     wim->dwFlags = dwFlags;
732     wim->dwClientInstance = lpDesc->dwInstance;
733     wim->u.in.hOuterWave = (HWAVEIN)lpDesc->hWave;
734
735     ndhi = waveInGetNumDevs();
736     if (dwFlags & WAVE_MAPPED) {
737         if (lpDesc->uMappedDeviceID >= ndhi) return MMSYSERR_INVALPARAM;
738         ndlo = lpDesc->uMappedDeviceID;
739         ndhi = ndlo + 1;
740         dwFlags &= ~WAVE_MAPPED;
741     } else {
742         ndlo = 0;
743     }
744
745     wim->avgSpeedOuter = wim->avgSpeedInner = lpDesc->lpFormat->nAvgBytesPerSec;
746     wim->nSamplesPerSecOuter = wim->nSamplesPerSecInner = lpDesc->lpFormat->nSamplesPerSec;
747
748     for (i = ndlo; i < ndhi; i++) {
749         if (waveInOpen(&wim->u.in.hInnerWave, i, lpDesc->lpFormat, (DWORD)widCallback,
750                        (DWORD)wim, (dwFlags & ~CALLBACK_TYPEMASK) | CALLBACK_FUNCTION | WAVE_FORMAT_DIRECT) == MMSYSERR_NOERROR) {
751             wim->hAcmStream = 0;
752             goto found;
753         }
754     }
755
756     if ((dwFlags & WAVE_FORMAT_DIRECT) == 0)
757     {
758         WAVEFORMATEX    wfx;
759
760         wfx.wFormatTag = WAVE_FORMAT_PCM;
761         wfx.cbSize = 0; /* normally, this field is not used for PCM format, just in case */
762         /* try some ACM stuff */
763
764 #define TRY(sps,bps)    wfx.nSamplesPerSec = (sps); wfx.wBitsPerSample = (bps); \
765                         switch (res=widOpenHelper(wim, i, lpDesc, &wfx, dwFlags | WAVE_FORMAT_DIRECT)) { \
766                         case MMSYSERR_NOERROR: wim->avgSpeedInner = wfx.nAvgBytesPerSec; wim->nSamplesPerSecInner = wfx.nSamplesPerSec; goto found; \
767                         case WAVERR_BADFORMAT: break; \
768                         default: goto error; \
769                         }
770
771         for (i = ndlo; i < ndhi; i++) {
772             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
773             /* first try with same stereo/mono option as source */
774             wfx.nChannels = lpDesc->lpFormat->nChannels;
775                         TRY(wfx.nSamplesPerSec, 16);
776                         TRY(wfx.nSamplesPerSec, 8);
777                         wfx.nChannels ^= 3;
778                         TRY(wfx.nSamplesPerSec, 16);
779                         TRY(wfx.nSamplesPerSec, 8);
780         }
781
782         for (i = ndlo; i < ndhi; i++) {
783             wfx.nSamplesPerSec=lpDesc->lpFormat->nSamplesPerSec;
784             /* first try with same stereo/mono option as source */
785             wfx.nChannels = lpDesc->lpFormat->nChannels;
786             TRY(96000, 16);
787             TRY(48000, 16);
788             TRY(44100, 16);
789             TRY(22050, 16);
790             TRY(11025, 16);
791
792             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
793             wfx.nChannels ^= 3;
794             TRY(96000, 16);
795             TRY(48000, 16);
796             TRY(44100, 16);
797             TRY(22050, 16);
798             TRY(11025, 16);
799
800             /* first try with same stereo/mono option as source */
801             wfx.nChannels = lpDesc->lpFormat->nChannels;
802             TRY(96000, 8);
803             TRY(48000, 8);
804             TRY(44100, 8);
805             TRY(22050, 8);
806             TRY(11025, 8);
807
808             /* 2^3 => 1, 1^3 => 2, so if stereo, try mono (and the other way around) */
809             wfx.nChannels ^= 3;
810             TRY(96000, 8);
811             TRY(48000, 8);
812             TRY(44100, 8);
813             TRY(22050, 8);
814             TRY(11025, 8);
815         }
816 #undef TRY
817     }
818
819     HeapFree(GetProcessHeap(), 0, wim);
820     WARN("ret = WAVERR_BADFORMAT\n");
821     return WAVERR_BADFORMAT;
822 found:
823     if (dwFlags & WAVE_FORMAT_QUERY) {
824         *lpdwUser = 0L;
825         HeapFree(GetProcessHeap(), 0, wim);
826     } else {
827         *lpdwUser = (DWORD)wim;
828     }
829     TRACE("Ok (stream=%08lx)\n", (DWORD)wim->hAcmStream);
830     return MMSYSERR_NOERROR;
831 error:
832     HeapFree(GetProcessHeap(), 0, wim);
833     if (res==ACMERR_NOTPOSSIBLE) {
834         WARN("ret = WAVERR_BADFORMAT\n");
835         return WAVERR_BADFORMAT;
836     }
837     WARN("ret = 0x%08lx\n", res);
838     return res;
839 }
840
841 static  DWORD   widClose(WAVEMAPDATA* wim)
842 {
843     DWORD ret;
844
845     TRACE("(%p)\n", wim);
846
847     ret = waveInClose(wim->u.in.hInnerWave);
848     if (ret == MMSYSERR_NOERROR) {
849         if (wim->hAcmStream) {
850             ret = acmStreamClose(wim->hAcmStream, 0);
851         }
852         if (ret == MMSYSERR_NOERROR) {
853             HeapFree(GetProcessHeap(), 0, wim);
854         }
855     }
856     return ret;
857 }
858
859 static  DWORD   widAddBuffer(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
860 {
861     PACMSTREAMHEADER    ash;
862     LPWAVEHDR           lpWaveHdrSrc;
863
864     TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
865
866     if (!wim->hAcmStream) {
867         return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
868     }
869
870     lpWaveHdrDst->dwFlags |= WHDR_INQUEUE;
871     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
872
873     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
874     return waveInAddBuffer(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
875 }
876
877 static  DWORD   widPrepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
878 {
879     PACMSTREAMHEADER    ash;
880     DWORD               size;
881     DWORD               dwRet;
882     LPWAVEHDR           lpWaveHdrSrc;
883
884     TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
885
886     if (!wim->hAcmStream) {
887         return waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
888     }
889     if (acmStreamSize(wim->hAcmStream, lpWaveHdrDst->dwBufferLength, &size,
890                       ACM_STREAMSIZEF_DESTINATION) != MMSYSERR_NOERROR) {
891         WARN("acmStreamSize failed\n");
892         return MMSYSERR_ERROR;
893     }
894
895     ash = HeapAlloc(GetProcessHeap(), 0, sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR) + size);
896     if (ash == NULL) {
897         WARN("no memory\n");
898         return MMSYSERR_NOMEM;
899     }
900
901     ash->cbStruct = sizeof(*ash);
902     ash->fdwStatus = 0L;
903     ash->dwUser = (DWORD)lpWaveHdrDst;
904     ash->pbSrc = (LPSTR)ash + sizeof(ACMSTREAMHEADER) + sizeof(WAVEHDR);
905     ash->cbSrcLength = size;
906     /* ash->cbSrcLengthUsed */
907     ash->dwSrcUser = 0L; /* FIXME ? */
908     ash->pbDst = lpWaveHdrDst->lpData;
909     ash->cbDstLength = lpWaveHdrDst->dwBufferLength;
910     /* ash->cbDstLengthUsed */
911     ash->dwDstUser = lpWaveHdrDst->dwUser; /* FIXME ? */
912     dwRet = acmStreamPrepareHeader(wim->hAcmStream, ash, 0L);
913     if (dwRet != MMSYSERR_NOERROR) {
914         WARN("acmStreamPrepareHeader failed\n");
915         goto errCleanUp;
916     }
917
918     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
919     lpWaveHdrSrc->lpData = ash->pbSrc;
920     lpWaveHdrSrc->dwBufferLength = size; /* conversion is not done yet */
921     lpWaveHdrSrc->dwFlags = 0;
922     lpWaveHdrSrc->dwLoops = 0;
923     dwRet = waveInPrepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
924     if (dwRet != MMSYSERR_NOERROR) {
925         WARN("waveInPrepareHeader failed\n");
926         goto errCleanUp;
927     }
928
929     lpWaveHdrDst->reserved = (DWORD)ash;
930     lpWaveHdrDst->dwFlags = WHDR_PREPARED;
931     TRACE("=> (0)\n");
932     return MMSYSERR_NOERROR;
933 errCleanUp:
934     TRACE("=> (%ld)\n", dwRet);
935     HeapFree(GetProcessHeap(), 0, ash);
936     return dwRet;
937 }
938
939 static  DWORD   widUnprepare(WAVEMAPDATA* wim, LPWAVEHDR lpWaveHdrDst, DWORD dwParam2)
940 {
941     PACMSTREAMHEADER    ash;
942     LPWAVEHDR           lpWaveHdrSrc;
943     DWORD               dwRet1, dwRet2;
944
945     TRACE("(%p %p %08lx)\n", wim, lpWaveHdrDst, dwParam2);
946
947     if (!wim->hAcmStream) {
948         return waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrDst, dwParam2);
949     }
950     ash = (PACMSTREAMHEADER)lpWaveHdrDst->reserved;
951     dwRet1 = acmStreamUnprepareHeader(wim->hAcmStream, ash, 0L);
952
953     lpWaveHdrSrc = (LPWAVEHDR)((LPSTR)ash + sizeof(ACMSTREAMHEADER));
954     dwRet2 = waveInUnprepareHeader(wim->u.in.hInnerWave, lpWaveHdrSrc, sizeof(*lpWaveHdrSrc));
955
956     HeapFree(GetProcessHeap(), 0, ash);
957
958     lpWaveHdrDst->dwFlags &= ~WHDR_PREPARED;
959     return (dwRet1 == MMSYSERR_NOERROR) ? dwRet2 : dwRet1;
960 }
961
962 static  DWORD   widGetPosition(WAVEMAPDATA* wim, LPMMTIME lpTime, DWORD dwParam2)
963 {
964     DWORD       val;
965
966     TRACE("(%p %p %08lx)\n", wim, lpTime, dwParam2);
967
968     val = waveInGetPosition(wim->u.in.hInnerWave, lpTime, dwParam2);
969     if (lpTime->wType == TIME_BYTES)
970         lpTime->u.cb = MulDiv(lpTime->u.cb, wim->avgSpeedOuter, wim->avgSpeedInner);
971     if (lpTime->wType == TIME_SAMPLES)
972         lpTime->u.cb = MulDiv(lpTime->u.cb, wim->nSamplesPerSecOuter, wim->nSamplesPerSecInner);
973     /* other time types don't require conversion */
974     return val;
975 }
976
977 static  DWORD   widGetDevCaps(UINT wDevID, WAVEMAPDATA* wim, LPWAVEINCAPSW lpWaveCaps, DWORD dwParam2)
978 {
979     TRACE("(%04x, %p %p %08lx)\n", wDevID, wim, lpWaveCaps, dwParam2);
980
981     /* if opened low driver, forward message */
982     if (WAVEMAP_IsData(wim))
983         return waveInGetDevCapsW((UINT)wim->u.in.hInnerWave, lpWaveCaps, dwParam2);
984     /* else if no drivers, nothing to map so return bad device */
985     if (waveInGetNumDevs() == 0) {
986         WARN("bad device id\n");
987         return MMSYSERR_BADDEVICEID;
988     }
989     /* otherwise, return caps of mapper itself */
990     if (wDevID == (UINT)-1 || wDevID == (UINT16)-1) {
991         WAVEINCAPSW wic;
992         static const WCHAR init[] = {'W','i','n','e',' ','w','a','v','e',' ','i','n',' ','m','a','p','p','e','r',0};
993         wic.wMid = 0x00FF;
994         wic.wPid = 0x0001;
995         wic.vDriverVersion = 0x0001;
996         strcpyW(wic.szPname, init);
997         wic.dwFormats =
998             WAVE_FORMAT_96M08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_96M16 | WAVE_FORMAT_96S16 |
999             WAVE_FORMAT_48M08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_48M16 | WAVE_FORMAT_48S16 |
1000             WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S16 |
1001             WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S16 |
1002             WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1S16;
1003         wic.wChannels = 2;
1004         memcpy(lpWaveCaps, &wic, min(dwParam2, sizeof(wic)));
1005
1006         return MMSYSERR_NOERROR;
1007     }
1008     ERR("This shouldn't happen\n");
1009     return MMSYSERR_ERROR;
1010 }
1011
1012 static  DWORD   widStop(WAVEMAPDATA* wim)
1013 {
1014     TRACE("(%p)\n", wim);
1015
1016     return waveInStop(wim->u.in.hInnerWave);
1017 }
1018
1019 static  DWORD   widStart(WAVEMAPDATA* wim)
1020 {
1021     TRACE("(%p)\n", wim);
1022
1023     return waveInStart(wim->u.in.hInnerWave);
1024 }
1025
1026 static  DWORD   widReset(WAVEMAPDATA* wim)
1027 {
1028     TRACE("(%p)\n", wim);
1029
1030     return waveInReset(wim->u.in.hInnerWave);
1031 }
1032
1033 static  DWORD   widMapperStatus(WAVEMAPDATA* wim, DWORD flags, LPVOID ptr)
1034 {
1035     UINT        id;
1036     DWORD       ret = MMSYSERR_NOTSUPPORTED;
1037
1038     TRACE("(%p %08lx %p)\n", wim, flags, ptr);
1039
1040     switch (flags) {
1041     case WAVEIN_MAPPER_STATUS_DEVICE:
1042         ret = waveInGetID(wim->u.in.hInnerWave, &id);
1043         *(LPDWORD)ptr = id;
1044         break;
1045     case WAVEIN_MAPPER_STATUS_MAPPED:
1046         FIXME("Unsupported yet flag=%ld\n", flags);
1047         *(LPDWORD)ptr = 0; /* FIXME ?? */
1048         break;
1049     case WAVEIN_MAPPER_STATUS_FORMAT:
1050         FIXME("Unsupported flag=%ld\n", flags);
1051         /* ptr points to a WAVEFORMATEX struct  - before or after streaming ? */
1052         *(LPDWORD)ptr = 0; /* FIXME ?? */
1053         break;
1054     default:
1055         FIXME("Unsupported flag=%ld\n", flags);
1056         *(LPDWORD)ptr = 0;
1057         break;
1058     }
1059     return ret;
1060 }
1061
1062 /**************************************************************************
1063  *                              widMessage (MSACM.@)
1064  */
1065 DWORD WINAPI WAVEMAP_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1066                                 DWORD dwParam1, DWORD dwParam2)
1067 {
1068     TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1069           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1070
1071     switch (wMsg) {
1072     case DRVM_INIT:
1073     case DRVM_EXIT:
1074     case DRVM_ENABLE:
1075     case DRVM_DISABLE:
1076         /* FIXME: Pretend this is supported */
1077         return 0;
1078
1079     case WIDM_OPEN:             return widOpen          ((LPDWORD)dwUser,     (LPWAVEOPENDESC)dwParam1, dwParam2);
1080     case WIDM_CLOSE:            return widClose         ((WAVEMAPDATA*)dwUser);
1081
1082     case WIDM_ADDBUFFER:        return widAddBuffer     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
1083     case WIDM_PREPARE:          return widPrepare       ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
1084     case WIDM_UNPREPARE:        return widUnprepare     ((WAVEMAPDATA*)dwUser, (LPWAVEHDR)dwParam1,     dwParam2);
1085     case WIDM_GETDEVCAPS:       return widGetDevCaps    (wDevID, (WAVEMAPDATA*)dwUser, (LPWAVEINCAPSW)dwParam1, dwParam2);
1086     case WIDM_GETNUMDEVS:       return 1;
1087     case WIDM_GETPOS:           return widGetPosition   ((WAVEMAPDATA*)dwUser, (LPMMTIME)dwParam1,      dwParam2);
1088     case WIDM_RESET:            return widReset         ((WAVEMAPDATA*)dwUser);
1089     case WIDM_START:            return widStart         ((WAVEMAPDATA*)dwUser);
1090     case WIDM_STOP:             return widStop          ((WAVEMAPDATA*)dwUser);
1091     case WIDM_MAPPER_STATUS:    return widMapperStatus  ((WAVEMAPDATA*)dwUser, dwParam1, (LPVOID)dwParam2);
1092     /* known but not supported */
1093     case DRV_QUERYDEVICEINTERFACESIZE:
1094     case DRV_QUERYDEVICEINTERFACE:
1095         return MMSYSERR_NOTSUPPORTED;
1096     default:
1097         FIXME("unknown message %u!\n", wMsg);
1098     }
1099     return MMSYSERR_NOTSUPPORTED;
1100 }
1101
1102 /*======================================================================*
1103  *                  Driver part                                         *
1104  *======================================================================*/
1105
1106 static  struct WINE_WAVEMAP* oss = NULL;
1107
1108 /**************************************************************************
1109  *                              WAVEMAP_drvOpen                 [internal]
1110  */
1111 static  DWORD   WAVEMAP_drvOpen(LPSTR str)
1112 {
1113     TRACE("(%p)\n", str);
1114
1115     if (oss)
1116         return 0;
1117
1118     /* I know, this is ugly, but who cares... */
1119     oss = (struct WINE_WAVEMAP*)1;
1120     return 1;
1121 }
1122
1123 /**************************************************************************
1124  *                              WAVEMAP_drvClose                [internal]
1125  */
1126 static  DWORD   WAVEMAP_drvClose(DWORD dwDevID)
1127 {
1128     TRACE("(%08lx)\n", dwDevID);
1129
1130     if (oss) {
1131         oss = NULL;
1132         return 1;
1133     }
1134     return 0;
1135 }
1136
1137 /**************************************************************************
1138  *                              DriverProc (MSACM.@)
1139  */
1140 LONG CALLBACK   WAVEMAP_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
1141                                    DWORD dwParam1, DWORD dwParam2)
1142 {
1143     TRACE("(%08lX, %p, %08lX, %08lX, %08lX)\n",
1144           dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1145
1146     switch(wMsg) {
1147     case DRV_LOAD:              return 1;
1148     case DRV_FREE:              return 1;
1149     case DRV_OPEN:              return WAVEMAP_drvOpen((LPSTR)dwParam1);
1150     case DRV_CLOSE:             return WAVEMAP_drvClose(dwDevID);
1151     case DRV_ENABLE:            return 1;
1152     case DRV_DISABLE:           return 1;
1153     case DRV_QUERYCONFIGURE:    return 1;
1154     case DRV_CONFIGURE:         MessageBoxA(0, "WAVEMAP MultiMedia Driver !", "Wave mapper Driver", MB_OK);     return 1;
1155     case DRV_INSTALL:           return DRVCNF_RESTART;
1156     case DRV_REMOVE:            return DRVCNF_RESTART;
1157     default:
1158         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1159     }
1160 }