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