- corrected control positions
[wine] / dlls / msacm32 / stream.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  *      MSACM32 library
5  *
6  *      Copyright 1998  Patrik Stridvall
7  *                1999  Eric Pouech
8  */
9
10 /* TODO
11  *      + asynchronous conversion is not implemented
12  *      + callback/notification
13  *      * acmStreamMessage
14  *      + properly close ACM streams
15  */
16
17 #include "winbase.h"
18 #include "winerror.h"
19 #include "windef.h"
20 #include "debugtools.h"
21 #include "mmsystem.h"
22 #include "msacm.h"
23 #include "msacmdrv.h"
24 #include "wineacm.h"
25
26 DEFAULT_DEBUG_CHANNEL(msacm)
27     
28 static PWINE_ACMSTREAM  ACM_GetStream(HACMSTREAM has)
29 {
30     return (PWINE_ACMSTREAM)has;
31 }
32
33 /***********************************************************************
34  *           acmStreamClose (MSACM32.37)
35  */
36 MMRESULT WINAPI acmStreamClose(HACMSTREAM has, DWORD fdwClose)
37 {
38     PWINE_ACMSTREAM     was;
39     MMRESULT            ret;
40                 
41     TRACE("(0x%08x, %ld)\n", has, fdwClose);
42     
43     if ((was = ACM_GetStream(has)) == NULL) {
44         return MMSYSERR_INVALHANDLE;
45     }
46     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CLOSE, (DWORD)&was->drvInst, 0);
47     if (ret == MMSYSERR_NOERROR) {
48         /* FIXME: shall the was->pDrv->hDrvr be also closed ? */
49         HeapFree(MSACM_hHeap, 0, was);
50     }
51     TRACE("=> (%d)\n", ret);
52     return ret;
53 }
54
55 /***********************************************************************
56  *           acmStreamConvert (MSACM32.38)
57  */
58 MMRESULT WINAPI acmStreamConvert(HACMSTREAM has, PACMSTREAMHEADER pash, 
59                                  DWORD fdwConvert)
60 {
61     PWINE_ACMSTREAM     was;
62     MMRESULT            ret = MMSYSERR_NOERROR;
63     PACMDRVSTREAMHEADER padsh;
64
65     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwConvert);
66     
67     if ((was = ACM_GetStream(has)) == NULL)
68         return MMSYSERR_INVALHANDLE;
69     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
70         return MMSYSERR_INVALPARAM;
71
72     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
73         return ACMERR_UNPREPARED;
74
75     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
76      * size. some fields are private to msacm internals, and are exposed
77      * in ACMSTREAMHEADER in the dwReservedDriver array
78      */
79     padsh = (PACMDRVSTREAMHEADER)pash;
80
81     /* check that pointers have not been modified */
82     if (padsh->pbPreparedSrc != padsh->pbSrc ||
83         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
84         padsh->pbPreparedDst != padsh->pbDst ||
85         padsh->cbPreparedDstLength < padsh->cbDstLength) {
86         return MMSYSERR_INVALPARAM;
87     }   
88
89     padsh->fdwConvert = fdwConvert;
90
91     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_CONVERT, (DWORD)&was->drvInst, (DWORD)padsh);
92     if (ret == MMSYSERR_NOERROR) {
93         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_DONE;
94     }
95     TRACE("=> (%d)\n", ret);
96     return ret;
97 }
98
99 /***********************************************************************
100  *           acmStreamMessage (MSACM32.39)
101  */
102 MMRESULT WINAPI acmStreamMessage(HACMSTREAM has, UINT uMsg, LPARAM lParam1, 
103                                  LPARAM lParam2)
104 {
105     FIXME("(0x%08x, %u, %ld, %ld): stub\n", has, uMsg, lParam1, lParam2);
106     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
107     return MMSYSERR_ERROR;
108 }
109
110 /***********************************************************************
111  *           acmStreamOpen (MSACM32.40)
112  */
113 MMRESULT WINAPI acmStreamOpen(PHACMSTREAM phas, HACMDRIVER had, PWAVEFORMATEX pwfxSrc,
114                               PWAVEFORMATEX pwfxDst, PWAVEFILTER pwfltr, DWORD dwCallback,
115                               DWORD dwInstance, DWORD fdwOpen)
116 {
117     PWINE_ACMSTREAM     was;
118     PWINE_ACMDRIVER     wad;
119     MMRESULT            ret;
120     int                 wfxSrcSize;
121     int                 wfxDstSize;
122     
123     TRACE("(%p, 0x%08x, %p, %p, %p, %ld, %ld, %ld)\n",
124           phas, had, pwfxSrc, pwfxDst, pwfltr, dwCallback, dwInstance, fdwOpen);
125
126     TRACE("src [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
127           pwfxSrc->wFormatTag, pwfxSrc->nChannels, pwfxSrc->nSamplesPerSec, pwfxSrc->nAvgBytesPerSec, 
128           pwfxSrc->nBlockAlign, pwfxSrc->wBitsPerSample, pwfxSrc->cbSize);
129
130     TRACE("dst [wFormatTag=%u, nChannels=%u, nSamplesPerSec=%lu, nAvgBytesPerSec=%lu, nBlockAlign=%u, wBitsPerSample=%u, cbSize=%u]\n", 
131           pwfxDst->wFormatTag, pwfxDst->nChannels, pwfxDst->nSamplesPerSec, pwfxDst->nAvgBytesPerSec, 
132           pwfxDst->nBlockAlign, pwfxDst->wBitsPerSample, pwfxDst->cbSize);
133
134 #define SIZEOF_WFX(wfx) (sizeof(WAVEFORMATEX) + ((wfx->wFormatTag == WAVE_FORMAT_PCM) ? 0 : wfx->cbSize))
135     wfxSrcSize = SIZEOF_WFX(pwfxSrc);
136     wfxDstSize = SIZEOF_WFX(pwfxDst);
137 #undef SIZEOF_WFX
138
139     was = HeapAlloc(MSACM_hHeap, 0, sizeof(*was) + wfxSrcSize + wfxDstSize + ((pwfltr) ? sizeof(WAVEFILTER) : 0));
140     if (was == NULL)
141         return MMSYSERR_NOMEM;
142     
143     was->drvInst.cbStruct = sizeof(was->drvInst);
144     was->drvInst.pwfxSrc = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was));
145     memcpy(was->drvInst.pwfxSrc, pwfxSrc, wfxSrcSize);
146     was->drvInst.pwfxDst = (PWAVEFORMATEX)((LPSTR)was + sizeof(*was) + wfxSrcSize);
147     memcpy(was->drvInst.pwfxDst, pwfxDst, wfxDstSize);
148     if (pwfltr) {
149         was->drvInst.pwfltr = (PWAVEFILTER)((LPSTR)was + sizeof(*was) + wfxSrcSize + wfxDstSize);
150         memcpy(was->drvInst.pwfltr, pwfltr, sizeof(WAVEFILTER));
151     } else {
152         was->drvInst.pwfltr = NULL;
153     }
154     was->drvInst.dwCallback = dwCallback;    
155     was->drvInst.dwInstance = dwInstance;
156     was->drvInst.fdwOpen = fdwOpen;
157     was->drvInst.fdwDriver = 0L;  
158     was->drvInst.dwDriver = 0L;     
159     was->drvInst.has = (HACMSTREAM)was;
160     
161     if (had) {
162         if (!(wad = MSACM_GetDriver(had))) {
163             ret = MMSYSERR_INVALPARAM;
164             goto errCleanUp;
165         }
166         
167         was->obj.pACMDriverID = wad->obj.pACMDriverID;
168         was->pDrv = wad;
169         
170         ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
171         if (ret != MMSYSERR_NOERROR)
172             goto errCleanUp;
173     } else {
174         PWINE_ACMDRIVERID wadi;
175         
176         ret = ACMERR_NOTPOSSIBLE;
177         for (wadi = MSACM_pFirstACMDriverID; wadi; wadi = wadi->pNextACMDriverID) {
178             ret = acmDriverOpen(&had, (HACMDRIVERID)wadi, 0L);
179             if (ret == MMSYSERR_NOERROR) {
180                 if ((wad = MSACM_GetDriver(had)) != 0) {
181                     was->obj.pACMDriverID = wad->obj.pACMDriverID;
182                     was->pDrv = wad;
183                     
184                     ret = SendDriverMessage(wad->hDrvr, ACMDM_STREAM_OPEN, (DWORD)&was->drvInst, 0L);
185                     /* FIXME: when shall the acmDriver be Close():d ? */
186                     if (ret == MMSYSERR_NOERROR)
187                         break;
188                 }
189                 /* no match, close this acm driver and try next one */
190                 acmDriverClose(had, 0L);
191             }
192         }
193         if (ret != MMSYSERR_NOERROR) {
194             ret = ACMERR_NOTPOSSIBLE;
195             goto errCleanUp;
196         }
197     }
198     if (phas)
199         *phas = (HACMSTREAM)was;
200     TRACE("=> (%d)\n", ret);
201     ret = MMSYSERR_NOERROR;
202     if (!(fdwOpen & ACM_STREAMOPENF_QUERY))
203         return ret;
204 errCleanUp:             
205     HeapFree(MSACM_hHeap, 0, was);
206     TRACE("=> (%d)\n", ret);
207     return ret;
208 }
209
210
211 /***********************************************************************
212  *           acmStreamPrepareHeader (MSACM32.41)
213  */
214 MMRESULT WINAPI acmStreamPrepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
215                                        DWORD fdwPrepare)
216 {
217     PWINE_ACMSTREAM     was;
218     MMRESULT            ret = MMSYSERR_NOERROR;
219     PACMDRVSTREAMHEADER padsh;
220
221     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwPrepare);
222     
223     if ((was = ACM_GetStream(has)) == NULL)
224         return MMSYSERR_INVALHANDLE;
225     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
226         return MMSYSERR_INVALPARAM;
227     if (fdwPrepare)
228         ret = MMSYSERR_INVALFLAG;
229
230     if (pash->fdwStatus & ACMSTREAMHEADER_STATUSF_DONE)
231         return MMSYSERR_NOERROR;
232
233     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
234      * size. some fields are private to msacm internals, and are exposed
235      * in ACMSTREAMHEADER in the dwReservedDriver array
236      */
237     padsh = (PACMDRVSTREAMHEADER)pash;
238
239     padsh->fdwConvert = fdwPrepare;
240     padsh->padshNext = NULL;
241     padsh->fdwDriver = padsh->dwDriver = 0L;
242
243     padsh->fdwPrepared = 0;
244     padsh->dwPrepared = 0;
245     padsh->pbPreparedSrc = 0;
246     padsh->cbPreparedSrcLength = 0;
247     padsh->pbPreparedDst = 0;
248     padsh->cbPreparedDstLength = 0;
249
250     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_PREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
251     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
252         ret = MMSYSERR_NOERROR;
253         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE);
254         padsh->fdwStatus |= ACMSTREAMHEADER_STATUSF_PREPARED;
255         padsh->fdwPrepared = padsh->fdwStatus;
256         padsh->dwPrepared = 0;
257         padsh->pbPreparedSrc = padsh->pbSrc;
258         padsh->cbPreparedSrcLength = padsh->cbSrcLength;
259         padsh->pbPreparedDst = padsh->pbDst;
260         padsh->cbPreparedDstLength = padsh->cbDstLength;
261     } else {
262         padsh->fdwPrepared = 0;
263         padsh->dwPrepared = 0;
264         padsh->pbPreparedSrc = 0;
265         padsh->cbPreparedSrcLength = 0;
266         padsh->pbPreparedDst = 0;
267         padsh->cbPreparedDstLength = 0;
268     }
269     TRACE("=> (%d)\n", ret);
270     return ret;
271 }
272
273 /***********************************************************************
274  *           acmStreamReset (MSACM32.42)
275  */
276 MMRESULT WINAPI acmStreamReset(HACMSTREAM has, DWORD fdwReset)
277 {
278     PWINE_ACMSTREAM     was;
279     MMRESULT            ret = MMSYSERR_NOERROR;
280
281     TRACE("(0x%08x, %ld)\n", has, fdwReset);
282
283     if (fdwReset) {
284         ret = MMSYSERR_INVALFLAG;
285     } else if ((was = ACM_GetStream(has)) == NULL) {
286         return MMSYSERR_INVALHANDLE;
287     } else if (was->drvInst.fdwOpen & ACM_STREAMOPENF_ASYNC) {
288         ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_RESET, (DWORD)&was->drvInst, 0);
289     }
290     TRACE("=> (%d)\n", ret);
291     return ret;
292 }
293
294 /***********************************************************************
295  *           acmStreamSize (MSACM32.43)
296  */
297 MMRESULT WINAPI acmStreamSize(HACMSTREAM has, DWORD cbInput, 
298                               LPDWORD pdwOutputBytes, DWORD fdwSize)
299 {
300     PWINE_ACMSTREAM     was;
301     ACMDRVSTREAMSIZE    adss;
302     MMRESULT            ret;
303     
304     TRACE("(0x%08x, %ld, %p, %ld)\n", has, cbInput, pdwOutputBytes, fdwSize);
305     
306     if ((was = ACM_GetStream(has)) == NULL) {
307         return MMSYSERR_INVALHANDLE;
308     }
309     if ((fdwSize & ~ACM_STREAMSIZEF_QUERYMASK) != 0) {
310         return MMSYSERR_INVALFLAG;
311     }
312
313     *pdwOutputBytes = 0L;
314     
315     switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
316     case ACM_STREAMSIZEF_DESTINATION:
317         adss.cbDstLength = cbInput;
318         adss.cbSrcLength = 0;
319         break;
320     case ACM_STREAMSIZEF_SOURCE:
321         adss.cbSrcLength = cbInput;
322         adss.cbDstLength = 0;
323         break;
324     default:    
325         return MMSYSERR_INVALFLAG;
326     }
327     
328     adss.cbStruct = sizeof(adss);
329     adss.fdwSize = fdwSize;
330     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_SIZE, 
331                             (DWORD)&was->drvInst, (DWORD)&adss);
332     if (ret == MMSYSERR_NOERROR) {
333         switch (fdwSize & ACM_STREAMSIZEF_QUERYMASK) {
334         case ACM_STREAMSIZEF_DESTINATION:
335             *pdwOutputBytes = adss.cbSrcLength;
336             break;
337         case ACM_STREAMSIZEF_SOURCE:
338             *pdwOutputBytes = adss.cbDstLength;
339             break;
340         }
341     }
342     TRACE("=> (%d) [%lu]\n", ret, *pdwOutputBytes);
343     return ret;
344 }
345
346 /***********************************************************************
347  *           acmStreamUnprepareHeader (MSACM32.44)
348  */
349 MMRESULT WINAPI acmStreamUnprepareHeader(HACMSTREAM has, PACMSTREAMHEADER pash, 
350                                          DWORD fdwUnprepare)
351 {
352     PWINE_ACMSTREAM     was;
353     MMRESULT            ret = MMSYSERR_NOERROR;
354     PACMDRVSTREAMHEADER padsh;
355
356     TRACE("(0x%08x, %p, %ld)\n", has, pash, fdwUnprepare);
357     
358     if ((was = ACM_GetStream(has)) == NULL)
359         return MMSYSERR_INVALHANDLE;
360     if (!pash || pash->cbStruct < sizeof(ACMSTREAMHEADER))
361         return MMSYSERR_INVALPARAM;
362
363     if (!(pash->fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED))
364         return ACMERR_UNPREPARED;
365
366     /* Note: the ACMSTREAMHEADER and ACMDRVSTREAMHEADER structs are of same
367      * size. some fields are private to msacm internals, and are exposed
368      * in ACMSTREAMHEADER in the dwReservedDriver array
369      */
370     padsh = (PACMDRVSTREAMHEADER)pash;
371
372     /* check that pointers have not been modified */
373     if (padsh->pbPreparedSrc != padsh->pbSrc ||
374         padsh->cbPreparedSrcLength < padsh->cbSrcLength ||
375         padsh->pbPreparedDst != padsh->pbDst ||
376         padsh->cbPreparedDstLength < padsh->cbDstLength) {
377         return MMSYSERR_INVALPARAM;
378     }   
379
380     padsh->fdwConvert = fdwUnprepare;
381
382     ret = SendDriverMessage(was->pDrv->hDrvr, ACMDM_STREAM_UNPREPARE, (DWORD)&was->drvInst, (DWORD)padsh);
383     if (ret == MMSYSERR_NOERROR || ret == MMSYSERR_NOTSUPPORTED) {
384         ret = MMSYSERR_NOERROR;
385         padsh->fdwStatus &= ~(ACMSTREAMHEADER_STATUSF_DONE|ACMSTREAMHEADER_STATUSF_INQUEUE|ACMSTREAMHEADER_STATUSF_PREPARED);
386     }
387     TRACE("=> (%d)\n", ret);
388     return ret;
389 }