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