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