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