1 /*
2  * Unit tests for msacm functions
3  *
4  * Copyright (c) 2004 Robert Reif
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <math.h>
25 
26 #include "wine/test.h"
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winnls.h"
30 #include "mmsystem.h"
31 #define NOBITMAP
32 #include "mmreg.h"
33 #include "msacm.h"
34 #include "wine/msacmdrv.h"
35 
FormatTagEnumProc(HACMDRIVERID hadid,PACMFORMATTAGDETAILSA paftd,DWORD_PTR dwInstance,DWORD fdwSupport)36 static BOOL CALLBACK FormatTagEnumProc(HACMDRIVERID hadid,
37                                        PACMFORMATTAGDETAILSA paftd,
38                                        DWORD_PTR dwInstance,
39                                        DWORD fdwSupport)
40 {
41     MMRESULT rc;
42     HACMDRIVER had;
43 
44     if (winetest_interactive)
45         trace("   Format 0x%04x: %s\n", paftd->dwFormatTag, paftd->szFormatTag);
46 
47     rc = acmDriverOpen(&had, hadid, 0);
48     ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_NODRIVER,
49        "acmDriverOpen(): rc = %08x, should be %08x\n",
50        rc, MMSYSERR_NOERROR);
51 
52     if (rc == MMSYSERR_NOERROR)
53     {
54         ACMFORMATDETAILSA fd = {0};
55         WAVEFORMATEX *pwfx, dst;
56         ACMFORMATTAGDETAILSA aftd_pcm = {0};
57         DWORD dwSize, dwSizeMax;
58         DWORD i;
59 
60         fd.cbStruct = sizeof(fd);
61         if (paftd->cbFormatSize < sizeof(WAVEFORMATEX))
62             pwfx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WAVEFORMATEX));
63         else
64             pwfx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, paftd->cbFormatSize);
65         fd.pwfx = pwfx;
66         fd.cbwfx = paftd->cbFormatSize;
67         fd.dwFormatTag = paftd->dwFormatTag;
68 
69         /* try bad pwfx */
70         fd.pwfx = NULL;
71         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_FORMAT);
72         ok(rc == MMSYSERR_INVALPARAM,
73            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
74            rc, MMSYSERR_INVALPARAM);
75         fd.pwfx = pwfx;
76 
77         /* try bad wFormatTag */
78         fd.pwfx->wFormatTag = WAVE_FORMAT_UNKNOWN;
79         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_FORMAT);
80         ok(rc == MMSYSERR_INVALPARAM,
81            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
82            rc, MMSYSERR_INVALPARAM);
83         fd.pwfx->wFormatTag = paftd->dwFormatTag;
84 
85         /* try bad fdwSupport */
86         fd.fdwSupport = 0xdeadbeef;
87         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_FORMAT);
88         ok(rc == MMSYSERR_INVALPARAM,
89            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
90            rc, MMSYSERR_INVALPARAM);
91         fd.fdwSupport = 0;
92 
93         /* try bad pwfx structure size */
94         fd.cbwfx = sizeof(PCMWAVEFORMAT)-1;
95         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_FORMAT);
96         ok(rc == MMSYSERR_INVALPARAM,
97            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
98            rc, MMSYSERR_INVALPARAM);
99         fd.cbwfx = paftd->cbFormatSize;
100 
101         /* test bad parameters (all zero) */
102         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_FORMAT);
103         ok(rc == ACMERR_NOTPOSSIBLE,
104            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
105            rc, ACMERR_NOTPOSSIBLE);
106 
107         /* test acmFormatSuggest */
108 
109         /* if we don't specify a format, we must give at least the driver's maximum size for any format */
110         acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
111         rc = acmFormatSuggest(had, pwfx, &dst, dwSize-1, 0);
112         ok(rc == MMSYSERR_INVALPARAM,
113            "acmFormatSuggest(): rc = %08x, should be %08x\n",
114            rc, MMSYSERR_INVALPARAM);
115 
116         rc = acmFormatSuggest(had, pwfx, &dst, dwSize, 0);
117         ok(rc == ACMERR_NOTPOSSIBLE,
118            "acmFormatSuggest(): rc = %08x, should be %08x\n",
119            rc, ACMERR_NOTPOSSIBLE);
120 
121         /* if we do specify a format, we must give at least the driver's maximum size for that format */
122         aftd_pcm.cbStruct = sizeof(aftd_pcm);
123         aftd_pcm.dwFormatTag = WAVE_FORMAT_PCM;
124         rc = acmFormatTagDetailsA(had, &aftd_pcm, ACM_FORMATTAGDETAILSF_LARGESTSIZE);
125         ok(rc == MMSYSERR_NOERROR, "returned %08x\n", rc);
126 
127         dst.wFormatTag = WAVE_FORMAT_PCM;
128         rc = acmFormatSuggest(had, pwfx, &dst, aftd_pcm.cbFormatSize-1, ACM_FORMATSUGGESTF_WFORMATTAG);
129         ok(rc == MMSYSERR_INVALPARAM,
130            "acmFormatSuggest(): rc = %08x, should be %08x\n",
131            rc, MMSYSERR_INVALPARAM);
132 
133         rc = acmFormatSuggest(had, pwfx, &dst, aftd_pcm.cbFormatSize, ACM_FORMATSUGGESTF_WFORMATTAG);
134         ok(rc == ACMERR_NOTPOSSIBLE,
135            "acmFormatSuggest(): rc = %08x, should be %08x\n",
136            rc, ACMERR_NOTPOSSIBLE);
137 
138         /* test nonexistent format */
139         dst.wFormatTag = 0xbeef;
140         rc = acmFormatSuggest(had, pwfx, &dst, 0, ACM_FORMATSUGGESTF_WFORMATTAG);
141         ok(rc == ACMERR_NOTPOSSIBLE || rc == MMSYSERR_INVALPARAM,
142            "acmFormatSuggest(): rc = %08x, should be %08x\n",
143            rc, ACMERR_NOTPOSSIBLE);
144 
145         /* if the driver is NULL, we must give at least the maximum size for any driver */
146         acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &dwSizeMax);
147         rc = acmFormatSuggest(NULL, pwfx, &dst, dwSizeMax-1, 0);
148         ok(rc == MMSYSERR_INVALPARAM,
149            "acmFormatSuggest(): rc = %08x, should be %08x\n",
150            rc, MMSYSERR_INVALPARAM);
151 
152         if (paftd->dwFormatTag != WAVE_FORMAT_PCM)
153         {
154             rc = acmFormatSuggest(NULL, pwfx, &dst, dwSizeMax, 0);
155             ok(rc == ACMERR_NOTPOSSIBLE,
156                "acmFormatSuggest(): rc = %08x, should be %08x\n",
157                rc, ACMERR_NOTPOSSIBLE);
158         }
159 
160         /* if we specify a dst format, we must give the maximum size for that format */
161         dst.wFormatTag = WAVE_FORMAT_PCM;
162         rc = acmFormatSuggest(NULL, pwfx, &dst, aftd_pcm.cbFormatSize-1, ACM_FORMATSUGGESTF_WFORMATTAG);
163         ok(rc == MMSYSERR_INVALPARAM || broken (rc == ACMERR_NOTPOSSIBLE), /* WinXP */
164            "acmFormatSuggest(): rc = %08x, should be %08x\n",
165            rc, MMSYSERR_INVALPARAM);
166 
167         rc = acmFormatSuggest(NULL, pwfx, &dst, aftd_pcm.cbFormatSize, ACM_FORMATSUGGESTF_WFORMATTAG);
168         ok(rc == ACMERR_NOTPOSSIBLE,
169            "acmFormatSuggest(): rc = %08x, should be %08x\n",
170            rc, ACMERR_NOTPOSSIBLE);
171 
172         dst.wFormatTag = paftd->dwFormatTag;
173         rc = acmFormatSuggest(NULL, pwfx, &dst, paftd->cbFormatSize-1, ACM_FORMATSUGGESTF_WFORMATTAG);
174         ok(rc == MMSYSERR_INVALPARAM || broken (rc == ACMERR_NOTPOSSIBLE), /* WinXP */
175            "acmFormatSuggest(): rc = %08x, should be %08x\n",
176            rc, MMSYSERR_INVALPARAM);
177 
178         rc = acmFormatSuggest(NULL, pwfx, &dst, paftd->cbFormatSize, ACM_FORMATSUGGESTF_WFORMATTAG);
179         ok(rc == ACMERR_NOTPOSSIBLE,
180            "acmFormatSuggest(): rc = %08x, should be %08x\n",
181            rc, ACMERR_NOTPOSSIBLE);
182 
183         /* test nonexistent format */
184         dst.wFormatTag = 0xbeef;
185         rc = acmFormatSuggest(NULL, pwfx, &dst, 0, ACM_FORMATSUGGESTF_WFORMATTAG);
186         ok(rc == ACMERR_NOTPOSSIBLE || rc == MMSYSERR_INVALPARAM,
187            "acmFormatSuggest(): rc = %08x, should be %08x\n",
188            rc, ACMERR_NOTPOSSIBLE);
189 
190         /* test index */
191         for (i = 0; i < paftd->cStandardFormats; i++)
192         {
193             fd.dwFormatIndex = i;
194 
195             fd.fdwSupport = 0;
196             fd.cbwfx = paftd->cbFormatSize;
197             fd.pwfx->cbSize = 0xbeef;
198             rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
199             ok(rc == MMSYSERR_NOERROR,
200                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
201                rc, MMSYSERR_NOERROR);
202 
203             /* Windows will write cbSize (and other data) even if the
204              * given cbwfx is not large enough */
205             fd.fdwSupport = 0;
206             fd.cbwfx = sizeof(PCMWAVEFORMAT);
207             fd.pwfx->cbSize = 0xbeef;
208             rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
209             todo_wine_if(rc != MMSYSERR_NOERROR) /* remove when fixed */
210             ok(rc == MMSYSERR_NOERROR,
211                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
212                rc, MMSYSERR_NOERROR);
213             if (paftd->dwFormatTag != WAVE_FORMAT_PCM)
214                 todo_wine_if(fd.pwfx->cbSize != paftd->cbFormatSize - sizeof(WAVEFORMATEX)) /* remove when fixed */
215                 ok(fd.pwfx->cbSize == paftd->cbFormatSize - sizeof(WAVEFORMATEX),
216                    "got %d\n", fd.pwfx->cbSize);
217         }
218 
219         /* one more */
220         fd.dwFormatIndex = paftd->cStandardFormats;
221         fd.fdwSupport = 0;
222         rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
223         ok(rc == MMSYSERR_INVALPARAM,
224            "acmFormatDetailsA(): rc = %08x, should be %08x\n",
225            rc, MMSYSERR_INVALPARAM);
226 
227         HeapFree(GetProcessHeap(), 0, pwfx);
228     }
229     return TRUE;
230 }
231 
FormatEnumProc(HACMDRIVERID hadid,LPACMFORMATDETAILSA pafd,DWORD_PTR dwInstance,DWORD fd)232 static BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid,
233                                     LPACMFORMATDETAILSA pafd,
234                                     DWORD_PTR dwInstance,
235                                     DWORD fd)
236 {
237     MMRESULT rc;
238     HACMDRIVER had;
239     WAVEFORMATEX *dst, *dstMax;
240     DWORD dwSize, dwSizeMax;
241     DWORD fdwSupport;
242 
243     acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_SUPPORT, &fdwSupport);
244 
245     if (winetest_interactive)
246         trace("   0x%04x, %s\n", pafd->dwFormatTag, pafd->szFormat);
247 
248     acmDriverOpen(&had, hadid, 0);
249     dwSize = pafd->cbwfx;
250     dst = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
251 
252     /* test acmFormatSuggest with valid src format */
253     if (pafd->dwFormatTag == WAVE_FORMAT_PCM)
254     {
255         rc = acmFormatSuggest(had, pafd->pwfx, dst, dwSize, 0);
256         /* this fails on some decode-only drivers */
257         ok(rc == MMSYSERR_NOERROR || rc == ACMERR_NOTPOSSIBLE,
258            "acmFormatSuggest(): rc = %08x, should be %08x\n",
259            rc, MMSYSERR_NOERROR);
260         if (rc == MMSYSERR_NOERROR)
261         {
262             if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) /* supports different conversions */
263                 ok(dst->wFormatTag != WAVE_FORMAT_PCM, "expected different format\n");
264             else
265                 ok(dst->wFormatTag == WAVE_FORMAT_PCM,
266                    "expected %d, got %d\n", WAVE_FORMAT_PCM, dst->wFormatTag);
267         }
268     }
269     else
270     {
271         rc = acmFormatSuggest(had, pafd->pwfx, dst, dwSize, 0);
272         ok(rc == MMSYSERR_NOERROR,
273            "acmFormatSuggest(): rc = %08x, should be %08x\n",
274            rc, MMSYSERR_NOERROR);
275         ok(dst->wFormatTag == WAVE_FORMAT_PCM,
276            "expected %d, got %d\n", WAVE_FORMAT_PCM, dst->wFormatTag);
277         ok(dst->nChannels == pafd->pwfx->nChannels,
278            "expected %d, got %d\n", pafd->pwfx->nChannels, dst->nChannels);
279         if (pafd->dwFormatTag != 0x42) /* codec 0x0042 returns a different sample rate */
280             ok(dst->nSamplesPerSec == pafd->pwfx->nSamplesPerSec,
281                "expected %d, got %d\n", pafd->pwfx->nSamplesPerSec, dst->nSamplesPerSec);
282         ok(dst->wBitsPerSample == 16,
283            "expected %d, got %d\n", 16, dst->wBitsPerSample);
284         ok(dst->nBlockAlign == 2*pafd->pwfx->nChannels,
285            "expected %d, got %d\n", 2*pafd->pwfx->nChannels, dst->nBlockAlign);
286 
287         /* test with NULL driver */
288         acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &dwSizeMax);
289         dstMax = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSizeMax);
290         rc = acmFormatSuggest(NULL, pafd->pwfx, dstMax, dwSizeMax, 0);
291         ok(rc == MMSYSERR_NOERROR,
292            "acmFormatSuggest(): rc = %08x, should be %08x\n",
293            rc, MMSYSERR_NOERROR);
294 
295         HeapFree(GetProcessHeap(), 0, dstMax);
296     }
297 
298     ZeroMemory(dst, dwSize);
299     dst->wFormatTag = pafd->pwfx->wFormatTag;
300     rc = acmFormatSuggest(had, pafd->pwfx, dst, dwSize, ACM_FORMATSUGGESTF_WFORMATTAG);
301     if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER) /* supports same conversions */
302         ok(rc == MMSYSERR_NOERROR,
303            "acmFormatSuggest(): rc = %08x, should be %08x\n",
304            rc, MMSYSERR_NOERROR);
305     else
306         todo_wine_if(rc != ACMERR_NOTPOSSIBLE)
307         ok(rc == ACMERR_NOTPOSSIBLE,
308            "acmFormatSuggest(): rc = %08x, should be %08x\n",
309            rc, ACMERR_NOTPOSSIBLE);
310 
311     HeapFree(GetProcessHeap(), 0, dst);
312     acmDriverClose(had, 0);
313 
314     return TRUE;
315 }
316 
DriverEnumProc(HACMDRIVERID hadid,DWORD_PTR dwInstance,DWORD fdwSupport)317 static BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid,
318                                     DWORD_PTR dwInstance,
319                                     DWORD fdwSupport)
320 {
321     MMRESULT rc;
322     ACMDRIVERDETAILSA dd;
323     HACMDRIVER had;
324 
325     DWORD dwDriverPriority;
326     DWORD dwDriverSupport;
327 
328     if (winetest_interactive) {
329         trace("id: %p\n", hadid);
330         trace("  Supports:\n");
331         if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_ASYNC)
332             trace("    async conversions\n");
333         if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC)
334             trace("    different format conversions\n");
335         if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER)
336             trace("    same format conversions\n");
337         if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_FILTER)
338             trace("    filtering\n");
339     }
340 
341     /* try an invalid pointer */
342     rc = acmDriverDetailsA(hadid, 0, 0);
343     ok(rc == MMSYSERR_INVALPARAM,
344        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
345        rc, MMSYSERR_INVALPARAM);
346 
347     /* try an invalid structure size */
348     ZeroMemory(&dd, sizeof(dd));
349     rc = acmDriverDetailsA(hadid, &dd, 0);
350     ok(rc == MMSYSERR_INVALPARAM,
351        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
352        rc, MMSYSERR_INVALPARAM);
353 
354     /* MSDN says this should fail but it doesn't in practice */
355     dd.cbStruct = 4;
356     rc = acmDriverDetailsA(hadid, &dd, 0);
357     ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_NOTSUPPORTED,
358        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
359        rc, MMSYSERR_NOERROR);
360 
361     /* try an invalid handle */
362     dd.cbStruct = sizeof(dd);
363     rc = acmDriverDetailsA((HACMDRIVERID)1, &dd, 0);
364     ok(rc == MMSYSERR_INVALHANDLE,
365        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
366        rc, MMSYSERR_INVALHANDLE);
367 
368     /* try an invalid handle and pointer */
369     rc = acmDriverDetailsA((HACMDRIVERID)1, 0, 0);
370     ok(rc == MMSYSERR_INVALPARAM,
371        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
372        rc, MMSYSERR_INVALPARAM);
373 
374     /* try invalid details */
375     rc = acmDriverDetailsA(hadid, &dd, -1);
376     ok(rc == MMSYSERR_INVALFLAG,
377        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
378        rc, MMSYSERR_INVALFLAG);
379 
380     /* try valid parameters */
381     rc = acmDriverDetailsA(hadid, &dd, 0);
382     ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_NOTSUPPORTED,
383        "acmDriverDetailsA(): rc = %08x, should be %08x\n",
384        rc, MMSYSERR_NOERROR);
385 
386     /* cbStruct should contain size of returned data (at most sizeof(dd))
387        TODO: should it be *exactly* sizeof(dd), as tested here?
388      */
389     if (rc == MMSYSERR_NOERROR) {
390         static const struct {
391             const char *shortname;
392             WORD mid;
393             WORD pid;
394             WORD pid_alt;
395         } *iter, expected_ids[] = {
396             { "Microsoft IMA ADPCM", MM_MICROSOFT, MM_MSFT_ACM_IMAADPCM },
397             { "MS-ADPCM", MM_MICROSOFT, MM_MSFT_ACM_MSADPCM },
398             { "Microsoft CCITT G.711", MM_MICROSOFT, MM_MSFT_ACM_G711},
399             { "MPEG Layer-3 Codec", MM_FRAUNHOFER_IIS, MM_FHGIIS_MPEGLAYER3_DECODE, MM_FHGIIS_MPEGLAYER3_PROFESSIONAL },
400             { "MS-PCM", MM_MICROSOFT, MM_MSFT_ACM_PCM },
401             { 0 }
402         };
403 
404         ok(dd.cbStruct == sizeof(dd),
405             "acmDriverDetailsA(): cbStruct = %08x\n", dd.cbStruct);
406 
407         for (iter = expected_ids; iter->shortname; ++iter) {
408             if (!strcmp(iter->shortname, dd.szShortName)) {
409                 /* try alternative product id on mismatch */
410                 if (iter->pid_alt && iter->pid != dd.wPid)
411                     ok(iter->mid == dd.wMid && iter->pid_alt == dd.wPid,
412                         "Got wrong manufacturer (0x%x vs 0x%x) or product (0x%x vs 0x%x)\n",
413                         dd.wMid, iter->mid,
414                         dd.wPid, iter->pid_alt);
415                 else
416                     ok(iter->mid == dd.wMid && iter->pid == dd.wPid,
417                         "Got wrong manufacturer (0x%x vs 0x%x) or product (0x%x vs 0x%x)\n",
418                         dd.wMid, iter->mid,
419                         dd.wPid, iter->pid);
420             }
421         }
422     }
423 
424     if (rc == MMSYSERR_NOERROR && winetest_interactive) {
425         trace("  Short name: %s\n", dd.szShortName);
426         trace("  Long name: %s\n", dd.szLongName);
427         trace("  Copyright: %s\n", dd.szCopyright);
428         trace("  Licensing: %s\n", dd.szLicensing);
429         trace("  Features: %s\n", dd.szFeatures);
430         trace("  Supports %u formats\n", dd.cFormatTags);
431         trace("  Supports %u filter formats\n", dd.cFilterTags);
432         trace("  Mid: 0x%x\n", dd.wMid);
433         trace("  Pid: 0x%x\n", dd.wPid);
434     }
435 
436     /* try bad pointer */
437     rc = acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_PRIORITY, 0);
438     ok(rc == MMSYSERR_INVALPARAM,
439         "acmMetrics(): rc = %08x, should be %08x\n",
440         rc, MMSYSERR_INVALPARAM);
441 
442     /* try bad handle */
443     rc = acmMetrics((HACMOBJ)1, ACM_METRIC_DRIVER_PRIORITY, &dwDriverPriority);
444     ok(rc == MMSYSERR_INVALHANDLE,
445         "acmMetrics(): rc = %08x, should be %08x\n",
446         rc, MMSYSERR_INVALHANDLE);
447 
448     /* try bad pointer and handle */
449     rc = acmMetrics((HACMOBJ)1, ACM_METRIC_DRIVER_PRIORITY, 0);
450     ok(rc == MMSYSERR_INVALHANDLE,
451         "acmMetrics(): rc = %08x, should be %08x\n",
452         rc, MMSYSERR_INVALHANDLE);
453 
454     /* try valid parameters */
455     rc = acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_PRIORITY, &dwDriverSupport);
456     ok(rc == MMSYSERR_NOERROR,
457         "acmMetrics(): rc = %08x, should be %08x\n",
458         rc, MMSYSERR_NOERROR);
459 
460     /* try bad pointer */
461     rc = acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_SUPPORT, 0);
462     ok(rc == MMSYSERR_INVALPARAM,
463         "acmMetrics(): rc = %08x, should be %08x\n",
464         rc, MMSYSERR_INVALPARAM);
465 
466     /* try bad handle */
467     rc = acmMetrics((HACMOBJ)1, ACM_METRIC_DRIVER_SUPPORT, &dwDriverSupport);
468     ok(rc == MMSYSERR_INVALHANDLE,
469         "acmMetrics(): rc = %08x, should be %08x\n",
470         rc, MMSYSERR_INVALHANDLE);
471 
472     /* try bad pointer and handle */
473     rc = acmMetrics((HACMOBJ)1, ACM_METRIC_DRIVER_SUPPORT, 0);
474     ok(rc == MMSYSERR_INVALHANDLE,
475         "acmMetrics(): rc = %08x, should be %08x\n",
476         rc, MMSYSERR_INVALHANDLE);
477 
478     /* try valid parameters */
479     rc = acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_SUPPORT, &dwDriverSupport);
480     ok(rc == MMSYSERR_NOERROR,
481         "acmMetrics(): rc = %08x, should be %08x\n",
482         rc, MMSYSERR_NOERROR);
483 
484     /* try invalid pointer */
485     rc = acmDriverOpen(0, hadid, 0);
486     ok(rc == MMSYSERR_INVALPARAM,
487        "acmDriverOpen(): rc = %08x, should be %08x\n",
488        rc, MMSYSERR_INVALPARAM);
489 
490     /* try invalid handle */
491     rc = acmDriverOpen(&had, (HACMDRIVERID)1, 0);
492     ok(rc == MMSYSERR_INVALHANDLE,
493        "acmDriverOpen(): rc = %08x, should be %08x\n",
494        rc, MMSYSERR_INVALHANDLE);
495 
496     /* try invalid open */
497     rc = acmDriverOpen(&had, hadid, -1);
498     ok(rc == MMSYSERR_INVALFLAG,
499        "acmDriverOpen(): rc = %08x, should be %08x\n",
500        rc, MMSYSERR_INVALFLAG);
501 
502     /* try valid parameters */
503     rc = acmDriverOpen(&had, hadid, 0);
504     ok(rc == MMSYSERR_NOERROR || rc == MMSYSERR_NODRIVER,
505        "acmDriverOpen(): rc = %08x, should be %08x\n",
506        rc, MMSYSERR_NOERROR);
507 
508     if (rc == MMSYSERR_NOERROR) {
509         DWORD dwSize;
510         HACMDRIVERID hid;
511 
512         /* try bad pointer */
513         rc = acmDriverID((HACMOBJ)had, 0, 0);
514         ok(rc == MMSYSERR_INVALPARAM,
515            "acmDriverID(): rc = %08x, should be %08x\n",
516            rc, MMSYSERR_INVALPARAM);
517 
518         /* try bad handle */
519         rc = acmDriverID((HACMOBJ)1, &hid, 0);
520         ok(rc == MMSYSERR_INVALHANDLE,
521            "acmDriverID(): rc = %08x, should be %08x\n",
522            rc, MMSYSERR_INVALHANDLE);
523 
524         /* try bad handle and pointer */
525         rc = acmDriverID((HACMOBJ)1, 0, 0);
526         ok(rc == MMSYSERR_INVALHANDLE,
527            "acmDriverID(): rc = %08x, should be %08x\n",
528            rc, MMSYSERR_INVALHANDLE);
529 
530         /* try bad flag */
531         rc = acmDriverID((HACMOBJ)had, &hid, 1);
532         ok(rc == MMSYSERR_INVALFLAG,
533            "acmDriverID(): rc = %08x, should be %08x\n",
534            rc, MMSYSERR_INVALFLAG);
535 
536         /* try valid parameters */
537         rc = acmDriverID((HACMOBJ)had, &hid, 0);
538         ok(rc == MMSYSERR_NOERROR,
539            "acmDriverID(): rc = %08x, should be %08x\n",
540            rc, MMSYSERR_NOERROR);
541         ok(hid == hadid,
542            "acmDriverID() returned ID %p doesn't equal %p\n",
543            hid, hadid);
544 
545         /* try bad pointer */
546         rc = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, 0);
547         ok(rc == MMSYSERR_INVALPARAM,
548            "acmMetrics(): rc = %08x, should be %08x\n",
549            rc, MMSYSERR_INVALPARAM);
550 
551         /* try bad handle */
552         rc = acmMetrics((HACMOBJ)1, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
553         ok(rc == MMSYSERR_INVALHANDLE,
554            "acmMetrics(): rc = %08x, should be %08x\n",
555            rc, MMSYSERR_INVALHANDLE);
556 
557         /* try bad pointer and handle */
558         rc = acmMetrics((HACMOBJ)1, ACM_METRIC_MAX_SIZE_FORMAT, 0);
559         ok(rc == MMSYSERR_INVALHANDLE,
560            "acmMetrics(): rc = %08x, should be %08x\n",
561            rc, MMSYSERR_INVALHANDLE);
562 
563         /* try valid parameters */
564         rc = acmMetrics((HACMOBJ)had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);
565         ok(rc == MMSYSERR_NOERROR,
566            "acmMetrics(): rc = %08x, should be %08x\n",
567            rc, MMSYSERR_NOERROR);
568         if (rc == MMSYSERR_NOERROR) {
569             ACMFORMATDETAILSA fd;
570             WAVEFORMATEX * pwfx;
571             ACMFORMATTAGDETAILSA aftd;
572 
573             /* try bad pointer */
574             rc = acmFormatEnumA(had, 0, FormatEnumProc, 0, 0);
575             ok(rc == MMSYSERR_INVALPARAM,
576                "acmFormatEnumA(): rc = %08x, should be %08x\n",
577                 rc, MMSYSERR_INVALPARAM);
578 
579             /* try bad structure size */
580             ZeroMemory(&fd, sizeof(fd));
581             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
582             ok(rc == MMSYSERR_INVALPARAM,
583                "acmFormatEnumA(): rc = %08x, should be %08x\n",
584                rc, MMSYSERR_INVALPARAM);
585 
586             fd.cbStruct = sizeof(fd) - 1;
587             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
588             ok(rc == MMSYSERR_INVALPARAM,
589                "acmFormatEnumA(): rc = %08x, should be %08x\n",
590                rc, MMSYSERR_INVALPARAM);
591 
592             pwfx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
593 
594             if (dwSize >= sizeof(WAVEFORMATEX))
595                 pwfx->cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);
596             pwfx->wFormatTag = WAVE_FORMAT_UNKNOWN;
597 
598             fd.cbStruct = sizeof(fd);
599             fd.pwfx = pwfx;
600             fd.cbwfx = dwSize;
601             fd.dwFormatTag = WAVE_FORMAT_UNKNOWN;
602 
603             /* try bad callback */
604             rc = acmFormatEnumA(had, &fd, NULL, 0, 0);
605             ok(rc == MMSYSERR_INVALPARAM,
606                "acmFormatEnumA(): rc = %08x, should be %08x\n",
607                rc, MMSYSERR_INVALPARAM);
608 
609             /* try bad pwfx */
610             fd.pwfx = NULL;
611             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
612             ok(rc == MMSYSERR_INVALPARAM,
613                "acmFormatEnumA(): rc = %08x, should be %08x\n",
614                rc, MMSYSERR_INVALPARAM);
615             fd.pwfx = pwfx;
616 
617             /* fdwSupport must be zero */
618             fd.fdwSupport = 0xdeadbeef;
619             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
620             ok(rc == MMSYSERR_INVALPARAM,
621                "acmFormatEnumA(): rc = %08x, should be %08x\n",
622                rc, MMSYSERR_INVALPARAM);
623             fd.fdwSupport = 0;
624 
625             /* try bad pwfx structure size */
626             fd.cbwfx = dwSize-1;
627             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
628             ok(rc == MMSYSERR_INVALPARAM,
629                "acmFormatEnumA(): rc = %08x, should be %08x\n",
630                rc, MMSYSERR_INVALPARAM);
631             fd.cbwfx = dwSize;
632 
633             /* try valid parameters */
634             rc = acmFormatEnumA(had, &fd, FormatEnumProc, 0, 0);
635             ok(rc == MMSYSERR_NOERROR,
636                "acmFormatEnumA(): rc = %08x, should be %08x\n",
637                rc, MMSYSERR_NOERROR);
638 
639             /* try bad pointer */
640             rc = acmFormatTagEnumA(had, 0, FormatTagEnumProc, 0, 0);
641             ok(rc == MMSYSERR_INVALPARAM,
642                "acmFormatTagEnumA(): rc = %08x, should be %08x\n",
643                 rc, MMSYSERR_INVALPARAM);
644 
645             /* try bad structure size */
646             ZeroMemory(&aftd, sizeof(aftd));
647             rc = acmFormatTagEnumA(had, &aftd, FormatTagEnumProc, 0, 0);
648             ok(rc == MMSYSERR_INVALPARAM,
649                "acmFormatTagEnumA(): rc = %08x, should be %08x\n",
650                rc, MMSYSERR_INVALPARAM);
651 
652             aftd.cbStruct = sizeof(aftd) - 1;
653             rc = acmFormatTagEnumA(had, &aftd, FormatTagEnumProc, 0, 0);
654             ok(rc == MMSYSERR_INVALPARAM,
655                "acmFormatTagEnumA(): rc = %08x, should be %08x\n",
656                rc, MMSYSERR_INVALPARAM);
657 
658             aftd.cbStruct = sizeof(aftd);
659             aftd.dwFormatTag = WAVE_FORMAT_UNKNOWN;
660 
661             /* try bad flag */
662             rc = acmFormatTagEnumA(had, &aftd, FormatTagEnumProc, 0, 1);
663             ok(rc == MMSYSERR_INVALFLAG,
664                "acmFormatTagEnumA(): rc = %08x, should be %08x\n",
665                rc, MMSYSERR_INVALFLAG);
666 
667             /* try valid parameters */
668             rc = acmFormatTagEnumA(had, &aftd, FormatTagEnumProc, 0, 0);
669             ok(rc == MMSYSERR_NOERROR,
670                "acmFormatTagEnumA(): rc = %08x, should be %08x\n",
671                rc, MMSYSERR_NOERROR);
672 
673             /* try bad pointer */
674             rc = acmFormatDetailsA(had, NULL, ACM_FORMATDETAILSF_INDEX);
675             ok(rc == MMSYSERR_INVALPARAM,
676                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
677                rc, MMSYSERR_INVALPARAM);
678 
679             /* try bad structure size */
680             ZeroMemory(&fd, sizeof(fd));
681             rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
682             ok(rc == MMSYSERR_INVALPARAM,
683                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
684                rc, MMSYSERR_INVALPARAM);
685 
686             fd.cbStruct = sizeof(fd) - 1;
687             rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
688             ok(rc == MMSYSERR_INVALPARAM,
689                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
690                rc, MMSYSERR_INVALPARAM);
691 
692             fd.cbStruct = sizeof(fd);
693             fd.pwfx = pwfx;
694             ZeroMemory(fd.pwfx, dwSize);
695             fd.cbwfx = dwSize;
696             fd.dwFormatTag = WAVE_FORMAT_UNKNOWN;
697 
698             /* try WAVE_FORMAT_UNKNOWN */
699             rc = acmFormatDetailsA(had, &fd, ACM_FORMATDETAILSF_INDEX);
700             ok(rc == MMSYSERR_INVALPARAM,
701                "acmFormatDetailsA(): rc = %08x, should be %08x\n",
702                rc, MMSYSERR_INVALPARAM);
703 
704             HeapFree(GetProcessHeap(), 0, pwfx);
705 
706             /* try invalid handle */
707             rc = acmDriverClose((HACMDRIVER)1, 0);
708             ok(rc == MMSYSERR_INVALHANDLE,
709                "acmDriverClose(): rc = %08x, should be %08x\n",
710                rc, MMSYSERR_INVALHANDLE);
711 
712             /* try invalid flag */
713             rc = acmDriverClose(had, 1);
714             ok(rc == MMSYSERR_INVALFLAG,
715                "acmDriverClose(): rc = %08x, should be %08x\n",
716                rc, MMSYSERR_INVALFLAG);
717 
718             /* try valid parameters */
719             rc = acmDriverClose(had, 0);
720             ok(rc == MMSYSERR_NOERROR,
721                "acmDriverClose(): rc = %08x, should be %08x\n",
722                rc, MMSYSERR_NOERROR);
723 
724             /* try closing again */
725             rc = acmDriverClose(had, 0);
726             ok(rc == MMSYSERR_INVALHANDLE,
727                "acmDriverClose(): rc = %08x, should be %08x\n",
728                rc, MMSYSERR_INVALHANDLE);
729         }
730     }
731 
732     return TRUE;
733 }
734 
get_metric(UINT uMetric)735 static const char * get_metric(UINT uMetric)
736 {
737     switch (uMetric) {
738     case ACM_METRIC_COUNT_CODECS:
739         return "ACM_METRIC_COUNT_CODECS";
740     case ACM_METRIC_COUNT_CONVERTERS:
741         return "ACM_METRIC_COUNT_CONVERTERS";
742     case ACM_METRIC_COUNT_DISABLED:
743         return "ACM_METRIC_COUNT_DISABLED";
744     case ACM_METRIC_COUNT_DRIVERS:
745         return "ACM_METRIC_COUNT_DRIVERS";
746     case ACM_METRIC_COUNT_FILTERS:
747         return "ACM_METRIC_COUNT_FILTERS";
748     case ACM_METRIC_COUNT_HARDWARE:
749         return "ACM_METRIC_COUNT_HARDWARE";
750     case ACM_METRIC_COUNT_LOCAL_CODECS:
751         return "ACM_METRIC_COUNT_LOCAL_CODECS";
752     case ACM_METRIC_COUNT_LOCAL_CONVERTERS:
753         return "ACM_METRIC_COUNT_LOCAL_CONVERTERS";
754     case ACM_METRIC_COUNT_LOCAL_DISABLED:
755         return "ACM_METRIC_COUNT_LOCAL_DISABLED";
756     case ACM_METRIC_COUNT_LOCAL_DRIVERS:
757         return "ACM_METRIC_COUNT_LOCAL_DRIVERS";
758     case ACM_METRIC_COUNT_LOCAL_FILTERS:
759         return "ACM_METRIC_COUNT_LOCAL_FILTERS";
760     case ACM_METRIC_DRIVER_PRIORITY:
761         return "ACM_METRIC_DRIVER_PRIORITY";
762     case ACM_METRIC_DRIVER_SUPPORT:
763         return "ACM_METRIC_DRIVER_SUPPORT";
764     case ACM_METRIC_HARDWARE_WAVE_INPUT:
765         return "ACM_METRIC_HARDWARE_WAVE_INPUT";
766     case ACM_METRIC_HARDWARE_WAVE_OUTPUT:
767         return "ACM_METRIC_HARDWARE_WAVE_OUTPUT";
768     case ACM_METRIC_MAX_SIZE_FILTER:
769         return "ACM_METRIC_MAX_SIZE_FILTER";
770     case ACM_METRIC_MAX_SIZE_FORMAT:
771         return "ACM_METRIC_MAX_SIZE_FORMAT";
772     }
773 
774     return "UNKNOWN";
775 }
776 
check_count(UINT uMetric)777 static void check_count(UINT uMetric)
778 {
779     DWORD dwMetric;
780     MMRESULT rc;
781 
782     /* try invalid result pointer */
783     rc = acmMetrics(NULL, uMetric, 0);
784     ok(rc == MMSYSERR_INVALPARAM,
785        "acmMetrics(NULL, %s, 0): rc = 0x%08x, should be 0x%08x\n",
786        get_metric(uMetric), rc, MMSYSERR_INVALPARAM);
787 
788     /* try invalid handle */
789     rc = acmMetrics((HACMOBJ)1, uMetric, &dwMetric);
790     ok(rc == MMSYSERR_INVALHANDLE,
791        "acmMetrics(1, %s, %p): rc = 0x%08x, should be 0x%08x\n",
792        get_metric(uMetric), &dwMetric, rc, MMSYSERR_INVALHANDLE);
793 
794     /* try invalid result pointer and handle */
795     rc = acmMetrics((HACMOBJ)1, uMetric, 0);
796     ok(rc == MMSYSERR_INVALHANDLE,
797        "acmMetrics(1, %s, 0): rc = 0x%08x, should be 0x%08x\n",
798        get_metric(uMetric), rc, MMSYSERR_INVALHANDLE);
799 
800     /* try valid parameters */
801     rc = acmMetrics(NULL, uMetric, &dwMetric);
802     ok(rc == MMSYSERR_NOERROR, "acmMetrics() failed: rc = 0x%08x\n", rc);
803 
804     if (rc == MMSYSERR_NOERROR && winetest_interactive)
805         trace("%s: %u\n", get_metric(uMetric), dwMetric);
806 }
807 
driver_tests(void)808 static void driver_tests(void)
809 {
810     MMRESULT rc;
811     DWORD dwACMVersion = acmGetVersion();
812 
813     if (winetest_interactive) {
814         trace("ACM version = %u.%02u build %u%s\n",
815             HIWORD(dwACMVersion) >> 8,
816             HIWORD(dwACMVersion) & 0xff,
817             LOWORD(dwACMVersion),
818             LOWORD(dwACMVersion)  ==  0 ? " (Retail)" : "");
819     }
820 
821     check_count(ACM_METRIC_COUNT_CODECS);
822     check_count(ACM_METRIC_COUNT_CONVERTERS);
823     check_count(ACM_METRIC_COUNT_DISABLED);
824     check_count(ACM_METRIC_COUNT_DRIVERS);
825     check_count(ACM_METRIC_COUNT_FILTERS);
826     check_count(ACM_METRIC_COUNT_HARDWARE);
827     check_count(ACM_METRIC_COUNT_LOCAL_CODECS);
828     check_count(ACM_METRIC_COUNT_LOCAL_CONVERTERS);
829     check_count(ACM_METRIC_COUNT_LOCAL_DISABLED);
830     check_count(ACM_METRIC_COUNT_LOCAL_DRIVERS);
831     check_count(ACM_METRIC_COUNT_LOCAL_FILTERS);
832 
833     if (winetest_interactive)
834         trace("enabled drivers:\n");
835 
836     rc = acmDriverEnum(DriverEnumProc, 0, 0);
837     ok(rc == MMSYSERR_NOERROR,
838       "acmDriverEnum() failed, rc=%08x, should be 0x%08x\n",
839       rc, MMSYSERR_NOERROR);
840 }
841 
test_prepareheader(void)842 static void test_prepareheader(void)
843 {
844     HACMSTREAM has;
845     ADPCMWAVEFORMAT *src;
846     WAVEFORMATEX dst;
847     MMRESULT mr;
848     ACMSTREAMHEADER hdr;
849     BYTE buf[sizeof(WAVEFORMATEX) + 32], pcm[2048], input[512];
850     ADPCMCOEFSET *coef;
851 
852     src = (ADPCMWAVEFORMAT*)buf;
853     coef = src->aCoef;
854     src->wfx.cbSize = 32;
855     src->wfx.wFormatTag = WAVE_FORMAT_ADPCM;
856     src->wfx.nSamplesPerSec = 22050;
857     src->wfx.wBitsPerSample = 4;
858     src->wfx.nChannels = 1;
859     src->wfx.nBlockAlign = 512;
860     src->wfx.nAvgBytesPerSec = 11025;
861     src->wSamplesPerBlock = 0x3f4;
862     src->wNumCoef = 7;
863     coef[0].iCoef1 = 0x0100;
864     coef[0].iCoef2 = 0x0000;
865     coef[1].iCoef1 = 0x0200;
866     coef[1].iCoef2 = 0xff00;
867     coef[2].iCoef1 = 0x0000;
868     coef[2].iCoef2 = 0x0000;
869     coef[3].iCoef1 = 0x00c0;
870     coef[3].iCoef2 = 0x0040;
871     coef[4].iCoef1 = 0x00f0;
872     coef[4].iCoef2 = 0x0000;
873     coef[5].iCoef1 = 0x01cc;
874     coef[5].iCoef2 = 0xff30;
875     coef[6].iCoef1 = 0x0188;
876     coef[6].iCoef2 = 0xff18;
877 
878     dst.cbSize = 0;
879     dst.wFormatTag = WAVE_FORMAT_PCM;
880     dst.nSamplesPerSec = 22050;
881     dst.wBitsPerSample = 8;
882     dst.nChannels = 1;
883     dst.nBlockAlign = dst.wBitsPerSample * dst.nChannels / 8;
884     dst.nAvgBytesPerSec = dst.nSamplesPerSec * dst.nBlockAlign;
885 
886     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)src, &dst, NULL, 0, 0, 0);
887     ok(mr == MMSYSERR_NOERROR, "open failed: 0x%x\n", mr);
888 
889     memset(input, 0, sizeof(input));
890     memset(&hdr, 0, sizeof(hdr));
891     hdr.cbStruct = sizeof(hdr);
892     hdr.pbSrc = input;
893     hdr.cbSrcLength = sizeof(input);
894     hdr.pbDst = pcm;
895     hdr.cbDstLength = sizeof(pcm);
896 
897     mr = acmStreamPrepareHeader(has, &hdr, 0);
898     ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
899     ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_PREPARED, "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
900 
901     mr = acmStreamUnprepareHeader(has, &hdr, 0);
902     ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
903     ok(hdr.fdwStatus == 0, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
904 
905     memset(&hdr, 0, sizeof(hdr));
906     hdr.cbStruct = sizeof(hdr);
907     hdr.pbSrc = input;
908     hdr.cbSrcLength = 0; /* invalid source length */
909     hdr.pbDst = pcm;
910     hdr.cbDstLength = sizeof(pcm);
911 
912     mr = acmStreamPrepareHeader(has, &hdr, 0);
913     ok(mr == MMSYSERR_INVALPARAM, "expected 0x0b, got 0x%x\n", mr);
914 
915     hdr.cbSrcLength = src->wfx.nBlockAlign - 1; /* less than block align */
916     mr = acmStreamPrepareHeader(has, &hdr, 0);
917     ok(mr == ACMERR_NOTPOSSIBLE, "expected 0x200, got 0x%x\n", mr);
918 
919     hdr.cbSrcLength = src->wfx.nBlockAlign + 1; /* more than block align */
920     mr = acmStreamPrepareHeader(has, &hdr, 0);
921     ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
922 
923     mr = acmStreamUnprepareHeader(has, &hdr, 0);
924     ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
925 
926     hdr.cbSrcLength = src->wfx.nBlockAlign;
927     mr = acmStreamPrepareHeader(has, &hdr, 1); /* invalid use of reserved parameter */
928     ok(mr == MMSYSERR_INVALFLAG, "expected 0x0a, got 0x%x\n", mr);
929 
930     mr = acmStreamPrepareHeader(has, &hdr, 0);
931     ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
932 
933     mr = acmStreamUnprepareHeader(has, &hdr, 0);
934     ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
935 
936     memset(&hdr, 0, sizeof(hdr));
937     hdr.cbStruct = sizeof(hdr);
938     hdr.pbSrc = input;
939     hdr.cbSrcLength = sizeof(input);
940     hdr.pbDst = pcm;
941     hdr.cbDstLength = sizeof(pcm);
942     hdr.fdwStatus = ACMSTREAMHEADER_STATUSF_DONE;
943 
944     mr = acmStreamPrepareHeader(has, &hdr, 0);
945     ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
946     ok(hdr.fdwStatus == (ACMSTREAMHEADER_STATUSF_PREPARED | ACMSTREAMHEADER_STATUSF_DONE), "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
947 
948     hdr.cbSrcLengthUsed = 12345;
949     hdr.cbDstLengthUsed = 12345;
950     hdr.fdwStatus &= ~ACMSTREAMHEADER_STATUSF_DONE;
951     mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
952     ok(mr == MMSYSERR_NOERROR, "convert failed: 0x%x\n", mr);
953     ok(hdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE, "conversion was not done: 0x%x\n", hdr.fdwStatus);
954     ok(hdr.cbSrcLengthUsed == hdr.cbSrcLength, "expected %d, got %d\n", hdr.cbSrcLength, hdr.cbSrcLengthUsed);
955 todo_wine
956     ok(hdr.cbDstLengthUsed == 1010, "expected 1010, got %d\n", hdr.cbDstLengthUsed);
957 
958     mr = acmStreamUnprepareHeader(has, &hdr, 0);
959     ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
960     ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_DONE, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
961 
962     /* The 2 next tests are related to Lost Horizon (bug 24723) */
963     memset(&hdr, 0, sizeof(hdr));
964     hdr.cbStruct = sizeof(hdr);
965     hdr.pbSrc = input;
966     hdr.cbSrcLength = sizeof(input);
967     hdr.pbDst = pcm;
968     hdr.cbDstLength = -4;
969 
970     mr = acmStreamPrepareHeader(has, &hdr, 0);
971     if (sizeof(void *) == 4) /* 64 bit fails on this test */
972     {
973         ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
974         ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_PREPARED, "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
975 
976         hdr.cbSrcLengthUsed = 12345;
977         hdr.cbDstLengthUsed = 12345;
978         hdr.fdwStatus &= ~ACMSTREAMHEADER_STATUSF_DONE;
979         mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
980         ok(mr == MMSYSERR_NOERROR, "convert failed: 0x%x\n", mr);
981         ok(hdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE, "conversion was not done: 0x%x\n", hdr.fdwStatus);
982         ok(hdr.cbSrcLengthUsed == hdr.cbSrcLength, "expected %d, got %d\n", hdr.cbSrcLength, hdr.cbSrcLengthUsed);
983 todo_wine
984         ok(hdr.cbDstLengthUsed == 1010, "expected 1010, got %d\n", hdr.cbDstLengthUsed);
985 
986         mr = acmStreamUnprepareHeader(has, &hdr, 0);
987         ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
988         ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_DONE, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
989     }
990     else
991 todo_wine
992         ok(mr == MMSYSERR_INVALPARAM, "expected 0x0b, got 0x%x\n", mr);
993 
994     memset(&hdr, 0, sizeof(hdr));
995     hdr.cbStruct = sizeof(hdr);
996     hdr.pbSrc = input;
997     hdr.cbSrcLength = 24;
998     hdr.pbDst = pcm;
999     hdr.cbDstLength = -4;
1000     mr = acmStreamPrepareHeader(has, &hdr, 0);
1001     ok(mr == ACMERR_NOTPOSSIBLE, "expected 0x200, got 0x%x\n", mr);
1002     ok(hdr.fdwStatus == 0, "expected 0, got 0x%x\n", hdr.fdwStatus);
1003 
1004     hdr.cbSrcLengthUsed = 12345;
1005     hdr.cbDstLengthUsed = 12345;
1006     mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
1007     ok(mr == ACMERR_UNPREPARED, "expected 0x202, got 0x%x\n", mr);
1008     ok(hdr.cbSrcLengthUsed == 12345, "expected 12345, got %d\n", hdr.cbSrcLengthUsed);
1009     ok(hdr.cbDstLengthUsed == 12345, "expected 12345, got %d\n", hdr.cbDstLengthUsed);
1010 
1011     mr = acmStreamUnprepareHeader(has, &hdr, 0);
1012     ok(mr == ACMERR_UNPREPARED, "expected 0x202, got 0x%x\n", mr);
1013 
1014     /* Less output space than required */
1015     memset(&hdr, 0, sizeof(hdr));
1016     hdr.cbStruct = sizeof(hdr);
1017     hdr.pbSrc = input;
1018     hdr.cbSrcLength = sizeof(input);
1019     hdr.pbDst = pcm;
1020     hdr.cbDstLength = 32;
1021 
1022     mr = acmStreamPrepareHeader(has, &hdr, 0);
1023     ok(mr == MMSYSERR_NOERROR, "prepare failed: 0x%x\n", mr);
1024     ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_PREPARED, "header wasn't prepared: 0x%x\n", hdr.fdwStatus);
1025 
1026     hdr.cbSrcLengthUsed = 12345;
1027     hdr.cbDstLengthUsed = 12345;
1028     hdr.fdwStatus &= ~ACMSTREAMHEADER_STATUSF_DONE;
1029     mr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
1030     ok(mr == MMSYSERR_NOERROR, "convert failed: 0x%x\n", mr);
1031     ok(hdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE, "conversion was not done: 0x%x\n", hdr.fdwStatus);
1032 todo_wine
1033     ok(hdr.cbSrcLengthUsed == hdr.cbSrcLength, "expected %d, got %d\n", hdr.cbSrcLength, hdr.cbSrcLengthUsed);
1034 todo_wine
1035     ok(hdr.cbDstLengthUsed == hdr.cbDstLength, "expected %d, got %d\n", hdr.cbDstLength, hdr.cbDstLengthUsed);
1036 
1037     mr = acmStreamUnprepareHeader(has, &hdr, 0);
1038     ok(mr == MMSYSERR_NOERROR, "unprepare failed: 0x%x\n", mr);
1039     ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_DONE, "header wasn't unprepared: 0x%x\n", hdr.fdwStatus);
1040 
1041     mr = acmStreamClose(has, 0);
1042     ok(mr == MMSYSERR_NOERROR, "close failed: 0x%x\n", mr);
1043 }
1044 
1045 static const BYTE input[64] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63};
1046 
1047 struct stream_output
1048 {
1049     WAVEFORMATEX src;
1050     WAVEFORMATEX dst;
1051     BYTE output[256];
1052     DWORD dst_used;
1053     BOOL todo;
1054 };
1055 
1056 static const struct stream_output expected_output[] = {
1057     /* #0: Identical conversion */
1058     {{WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63}, 64, FALSE},
1059 
1060     /* #1: 1 -> 2 channels */
1061     {{WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {WAVE_FORMAT_PCM, 2, 8000, 16000, 2, 8}, {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63}, 128, FALSE},
1062 
1063     /* #2: 2 -> 1 channels: all of the audio underflows due to addition */
1064     {{WAVE_FORMAT_PCM, 2, 8000, 16000, 2, 8}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, 32, FALSE},
1065 
1066     /* #3: 2 -> 2 channels */
1067     {{WAVE_FORMAT_PCM, 2, 8000, 16000, 2, 8}, {WAVE_FORMAT_PCM, 2, 8000, 16000, 2, 8}, {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63}, 64, FALSE},
1068 
1069     /* #4: 8 -> 16 bits per sample */
1070     {{WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {WAVE_FORMAT_PCM, 1, 8000, 16000, 2, 16}, {0,128,0,129,0,130,0,131,0,132,0,133,0,134,0,135,0,136,0,137,0,138,0,139,0,140,0,141,0,142,0,143,0,144,0,145,0,146,0,147,0,148,0,149,0,150,0,151,0,152,0,153,0,154,0,155,0,156,0,157,0,158,0,159,0,160,0,161,0,162,0,163,0,164,0,165,0,166,0,167,0,168,0,169,0,170,0,171,0,172,0,173,0,174,0,175,0,176,0,177,0,178,0,179,0,180,0,181,0,182,0,183,0,184,0,185,0,186,0,187,0,188,0,189,0,190,0,191}, 128, FALSE},
1071 
1072     /* #5: 16 -> 8 bits per sample */
1073     {{WAVE_FORMAT_PCM, 1, 8000, 16000, 2, 16}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {129,131,133,135,137,139,141,143,145,147,149,151,153,155,157,159,161,163,165,167,169,171,173,175,177,179,181,183,185,187,189,191}, 32, FALSE},
1074 
1075     /* #6: 16 bits per sample, 2 -> 1 channels */
1076     {{WAVE_FORMAT_PCM, 2, 8000, 32000, 4, 16}, {WAVE_FORMAT_PCM, 1, 8000, 16000, 2, 16}, {2,4,10,12,18,20,26,28,34,36,42,44,50,52,58,60,66,68,74,76,82,84,90,92,98,100,106,108,114,116,122,124}, 32, FALSE},
1077 
1078     /* #7: 8000 -> 11025 sample rate */
1079     /* FIXME: upsampling is slightly off on wine - the algorithm is wrong whenever error > (srcrate + dstrate) / 2 */
1080     {{WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {WAVE_FORMAT_PCM, 1, 11025, 11025, 1, 8}, {0,1,1,2,3,4,4,5,6,7,7,8,9,9,10,11,12,12,13,14,15,15,16,17,17,18,19,20,20,21,22,22,23,24,25,25,26,27,28,28,29,30,30,31,32,33,33,34,35,36,36,37,38,38,39,40,41,41,42,43,44,44,45,46,46,47,48,49,49,50,51,52,52,53,54,54,55,56,57,57,58,59,60,60,61,62,62,63}, 88, TRUE},
1081 
1082     /* #8: 8000 -> 22050 sample rate */
1083     {{WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8}, {0,0,1,1,1,2,2,3,3,3,4,4,4,5,5,5,6,6,7,7,7,8,8,8,9,9,9,10,10,11,11,11,12,12,12,13,13,13,14,14,15,15,15,16,16,16,17,17,17,18,18,19,19,19,20,20,20,21,21,21,22,22,22,23,23,24,24,24,25,25,25,26,26,26,27,27,28,28,28,29,29,29,30,30,30,31,31,32,32,32,33,33,33,34,34,34,35,35,36,36,36,37,37,37,38,38,38,39,39,40,40,40,41,41,41,42,42,42,43,43,44,44,44,45,45,45,46,46,46,47,47,48,48,48,49,49,49,50,50,50,51,51,52,52,52,53,53,53,54,54,54,55,55,56,56,56,57,57,57,58,58,58,59,59,60,60,60,61,61,61,62,62,62,63,63,63}, 176, TRUE},
1084 
1085     /* #9: 11025 -> 22050 sample rate */
1086     {{WAVE_FORMAT_PCM, 1, 11025, 11025, 1, 8}, {WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8}, {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,52,53,53,54,54,55,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63}, 128, FALSE},
1087 
1088     /* #10: 22050 -> 11025 sample rate */
1089     {{WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8}, {WAVE_FORMAT_PCM, 1, 11025, 11025, 1, 8}, {1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63}, 32, FALSE},
1090 
1091     /* #11: 11025 -> 8000 sample rate */
1092     {{WAVE_FORMAT_PCM, 1, 11025, 11025, 1, 8}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {0,2,3,4,6,7,8,10,11,13,14,15,17,18,19,21,22,24,25,26,28,29,31,32,33,35,36,37,39,40,42,43,44,46,47,48,50,51,53,54,55,57,58,59,61,62}, 46, FALSE},
1093 
1094     /* #12: 22050 -> 8000 sample rate */
1095     {{WAVE_FORMAT_PCM, 1, 22050, 22050, 1, 8}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {1,4,6,9,12,15,17,20,23,26,28,31,34,37,39,42,45,48,50,53,56,59,62}, 23, FALSE},
1096 
1097     /* #13: 44100 -> 8000 sample rate */
1098     {{WAVE_FORMAT_PCM, 1, 44100, 44100, 1, 8}, {WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8}, {2,8,13,19,24,30,35,41,46,52,57,63}, 12, FALSE},
1099 };
1100 
test_convert(void)1101 static void test_convert(void)
1102 {
1103     HACMSTREAM has;
1104     ACMSTREAMHEADER hdr = {0};
1105     BYTE output[256];
1106     MMRESULT mmr;
1107     unsigned i;
1108 
1109     for (i = 0; i < ARRAY_SIZE(expected_output); i++)
1110     {
1111         mmr = acmStreamOpen(&has, NULL, (WAVEFORMATEX *)&expected_output[i].src, (WAVEFORMATEX *)&expected_output[i].dst, NULL, 0, 0, 0);
1112         ok(mmr == MMSYSERR_NOERROR, "#%d: open failed: 0x%x\n", i, mmr);
1113 
1114         memset(&hdr, 0, sizeof(hdr));
1115         hdr.cbStruct = sizeof(hdr);
1116         hdr.pbSrc = (BYTE *)input;
1117         hdr.cbSrcLength = sizeof(input);
1118         hdr.pbDst = output;
1119         hdr.cbDstLength = sizeof(output);
1120 
1121         mmr = acmStreamPrepareHeader(has, &hdr, 0);
1122         ok(mmr == MMSYSERR_NOERROR, "#%d: prepare failed: 0x%x\n", i, mmr);
1123         ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_PREPARED, "#%d: header wasn't prepared: 0x%x\n", i, hdr.fdwStatus);
1124 
1125         memset(&output, 0, sizeof(output));
1126         mmr = acmStreamConvert(has, &hdr, ACM_STREAMCONVERTF_BLOCKALIGN);
1127         ok(mmr == MMSYSERR_NOERROR, "#%d: convert failed: 0x%x\n", i, mmr);
1128         ok(hdr.fdwStatus & ACMSTREAMHEADER_STATUSF_DONE, "#%d: conversion was not done: 0x%x\n", i, hdr.fdwStatus);
1129         ok(hdr.cbSrcLengthUsed == hdr.cbSrcLength, "#%d: expected %d, got %d\n", i, hdr.cbSrcLength, hdr.cbSrcLengthUsed);
1130         ok(hdr.cbDstLengthUsed == expected_output[i].dst_used, "#%d: expected %d, got %d\n", i, expected_output[i].dst_used, hdr.cbDstLengthUsed);
1131 todo_wine_if(expected_output[i].todo)
1132         ok(!memcmp(expected_output[i].output, output, hdr.cbDstLengthUsed), "#%d: output does not match\n", i);
1133 
1134         mmr = acmStreamUnprepareHeader(has, &hdr, 0);
1135         ok(mmr == MMSYSERR_NOERROR, "#%d: unprepare failed: 0x%x\n", i, mmr);
1136         ok(hdr.fdwStatus == ACMSTREAMHEADER_STATUSF_DONE, "#%d: header wasn't unprepared: 0x%x\n", i, hdr.fdwStatus);
1137 
1138         mmr = acmStreamClose(has, 0);
1139         ok(mmr == MMSYSERR_NOERROR, "#%d: close failed: 0x%x\n", i, mmr);
1140     }
1141 }
1142 
test_acmFormatSuggest(void)1143 static void test_acmFormatSuggest(void)
1144 {
1145     WAVEFORMATEX src, dst;
1146     DWORD suggest;
1147     MMRESULT rc;
1148     DWORD sizeMax;
1149 
1150     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &sizeMax);
1151 
1152     /* Test a valid PCM format */
1153     src.wFormatTag = WAVE_FORMAT_PCM;
1154     src.nChannels = 1;
1155     src.nSamplesPerSec = 8000;
1156     src.nAvgBytesPerSec = 16000;
1157     src.nBlockAlign = 2;
1158     src.wBitsPerSample = 16;
1159     src.cbSize = 0;
1160     suggest = 0;
1161     memset(&dst, 0, sizeof(dst));
1162     rc = acmFormatSuggest(NULL, &src, &dst, sizeof(PCMWAVEFORMAT), suggest);
1163     ok(rc == MMSYSERR_NOERROR, "failed with error 0x%x\n", rc);
1164     ok(src.wFormatTag == dst.wFormatTag, "expected %d, got %d\n", src.wFormatTag, dst.wFormatTag);
1165     ok(src.nChannels == dst.nChannels, "expected %d, got %d\n", src.nChannels, dst.nChannels);
1166     ok(src.nSamplesPerSec == dst.nSamplesPerSec, "expected %d, got %d\n", src.nSamplesPerSec, dst.nSamplesPerSec);
1167     ok(src.nAvgBytesPerSec == dst.nAvgBytesPerSec, "expected %d, got %d\n", src.nAvgBytesPerSec, dst.nAvgBytesPerSec);
1168     ok(src.nBlockAlign == dst.nBlockAlign, "expected %d, got %d\n", src.nBlockAlign, dst.nBlockAlign);
1169     ok(src.wBitsPerSample == dst.wBitsPerSample, "expected %d, got %d\n", src.wBitsPerSample, dst.wBitsPerSample);
1170 
1171     /* All parameters from destination are valid */
1172     suggest = ACM_FORMATSUGGESTF_NCHANNELS
1173             | ACM_FORMATSUGGESTF_NSAMPLESPERSEC
1174             | ACM_FORMATSUGGESTF_WBITSPERSAMPLE
1175             | ACM_FORMATSUGGESTF_WFORMATTAG;
1176     dst = src;
1177     rc = acmFormatSuggest(NULL, &src, &dst, sizeof(PCMWAVEFORMAT), suggest);
1178     ok(rc == MMSYSERR_NOERROR, "failed with error 0x%x\n", rc);
1179     ok(src.wFormatTag == dst.wFormatTag, "expected %d, got %d\n", src.wFormatTag, dst.wFormatTag);
1180     ok(src.nChannels == dst.nChannels, "expected %d, got %d\n", src.nChannels, dst.nChannels);
1181     ok(src.nSamplesPerSec == dst.nSamplesPerSec, "expected %d, got %d\n", src.nSamplesPerSec, dst.nSamplesPerSec);
1182     ok(src.nAvgBytesPerSec == dst.nAvgBytesPerSec, "expected %d, got %d\n", src.nAvgBytesPerSec, dst.nAvgBytesPerSec);
1183     ok(src.nBlockAlign == dst.nBlockAlign, "expected %d, got %d\n", src.nBlockAlign, dst.nBlockAlign);
1184     ok(src.wBitsPerSample == dst.wBitsPerSample, "expected %d, got %d\n", src.wBitsPerSample, dst.wBitsPerSample);
1185 
1186     /* Test an invalid PCM format */
1187     ZeroMemory(&dst, sizeof(dst));
1188     src.nSamplesPerSec = 0xdeadbeef;
1189     suggest = 0;
1190     rc = acmFormatSuggest(NULL, &src, &dst, sizeMax, suggest);
1191     todo_wine {
1192     ok(rc == MMSYSERR_NOERROR, "failed with error 0x%x\n", rc);
1193     ok(dst.wFormatTag == WAVE_FORMAT_PCM, "expected %d, got %d\n", WAVE_FORMAT_PCM, dst.wFormatTag);
1194     ok(dst.nSamplesPerSec == 0xdeadbeef, "expected %d, got %d\n", 0xdeadbeef, dst.nSamplesPerSec);
1195     }
1196     src.nSamplesPerSec = 8000;
1197 
1198     /* Test a nonexistent format */
1199     src.wFormatTag = 0xbeef;
1200     rc = acmFormatSuggest(NULL, &src, &dst, sizeMax-1, suggest);
1201     ok(rc == MMSYSERR_INVALPARAM, "failed with error 0x%x\n", rc);
1202 
1203     rc = acmFormatSuggest(NULL, &src, &dst, sizeMax, suggest);
1204     todo_wine
1205     ok(rc == MMSYSERR_NODRIVER, "failed with error 0x%x\n", rc);
1206 
1207     /* Test converting between two known but incompatible formats */
1208     src.wFormatTag = WAVE_FORMAT_ALAW;
1209     src.nChannels = 1;
1210     src.nSamplesPerSec = 8000;
1211     src.nAvgBytesPerSec = 8000;
1212     src.nBlockAlign = 1;
1213     src.wBitsPerSample = 8;
1214     src.cbSize = 0;
1215     suggest = ACM_FORMATSUGGESTF_WFORMATTAG;
1216     dst.wFormatTag = WAVE_FORMAT_IMA_ADPCM;
1217     rc = acmFormatSuggest(NULL, &src, &dst, sizeof(IMAADPCMWAVEFORMAT)-1, suggest);
1218     ok(rc == MMSYSERR_INVALPARAM, "failed with error 0x%x\n", rc);
1219 
1220     rc = acmFormatSuggest(NULL, &src, &dst, sizeof(IMAADPCMWAVEFORMAT), suggest);
1221     todo_wine
1222     ok(rc == MMSYSERR_NODRIVER, "failed with error 0x%x\n", rc);
1223 
1224     /* Invalid suggest flags */
1225     src.wFormatTag = WAVE_FORMAT_PCM;
1226     suggest = 0xFFFFFFFF;
1227     rc = acmFormatSuggest(NULL, &src, &dst, sizeof(dst), suggest);
1228     ok(rc == MMSYSERR_INVALFLAG, "failed with error 0x%x\n", rc);
1229 
1230     /* Invalid source and destination */
1231     suggest = 0;
1232     rc = acmFormatSuggest(NULL, NULL, &dst, sizeof(dst), suggest);
1233     ok(rc == MMSYSERR_INVALPARAM, "failed with error 0x%x\n", rc);
1234     rc = acmFormatSuggest(NULL, &src, NULL, sizeof(dst), suggest);
1235     ok(rc == MMSYSERR_INVALPARAM, "failed with error 0x%x\n", rc);
1236     rc = acmFormatSuggest(NULL, NULL, NULL, sizeof(dst), suggest);
1237     ok(rc == MMSYSERR_INVALPARAM, "failed with error 0x%x\n", rc);
1238 }
1239 
test_acmFormatTagDetails(void)1240 static void test_acmFormatTagDetails(void)
1241 {
1242     ACMFORMATTAGDETAILSW aftd = {0};
1243     MMRESULT rc;
1244 
1245     aftd.cbStruct = sizeof(aftd);
1246     aftd.dwFormatTag = WAVE_FORMAT_MPEGLAYER3;
1247     rc = acmFormatTagDetailsW(NULL, &aftd, ACM_FORMATTAGDETAILSF_FORMATTAG);
1248     if (rc == MMSYSERR_NOERROR)
1249         ok(aftd.cbFormatSize == sizeof(MPEGLAYER3WAVEFORMAT), "got %d\n", aftd.cbFormatSize);
1250 }
1251 
test_acmFormatChoose(void)1252 static void test_acmFormatChoose(void)
1253 {
1254     ACMFORMATCHOOSEW afc = {0};
1255     WAVEFORMATEX *pwfx;
1256     DWORD sizeMax;
1257     MMRESULT rc;
1258 
1259     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &sizeMax);
1260     pwfx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeMax);
1261 
1262     afc.cbStruct = sizeof(afc);
1263     afc.pwfx = pwfx;
1264 
1265     /* test invalid struct size */
1266     afc.cbStruct = sizeof(afc)-1;
1267     rc = acmFormatChooseW(&afc);
1268     ok(rc == MMSYSERR_INVALPARAM, "expected 0xb, got 0x%x\n", rc);
1269     afc.cbStruct = sizeof(afc);
1270 
1271     afc.pwfx = NULL;
1272     rc = acmFormatChooseW(&afc);
1273     ok(rc == MMSYSERR_INVALPARAM, "expected 0xb, got 0x%x\n", rc);
1274     afc.pwfx = pwfx;
1275 
1276     HeapFree(GetProcessHeap(), 0, pwfx);
1277 }
1278 
test_mp3(void)1279 static void test_mp3(void)
1280 {
1281     MPEGLAYER3WAVEFORMAT src;
1282     WAVEFORMATEX dst;
1283     HACMSTREAM has;
1284     DWORD output;
1285     MMRESULT mr;
1286 
1287     src.wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
1288     src.wfx.nSamplesPerSec = 11025;
1289     src.wfx.wBitsPerSample = 0;
1290     src.wfx.nChannels = 1;
1291     src.wfx.nBlockAlign = 576;
1292     src.wfx.nAvgBytesPerSec = 2000;
1293 
1294     src.wID = MPEGLAYER3_ID_MPEG;
1295     src.fdwFlags = 0;
1296     src.nBlockSize = 576;
1297     src.nFramesPerBlock = 1;
1298     src.nCodecDelay = 0;
1299 
1300     dst.cbSize = 0;
1301     dst.wFormatTag = WAVE_FORMAT_PCM;
1302     dst.nSamplesPerSec = 11025;
1303     dst.wBitsPerSample = 16;
1304     dst.nChannels = 1;
1305     dst.nBlockAlign = dst.wBitsPerSample * dst.nChannels / 8;
1306     dst.nAvgBytesPerSec = dst.nSamplesPerSec * dst.nBlockAlign;
1307 
1308     src.wfx.cbSize = 0;
1309 
1310     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)&src, &dst, NULL, 0, 0, 0);
1311     ok(mr == ACMERR_NOTPOSSIBLE, "expected error ACMERR_NOTPOSSIBLE, got 0x%x\n", mr);
1312     if (mr == MMSYSERR_NOERROR) acmStreamClose(has, 0);
1313 
1314     src.wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
1315     src.wID = 0;
1316 
1317     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)&src, &dst, NULL, 0, 0, 0);
1318     ok(mr == ACMERR_NOTPOSSIBLE, "expected error ACMERR_NOTPOSSIBLE, got 0x%x\n", mr);
1319     if (mr == MMSYSERR_NOERROR) acmStreamClose(has, 0);
1320 
1321     src.wID = MPEGLAYER3_ID_MPEG;
1322     src.nBlockSize = 0;
1323 
1324     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)&src, &dst, NULL, 0, 0, 0);
1325     ok(mr == MMSYSERR_NOERROR || broken(mr == ACMERR_NOTPOSSIBLE) /* Win 2008 */,
1326        "failed with error 0x%x\n", mr);
1327     if (mr == MMSYSERR_NOERROR)
1328     {
1329        mr = acmStreamClose(has, 0);
1330        ok(mr == MMSYSERR_NOERROR, "failed with error 0x%x\n", mr);
1331     }
1332     src.nBlockSize = 576;
1333     src.wfx.nAvgBytesPerSec = 0;
1334 
1335     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)&src, &dst, NULL, 0, 0, 0);
1336     ok(mr == MMSYSERR_NOERROR || broken(mr == ACMERR_NOTPOSSIBLE) /* Win 2008 */,
1337        "failed with error 0x%x\n", mr);
1338     if (mr == MMSYSERR_NOERROR)
1339     {
1340        /* causes a division by zero exception in XP, Vista,
1341           but throws ACMERR_NOTPOSSIBLE on others */
1342        if (0) acmStreamSize(has, 4000, &output, ACM_STREAMSIZEF_SOURCE);
1343        mr = acmStreamClose(has, 0);
1344        ok(mr == MMSYSERR_NOERROR, "failed with error 0x%x\n", mr);
1345     }
1346 
1347     src.wfx.nAvgBytesPerSec = 2000;
1348 
1349     mr = acmStreamOpen(&has, NULL, (WAVEFORMATEX*)&src, &dst, NULL, 0, 0, 0);
1350     ok(mr == MMSYSERR_NOERROR || broken(mr == ACMERR_NOTPOSSIBLE) /* Win 2008 */,
1351        "failed with error 0x%x\n", mr);
1352     if (mr == MMSYSERR_NOERROR)
1353     {
1354        mr = acmStreamSize(has, 4000, &output, ACM_STREAMSIZEF_SOURCE);
1355        ok(mr == MMSYSERR_NOERROR, "failed with error 0x%x\n", mr);
1356        mr = acmStreamClose(has, 0);
1357        ok(mr == MMSYSERR_NOERROR, "failed with error 0x%x\n", mr);
1358     }
1359 }
1360 
1361 static struct
1362 {
1363     struct
1364     {
1365         int load, free, open, close, enable, disable, install,
1366             remove, details, notify, querycfg, about;
1367     } driver;
1368     struct
1369     {
1370         int tag_details, details, suggest;
1371     } format;
1372     struct
1373     {
1374         int open, close, size, convert, prepare, unprepare, reset;
1375     } stream;
1376     int other;
1377 } driver_calls;
1378 
acm_driver_func(DWORD_PTR id,HDRVR handle,UINT msg,LPARAM param1,LPARAM param2)1379 static LRESULT CALLBACK acm_driver_func(DWORD_PTR id, HDRVR handle, UINT msg, LPARAM param1, LPARAM param2)
1380 {
1381     switch (msg)
1382     {
1383         /* Driver messages */
1384         case DRV_LOAD:
1385             driver_calls.driver.load++;
1386             return 1;
1387         case DRV_FREE:
1388             driver_calls.driver.free++;
1389             return 1;
1390         case DRV_OPEN:
1391             driver_calls.driver.open++;
1392             return 1;
1393         case DRV_CLOSE:
1394             driver_calls.driver.close++;
1395             return 1;
1396         case DRV_ENABLE:
1397             driver_calls.driver.enable++;
1398             return 1;
1399         case DRV_DISABLE:
1400             driver_calls.driver.disable++;
1401             return 1;
1402         case DRV_QUERYCONFIGURE:
1403             driver_calls.driver.querycfg++;
1404             return 1;
1405         case DRV_INSTALL:
1406             driver_calls.driver.install++;
1407             return DRVCNF_RESTART;
1408         case DRV_REMOVE:
1409             driver_calls.driver.remove++;
1410             return DRVCNF_RESTART;
1411         case ACMDM_DRIVER_ABOUT:
1412             driver_calls.driver.about++;
1413             return MMSYSERR_NOTSUPPORTED;
1414         case ACMDM_DRIVER_DETAILS:
1415         {
1416             ACMDRIVERDETAILSA *ptr = (ACMDRIVERDETAILSA *)param1;
1417 
1418             /* copied from pcmconverter.c */
1419             ptr->fccType = ACMDRIVERDETAILS_FCCTYPE_AUDIOCODEC;
1420             ptr->fccComp = ACMDRIVERDETAILS_FCCCOMP_UNDEFINED;
1421             ptr->wMid = MM_MICROSOFT;
1422             ptr->wPid = MM_MSFT_ACM_PCM;
1423             ptr->vdwACM = 0x01000000;
1424             ptr->vdwDriver = 0x01000000;
1425             ptr->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_CONVERTER;
1426             ptr->cFormatTags = 1;
1427             ptr->cFilterTags = 0;
1428             ptr->hicon = NULL;
1429             strcpy(ptr->szShortName, "TEST-CODEC");
1430             strcpy(ptr->szLongName, "Wine Test Codec");
1431             strcpy(ptr->szCopyright, "Brought to you by the Wine team...");
1432             strcpy(ptr->szLicensing, "Refer to LICENSE file");
1433             ptr->szFeatures[0] = 0;
1434 
1435             driver_calls.driver.details++;
1436             break;
1437         }
1438         case ACMDM_DRIVER_NOTIFY:
1439             driver_calls.driver.notify++;
1440             return MMSYSERR_NOTSUPPORTED;
1441 
1442         /* Format messages */
1443         case ACMDM_FORMATTAG_DETAILS:
1444             driver_calls.format.tag_details++;
1445             break;
1446         case ACMDM_FORMAT_DETAILS:
1447             driver_calls.format.details++;
1448             break;
1449         case ACMDM_FORMAT_SUGGEST:
1450             driver_calls.format.suggest++;
1451             break;
1452 
1453         /* Stream messages */
1454         case ACMDM_STREAM_OPEN:
1455             driver_calls.stream.open++;
1456             break;
1457         case ACMDM_STREAM_CLOSE:
1458             driver_calls.stream.close++;
1459             break;
1460         case ACMDM_STREAM_SIZE:
1461             driver_calls.stream.size++;
1462             break;
1463         case ACMDM_STREAM_CONVERT:
1464             driver_calls.stream.convert++;
1465             break;
1466         case ACMDM_STREAM_RESET:
1467             driver_calls.stream.reset++;
1468             return MMSYSERR_NOTSUPPORTED;
1469         case ACMDM_STREAM_PREPARE:
1470             driver_calls.stream.prepare++;
1471             break;
1472         case ACMDM_STREAM_UNPREPARE:
1473             driver_calls.stream.unprepare++;
1474             break;
1475 
1476         default:
1477             driver_calls.other++;
1478             return DefDriverProc(id, handle, msg, param1, param2);
1479     }
1480     return MMSYSERR_NOERROR;
1481 }
1482 
test_acmDriverAdd(void)1483 static void test_acmDriverAdd(void)
1484 {
1485     MMRESULT res;
1486     HACMDRIVERID drvid;
1487     union
1488     {
1489       ACMDRIVERDETAILSA drv_details;
1490     } acm;
1491 
1492     /* Driver load steps:
1493      * - acmDriverAdd checks the passed parameters
1494      * - DRV_LOAD message is sent - required
1495      * - DRV_ENABLE message is sent - required
1496      * - DRV_OPEN message is sent - required
1497      * - DRV_DETAILS message is sent - required
1498      * - ACMDM_FORMATTAG_DETAILS message is sent - optional
1499      * - DRV_QUERYCONFIGURE message is sent - optional
1500      * - ACMDM_DRIVER_ABOUT message is sent - optional
1501      */
1502 
1503     res = acmDriverAddA(&drvid, GetModuleHandleA(NULL), (LPARAM)acm_driver_func, 0, ACM_DRIVERADDF_FUNCTION);
1504     ok(res == MMSYSERR_NOERROR, "Expected 0, got %d\n", res);
1505 todo_wine
1506     ok(driver_calls.driver.open == 1, "Expected 1, got %d\n", driver_calls.driver.open);
1507     ok(driver_calls.driver.details == 1, "Expected 1, got %d\n", driver_calls.driver.details);
1508 
1509     memset(&acm, 0, sizeof(acm));
1510     res = acmDriverDetailsA(drvid, &acm.drv_details, 0);
1511     ok(res == MMSYSERR_INVALPARAM, "Expected 11, got %d\n", res);
1512 
1513     acm.drv_details.cbStruct = sizeof(acm.drv_details);
1514     res = acmDriverDetailsA(drvid, &acm.drv_details, 0);
1515     ok(res == MMSYSERR_NOERROR, "Expected 0, got %d\n", res);
1516 todo_wine
1517     ok(driver_calls.driver.open == 1, "Expected 1, got %d\n", driver_calls.driver.open);
1518     ok(driver_calls.driver.details == 2, "Expected 2, got %d\n", driver_calls.driver.details);
1519 todo_wine
1520     ok(driver_calls.driver.close == 0, "Expected 0, got %d\n", driver_calls.driver.close);
1521 }
1522 
START_TEST(msacm)1523 START_TEST(msacm)
1524 {
1525     driver_tests();
1526     test_prepareheader();
1527     test_convert();
1528     test_acmFormatSuggest();
1529     test_acmFormatTagDetails();
1530     test_acmFormatChoose();
1531     test_mp3();
1532     /* Test acmDriverAdd in the end as it may conflict
1533      * with other tests due to codec lookup order */
1534     test_acmDriverAdd();
1535 }
1536