1c2c66affSColin Finck /*
2c2c66affSColin Finck * Wine Driver for MCI wave forms
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 1994 Martin Ayotte
5c2c66affSColin Finck * 1999,2000,2005 Eric Pouech
6c2c66affSColin Finck * 2000 Francois Jacques
7c2c66affSColin Finck * 2009 Jörg Höhle
8c2c66affSColin Finck *
9c2c66affSColin Finck * This library is free software; you can redistribute it and/or
10c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
11c2c66affSColin Finck * License as published by the Free Software Foundation; either
12c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
13c2c66affSColin Finck *
14c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
15c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
16c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17c2c66affSColin Finck * Lesser General Public License for more details.
18c2c66affSColin Finck *
19c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
20c2c66affSColin Finck * License along with this library; if not, write to the Free Software
21c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22c2c66affSColin Finck */
23c2c66affSColin Finck
24c2c66affSColin Finck #include <assert.h>
25c2c66affSColin Finck #include <stdarg.h>
26c2c66affSColin Finck
27017f6919SAmine Khaldi #include "windef.h"
28017f6919SAmine Khaldi #include "winbase.h"
29017f6919SAmine Khaldi #include "wingdi.h"
30017f6919SAmine Khaldi #include "winuser.h"
31017f6919SAmine Khaldi #include "mmddk.h"
32017f6919SAmine Khaldi #include "wownt32.h"
33017f6919SAmine Khaldi #include "digitalv.h"
34017f6919SAmine Khaldi #include "wine/debug.h"
35c2c66affSColin Finck
36c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(mciwave);
37c2c66affSColin Finck
38c2c66affSColin Finck typedef struct {
39c2c66affSColin Finck UINT wDevID;
40c2c66affSColin Finck HANDLE hWave;
41c2c66affSColin Finck int nUseCount; /* Incremented for each shared open */
42c2c66affSColin Finck HMMIO hFile; /* mmio file handle open as Element */
43c2c66affSColin Finck MCIDEVICEID wNotifyDeviceID; /* MCI device ID with a pending notification */
44c2c66affSColin Finck HANDLE hCallback; /* Callback handle for pending notification */
45c2c66affSColin Finck LPWSTR lpFileName; /* Name of file (if any) */
46c2c66affSColin Finck WAVEFORMATEX wfxRef;
47c2c66affSColin Finck LPWAVEFORMATEX lpWaveFormat; /* Points to wfxRef until set by OPEN or RECORD */
48c2c66affSColin Finck BOOL fInput; /* FALSE = Output, TRUE = Input */
49c2c66affSColin Finck WORD wInput; /* wave input device */
50c2c66affSColin Finck WORD wOutput; /* wave output device */
51c2c66affSColin Finck volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
52c2c66affSColin Finck DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
53c2c66affSColin Finck DWORD dwPosition; /* position in bytes in chunk */
54c2c66affSColin Finck HANDLE hEvent; /* for synchronization */
55c2c66affSColin Finck LONG dwEventCount; /* for synchronization */
56c2c66affSColin Finck MMCKINFO ckMainRIFF; /* main RIFF chunk */
57c2c66affSColin Finck MMCKINFO ckWaveData; /* data chunk */
58c2c66affSColin Finck } WINE_MCIWAVE;
59c2c66affSColin Finck
60c2c66affSColin Finck /* ===================================================================
61c2c66affSColin Finck * ===================================================================
62c2c66affSColin Finck * FIXME: should be using the new mmThreadXXXX functions from WINMM
63c2c66affSColin Finck * instead of those
64c2c66affSColin Finck * it would require to add a wine internal flag to mmThreadCreate
65c2c66affSColin Finck * in order to pass a 32 bit function instead of a 16 bit one
66c2c66affSColin Finck * ===================================================================
67c2c66affSColin Finck * =================================================================== */
68c2c66affSColin Finck
69c2c66affSColin Finck typedef DWORD (*async_cmd)(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE evt);
70c2c66affSColin Finck
71c2c66affSColin Finck struct SCA {
72c2c66affSColin Finck async_cmd cmd;
73c2c66affSColin Finck HANDLE evt;
74c2c66affSColin Finck UINT wDevID;
75c2c66affSColin Finck DWORD_PTR dwParam1;
76c2c66affSColin Finck DWORD_PTR dwParam2;
77c2c66affSColin Finck };
78c2c66affSColin Finck
79c2c66affSColin Finck /**************************************************************************
80c2c66affSColin Finck * MCI_SCAStarter [internal]
81c2c66affSColin Finck */
MCI_SCAStarter(LPVOID arg)82c2c66affSColin Finck static DWORD CALLBACK MCI_SCAStarter(LPVOID arg)
83c2c66affSColin Finck {
84c2c66affSColin Finck struct SCA* sca = (struct SCA*)arg;
85c2c66affSColin Finck DWORD ret;
86c2c66affSColin Finck
87c2c66affSColin Finck TRACE("In thread before async command (%08x,%08lx,%08lx)\n",
88c2c66affSColin Finck sca->wDevID, sca->dwParam1, sca->dwParam2);
89c2c66affSColin Finck ret = sca->cmd(sca->wDevID, sca->dwParam1 | MCI_WAIT, sca->dwParam2, sca->evt);
90c2c66affSColin Finck TRACE("In thread after async command (%08x,%08lx,%08lx)\n",
91c2c66affSColin Finck sca->wDevID, sca->dwParam1, sca->dwParam2);
92c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, sca);
93c2c66affSColin Finck return ret;
94c2c66affSColin Finck }
95c2c66affSColin Finck
96c2c66affSColin Finck /**************************************************************************
97c2c66affSColin Finck * MCI_SendCommandAsync [internal]
98c2c66affSColin Finck */
MCI_SendCommandAsync(UINT wDevID,async_cmd cmd,DWORD_PTR dwParam1,DWORD_PTR dwParam2,UINT size)99c2c66affSColin Finck static DWORD MCI_SendCommandAsync(UINT wDevID, async_cmd cmd, DWORD_PTR dwParam1,
100c2c66affSColin Finck DWORD_PTR dwParam2, UINT size)
101c2c66affSColin Finck {
102c2c66affSColin Finck HANDLE handles[2];
103c2c66affSColin Finck struct SCA* sca = HeapAlloc(GetProcessHeap(), 0, sizeof(struct SCA) + size);
104c2c66affSColin Finck
105c2c66affSColin Finck if (sca == 0)
106c2c66affSColin Finck return MCIERR_OUT_OF_MEMORY;
107c2c66affSColin Finck
108c2c66affSColin Finck sca->wDevID = wDevID;
109c2c66affSColin Finck sca->cmd = cmd;
110c2c66affSColin Finck sca->dwParam1 = dwParam1;
111c2c66affSColin Finck
112c2c66affSColin Finck if (size && dwParam2) {
113c2c66affSColin Finck sca->dwParam2 = (DWORD_PTR)sca + sizeof(struct SCA);
114c2c66affSColin Finck /* copy structure passed by program in dwParam2 to be sure
115c2c66affSColin Finck * we can still use it whatever the program does
116c2c66affSColin Finck */
117c2c66affSColin Finck memcpy((LPVOID)sca->dwParam2, (LPVOID)dwParam2, size);
118c2c66affSColin Finck } else {
119c2c66affSColin Finck sca->dwParam2 = dwParam2;
120c2c66affSColin Finck }
121c2c66affSColin Finck
122c2c66affSColin Finck if ((sca->evt = handles[1] = CreateEventW(NULL, FALSE, FALSE, NULL)) == NULL ||
123c2c66affSColin Finck (handles[0] = CreateThread(NULL, 0, MCI_SCAStarter, sca, 0, NULL)) == 0) {
124c2c66affSColin Finck WARN("Couldn't allocate thread for async command handling, sending synchronously\n");
125c2c66affSColin Finck if (handles[1]) CloseHandle(handles[1]);
126c2c66affSColin Finck sca->evt = NULL;
127c2c66affSColin Finck return MCI_SCAStarter(&sca);
128c2c66affSColin Finck }
129c2c66affSColin Finck
130c2c66affSColin Finck SetThreadPriority(handles[0], THREAD_PRIORITY_TIME_CRITICAL);
131c2c66affSColin Finck /* wait until either:
132c2c66affSColin Finck * - the thread has finished (handles[0], likely an error)
133c2c66affSColin Finck * - init phase of async command is done (handles[1])
134c2c66affSColin Finck */
135c2c66affSColin Finck WaitForMultipleObjects(2, handles, FALSE, INFINITE);
136c2c66affSColin Finck CloseHandle(handles[0]);
137c2c66affSColin Finck CloseHandle(handles[1]);
138c2c66affSColin Finck return 0;
139c2c66affSColin Finck }
140c2c66affSColin Finck
141c2c66affSColin Finck /*======================================================================*
142c2c66affSColin Finck * MCI WAVE implementation *
143c2c66affSColin Finck *======================================================================*/
144c2c66affSColin Finck
145c2c66affSColin Finck static DWORD WAVE_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
146c2c66affSColin Finck
147c2c66affSColin Finck /**************************************************************************
148c2c66affSColin Finck * MCIWAVE_drvOpen [internal]
149c2c66affSColin Finck */
WAVE_drvOpen(LPCWSTR str,LPMCI_OPEN_DRIVER_PARMSW modp)150c2c66affSColin Finck static LRESULT WAVE_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
151c2c66affSColin Finck {
152c2c66affSColin Finck WINE_MCIWAVE* wmw;
153c2c66affSColin Finck
154c2c66affSColin Finck if (modp == NULL) return 0xFFFFFFFF;
155c2c66affSColin Finck
156c2c66affSColin Finck wmw = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCIWAVE));
157c2c66affSColin Finck
158c2c66affSColin Finck if (!wmw)
159c2c66affSColin Finck return 0;
160c2c66affSColin Finck
161c2c66affSColin Finck wmw->wDevID = modp->wDeviceID;
162c2c66affSColin Finck mciSetDriverData(wmw->wDevID, (DWORD_PTR)wmw);
163c2c66affSColin Finck modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
164c2c66affSColin Finck modp->wType = MCI_DEVTYPE_WAVEFORM_AUDIO;
165c2c66affSColin Finck
166c2c66affSColin Finck wmw->wfxRef.wFormatTag = WAVE_FORMAT_PCM;
167c2c66affSColin Finck wmw->wfxRef.nChannels = 1; /* MONO */
168c2c66affSColin Finck wmw->wfxRef.nSamplesPerSec = 11025;
169c2c66affSColin Finck wmw->wfxRef.nAvgBytesPerSec = 11025;
170c2c66affSColin Finck wmw->wfxRef.nBlockAlign = 1;
171c2c66affSColin Finck wmw->wfxRef.wBitsPerSample = 8;
172c2c66affSColin Finck wmw->wfxRef.cbSize = 0; /* don't care */
173c2c66affSColin Finck
174c2c66affSColin Finck return modp->wDeviceID;
175c2c66affSColin Finck }
176c2c66affSColin Finck
177c2c66affSColin Finck /**************************************************************************
178c2c66affSColin Finck * MCIWAVE_drvClose [internal]
179c2c66affSColin Finck */
WAVE_drvClose(MCIDEVICEID dwDevID)180c2c66affSColin Finck static LRESULT WAVE_drvClose(MCIDEVICEID dwDevID)
181c2c66affSColin Finck {
182c2c66affSColin Finck WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(dwDevID);
183c2c66affSColin Finck
184c2c66affSColin Finck if (wmw) {
185c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw);
186c2c66affSColin Finck mciSetDriverData(dwDevID, 0);
187c2c66affSColin Finck return 1;
188c2c66affSColin Finck }
189c2c66affSColin Finck return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
190c2c66affSColin Finck }
191c2c66affSColin Finck
192c2c66affSColin Finck /**************************************************************************
193c2c66affSColin Finck * WAVE_mciGetOpenDev [internal]
194c2c66affSColin Finck */
WAVE_mciGetOpenDev(MCIDEVICEID wDevID)195c2c66affSColin Finck static WINE_MCIWAVE *WAVE_mciGetOpenDev(MCIDEVICEID wDevID)
196c2c66affSColin Finck {
197c2c66affSColin Finck WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
198c2c66affSColin Finck
199c2c66affSColin Finck if (wmw == NULL || wmw->nUseCount == 0) {
200c2c66affSColin Finck WARN("Invalid wDevID=%u\n", wDevID);
201c2c66affSColin Finck return 0;
202c2c66affSColin Finck }
203c2c66affSColin Finck return wmw;
204c2c66affSColin Finck }
205c2c66affSColin Finck
206c2c66affSColin Finck /**************************************************************************
207c2c66affSColin Finck * WAVE_mciNotify [internal]
208c2c66affSColin Finck *
209c2c66affSColin Finck * Notifications in MCI work like a 1-element queue.
210c2c66affSColin Finck * Each new notification request supersedes the previous one.
211c2c66affSColin Finck * This affects Play and Record; other commands are immediate.
212c2c66affSColin Finck */
WAVE_mciNotify(DWORD_PTR hWndCallBack,WINE_MCIWAVE * wmw,UINT wStatus)213c2c66affSColin Finck static void WAVE_mciNotify(DWORD_PTR hWndCallBack, WINE_MCIWAVE* wmw, UINT wStatus)
214c2c66affSColin Finck {
215c2c66affSColin Finck /* We simply save one parameter by not passing the wDevID local
216c2c66affSColin Finck * to the command. They are the same (via mciGetDriverData).
217c2c66affSColin Finck */
218c2c66affSColin Finck MCIDEVICEID wDevID = wmw->wNotifyDeviceID;
219c2c66affSColin Finck HANDLE old = InterlockedExchangePointer(&wmw->hCallback, NULL);
220c2c66affSColin Finck if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
221c2c66affSColin Finck mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
222c2c66affSColin Finck }
223c2c66affSColin Finck
224c2c66affSColin Finck /**************************************************************************
225c2c66affSColin Finck * WAVE_ConvertByteToTimeFormat [internal]
226c2c66affSColin Finck */
WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE * wmw,DWORD val)227c2c66affSColin Finck static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val)
228c2c66affSColin Finck {
229c2c66affSColin Finck DWORD ret = 0;
230c2c66affSColin Finck
231c2c66affSColin Finck switch (wmw->dwMciTimeFormat) {
232c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
233c2c66affSColin Finck ret = MulDiv(val,1000,wmw->lpWaveFormat->nAvgBytesPerSec);
234c2c66affSColin Finck break;
235c2c66affSColin Finck case MCI_FORMAT_BYTES:
236c2c66affSColin Finck ret = val;
237c2c66affSColin Finck break;
238c2c66affSColin Finck case MCI_FORMAT_SAMPLES:
239c2c66affSColin Finck ret = MulDiv(val,wmw->lpWaveFormat->nSamplesPerSec,wmw->lpWaveFormat->nAvgBytesPerSec);
240c2c66affSColin Finck break;
241c2c66affSColin Finck default:
242c2c66affSColin Finck WARN("Bad time format %u!\n", wmw->dwMciTimeFormat);
243c2c66affSColin Finck }
244c2c66affSColin Finck TRACE("val=%u=0x%08x [tf=%u] => ret=%u\n", val, val, wmw->dwMciTimeFormat, ret);
245c2c66affSColin Finck return ret;
246c2c66affSColin Finck }
247c2c66affSColin Finck
248c2c66affSColin Finck /**************************************************************************
249c2c66affSColin Finck * WAVE_ConvertTimeFormatToByte [internal]
250c2c66affSColin Finck */
WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE * wmw,DWORD val)251c2c66affSColin Finck static DWORD WAVE_ConvertTimeFormatToByte(WINE_MCIWAVE* wmw, DWORD val)
252c2c66affSColin Finck {
253c2c66affSColin Finck DWORD ret = 0;
254c2c66affSColin Finck
255c2c66affSColin Finck switch (wmw->dwMciTimeFormat) {
256c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
257c2c66affSColin Finck ret = MulDiv(val,wmw->lpWaveFormat->nAvgBytesPerSec,1000);
258c2c66affSColin Finck if (ret > wmw->ckWaveData.cksize &&
259c2c66affSColin Finck val == WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize))
260c2c66affSColin Finck ret = wmw->ckWaveData.cksize;
261c2c66affSColin Finck break;
262c2c66affSColin Finck case MCI_FORMAT_BYTES:
263c2c66affSColin Finck ret = val;
264c2c66affSColin Finck break;
265c2c66affSColin Finck case MCI_FORMAT_SAMPLES:
266c2c66affSColin Finck ret = MulDiv(val,wmw->lpWaveFormat->nAvgBytesPerSec,wmw->lpWaveFormat->nSamplesPerSec);
267c2c66affSColin Finck break;
268c2c66affSColin Finck default:
269c2c66affSColin Finck WARN("Bad time format %u!\n", wmw->dwMciTimeFormat);
270c2c66affSColin Finck }
271c2c66affSColin Finck TRACE("val=%u=0x%08x [tf=%u] => ret=%u\n", val, val, wmw->dwMciTimeFormat, ret);
272c2c66affSColin Finck return ret;
273c2c66affSColin Finck }
274c2c66affSColin Finck
275c2c66affSColin Finck /**************************************************************************
276c2c66affSColin Finck * WAVE_mciReadFmt [internal]
277c2c66affSColin Finck */
WAVE_mciReadFmt(WINE_MCIWAVE * wmw,const MMCKINFO * pckMainRIFF)278c2c66affSColin Finck static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, const MMCKINFO* pckMainRIFF)
279c2c66affSColin Finck {
280c2c66affSColin Finck MMCKINFO mmckInfo;
281c2c66affSColin Finck LONG r;
282c2c66affSColin Finck LPWAVEFORMATEX pwfx;
283c2c66affSColin Finck
284c2c66affSColin Finck mmckInfo.ckid = mmioFOURCC('f', 'm', 't', ' ');
285c2c66affSColin Finck if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0)
286c2c66affSColin Finck return MCIERR_INVALID_FILE;
287c2c66affSColin Finck TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08X\n",
288c2c66affSColin Finck (LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
289c2c66affSColin Finck
290c2c66affSColin Finck pwfx = HeapAlloc(GetProcessHeap(), 0, mmckInfo.cksize);
291c2c66affSColin Finck if (!pwfx) return MCIERR_OUT_OF_MEMORY;
292c2c66affSColin Finck
293c2c66affSColin Finck r = mmioRead(wmw->hFile, (HPSTR)pwfx, mmckInfo.cksize);
294c2c66affSColin Finck if (r < sizeof(PCMWAVEFORMAT)) {
295c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pwfx);
296c2c66affSColin Finck return MCIERR_INVALID_FILE;
297c2c66affSColin Finck }
298c2c66affSColin Finck TRACE("wFormatTag=%04X !\n", pwfx->wFormatTag);
299c2c66affSColin Finck TRACE("nChannels=%d\n", pwfx->nChannels);
300c2c66affSColin Finck TRACE("nSamplesPerSec=%d\n", pwfx->nSamplesPerSec);
301c2c66affSColin Finck TRACE("nAvgBytesPerSec=%d\n", pwfx->nAvgBytesPerSec);
302c2c66affSColin Finck TRACE("nBlockAlign=%d\n", pwfx->nBlockAlign);
303c2c66affSColin Finck TRACE("wBitsPerSample=%u !\n", pwfx->wBitsPerSample);
304c2c66affSColin Finck if (r >= sizeof(WAVEFORMATEX))
305c2c66affSColin Finck TRACE("cbSize=%u !\n", pwfx->cbSize);
306c2c66affSColin Finck if ((pwfx->wFormatTag != WAVE_FORMAT_PCM)
307c2c66affSColin Finck && (r < sizeof(WAVEFORMATEX) || (r < sizeof(WAVEFORMATEX) + pwfx->cbSize))) {
308c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, pwfx);
309c2c66affSColin Finck return MCIERR_INVALID_FILE;
310c2c66affSColin Finck }
311c2c66affSColin Finck wmw->lpWaveFormat = pwfx;
312c2c66affSColin Finck
313c2c66affSColin Finck mmioAscend(wmw->hFile, &mmckInfo, 0);
314c2c66affSColin Finck wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
315c2c66affSColin Finck if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
316c2c66affSColin Finck TRACE("can't find data chunk\n");
317c2c66affSColin Finck return MCIERR_INVALID_FILE;
318c2c66affSColin Finck }
319c2c66affSColin Finck TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08X\n",
320c2c66affSColin Finck (LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
321c2c66affSColin Finck return 0;
322c2c66affSColin Finck }
323c2c66affSColin Finck
324c2c66affSColin Finck /**************************************************************************
325c2c66affSColin Finck * WAVE_mciDefaultFmt [internal]
326c2c66affSColin Finck *
327c2c66affSColin Finck * wmw->lpWaveFormat points to the default wave format at wmw->wfxRef
328c2c66affSColin Finck * until either Open File or Record. It becomes immutable afterwards,
329c2c66affSColin Finck * i.e. Set wave format or channels etc. is subsequently refused.
330c2c66affSColin Finck */
WAVE_mciDefaultFmt(WINE_MCIWAVE * wmw)331c2c66affSColin Finck static void WAVE_mciDefaultFmt(WINE_MCIWAVE* wmw)
332c2c66affSColin Finck {
333c2c66affSColin Finck wmw->lpWaveFormat = &wmw->wfxRef;
334c2c66affSColin Finck wmw->lpWaveFormat->wFormatTag = WAVE_FORMAT_PCM;
335c2c66affSColin Finck wmw->lpWaveFormat->nChannels = 1;
336c2c66affSColin Finck wmw->lpWaveFormat->nSamplesPerSec = 11025;
337c2c66affSColin Finck wmw->lpWaveFormat->nAvgBytesPerSec = 11025;
338c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign = 1;
339c2c66affSColin Finck wmw->lpWaveFormat->wBitsPerSample = 8;
340c2c66affSColin Finck wmw->lpWaveFormat->cbSize = 0;
341c2c66affSColin Finck }
342c2c66affSColin Finck
343c2c66affSColin Finck /**************************************************************************
344c2c66affSColin Finck * WAVE_mciCreateRIFFSkeleton [internal]
345c2c66affSColin Finck */
WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE * wmw)346c2c66affSColin Finck static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
347c2c66affSColin Finck {
348c2c66affSColin Finck MMCKINFO ckWaveFormat;
349c2c66affSColin Finck LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF);
350c2c66affSColin Finck LPMMCKINFO lpckWaveData = &(wmw->ckWaveData);
351c2c66affSColin Finck
352c2c66affSColin Finck lpckRIFF->ckid = FOURCC_RIFF;
353c2c66affSColin Finck lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
354c2c66affSColin Finck lpckRIFF->cksize = 0;
355c2c66affSColin Finck
356c2c66affSColin Finck if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckRIFF, MMIO_CREATERIFF))
357c2c66affSColin Finck goto err;
358c2c66affSColin Finck
359c2c66affSColin Finck ckWaveFormat.fccType = 0;
360c2c66affSColin Finck ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' ');
361c2c66affSColin Finck ckWaveFormat.cksize = sizeof(PCMWAVEFORMAT);
362c2c66affSColin Finck
363c2c66affSColin Finck /* Set wave format accepts PCM only, however open an
364c2c66affSColin Finck * existing ADPCM file, record into it and the MCI will
365c2c66affSColin Finck * happily save back in that format. */
366c2c66affSColin Finck if (wmw->lpWaveFormat->wFormatTag == WAVE_FORMAT_PCM) {
367c2c66affSColin Finck if (wmw->lpWaveFormat->nBlockAlign !=
368c2c66affSColin Finck wmw->lpWaveFormat->nChannels * wmw->lpWaveFormat->wBitsPerSample/8) {
369c2c66affSColin Finck WORD size = wmw->lpWaveFormat->nChannels *
370c2c66affSColin Finck wmw->lpWaveFormat->wBitsPerSample/8;
371c2c66affSColin Finck WARN("Incorrect nBlockAlign (%d), setting it to %d\n",
372c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign, size);
373c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign = size;
374c2c66affSColin Finck }
375c2c66affSColin Finck if (wmw->lpWaveFormat->nAvgBytesPerSec !=
376c2c66affSColin Finck wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
377c2c66affSColin Finck DWORD speed = wmw->lpWaveFormat->nSamplesPerSec *
378c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign;
379c2c66affSColin Finck WARN("Incorrect nAvgBytesPerSec (%d), setting it to %d\n",
380c2c66affSColin Finck wmw->lpWaveFormat->nAvgBytesPerSec, speed);
381c2c66affSColin Finck wmw->lpWaveFormat->nAvgBytesPerSec = speed;
382c2c66affSColin Finck }
383c2c66affSColin Finck }
384c2c66affSColin Finck if (wmw->lpWaveFormat == &wmw->wfxRef) {
385c2c66affSColin Finck LPWAVEFORMATEX pwfx = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WAVEFORMATEX));
386c2c66affSColin Finck if (!pwfx) return MCIERR_OUT_OF_MEMORY;
387c2c66affSColin Finck /* Set wave format accepts PCM only so the size is known. */
388c2c66affSColin Finck assert(wmw->wfxRef.wFormatTag == WAVE_FORMAT_PCM);
389c2c66affSColin Finck *pwfx = wmw->wfxRef;
390c2c66affSColin Finck wmw->lpWaveFormat = pwfx;
391c2c66affSColin Finck }
392c2c66affSColin Finck
393c2c66affSColin Finck if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, &ckWaveFormat, 0))
394c2c66affSColin Finck goto err;
395c2c66affSColin Finck
396c2c66affSColin Finck if (-1 == mmioWrite(wmw->hFile, (HPCSTR)wmw->lpWaveFormat, (WAVE_FORMAT_PCM==wmw->lpWaveFormat->wFormatTag)
397c2c66affSColin Finck ? sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX)+wmw->lpWaveFormat->cbSize))
398c2c66affSColin Finck goto err;
399c2c66affSColin Finck
400c2c66affSColin Finck if (MMSYSERR_NOERROR != mmioAscend(wmw->hFile, &ckWaveFormat, 0))
401c2c66affSColin Finck goto err;
402c2c66affSColin Finck
403c2c66affSColin Finck lpckWaveData->cksize = 0;
404c2c66affSColin Finck lpckWaveData->fccType = 0;
405c2c66affSColin Finck lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a');
406c2c66affSColin Finck
407c2c66affSColin Finck /* create data chunk */
408c2c66affSColin Finck if (MMSYSERR_NOERROR != mmioCreateChunk(wmw->hFile, lpckWaveData, 0))
409c2c66affSColin Finck goto err;
410c2c66affSColin Finck
411c2c66affSColin Finck return 0;
412c2c66affSColin Finck
413c2c66affSColin Finck err:
414c2c66affSColin Finck /* mciClose takes care of wmw->lpWaveFormat. */
415c2c66affSColin Finck return MCIERR_INVALID_FILE;
416c2c66affSColin Finck }
417c2c66affSColin Finck
create_tmp_file(HMMIO * hFile,LPWSTR * pszTmpFileName)418c2c66affSColin Finck static DWORD create_tmp_file(HMMIO* hFile, LPWSTR* pszTmpFileName)
419c2c66affSColin Finck {
420c2c66affSColin Finck WCHAR szTmpPath[MAX_PATH];
421c2c66affSColin Finck WCHAR szPrefix[4];
422c2c66affSColin Finck DWORD dwRet = MMSYSERR_NOERROR;
423c2c66affSColin Finck
424c2c66affSColin Finck szPrefix[0] = 'M';
425c2c66affSColin Finck szPrefix[1] = 'C';
426c2c66affSColin Finck szPrefix[2] = 'I';
427c2c66affSColin Finck szPrefix[3] = '\0';
428c2c66affSColin Finck
429bca17f6bSAmine Khaldi if (!GetTempPathW(ARRAY_SIZE(szTmpPath), szTmpPath)) {
430c2c66affSColin Finck WARN("can't retrieve temp path!\n");
431c2c66affSColin Finck *pszTmpFileName = NULL;
432c2c66affSColin Finck return MCIERR_FILE_NOT_FOUND;
433c2c66affSColin Finck }
434c2c66affSColin Finck
435c2c66affSColin Finck *pszTmpFileName = HeapAlloc(GetProcessHeap(),
436c2c66affSColin Finck HEAP_ZERO_MEMORY,
437c2c66affSColin Finck MAX_PATH * sizeof(WCHAR));
438c2c66affSColin Finck if (!GetTempFileNameW(szTmpPath, szPrefix, 0, *pszTmpFileName)) {
439c2c66affSColin Finck WARN("can't retrieve temp file name!\n");
440c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, *pszTmpFileName);
441c2c66affSColin Finck return MCIERR_FILE_NOT_FOUND;
442c2c66affSColin Finck }
443c2c66affSColin Finck
444c2c66affSColin Finck TRACE("%s!\n", debugstr_w(*pszTmpFileName));
445c2c66affSColin Finck
446c2c66affSColin Finck if (*pszTmpFileName && (*pszTmpFileName)[0]) {
447c2c66affSColin Finck
448c2c66affSColin Finck *hFile = mmioOpenW(*pszTmpFileName, NULL,
449c2c66affSColin Finck MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
450c2c66affSColin Finck
451c2c66affSColin Finck if (*hFile == 0) {
452c2c66affSColin Finck WARN("can't create file=%s!\n", debugstr_w(*pszTmpFileName));
453c2c66affSColin Finck /* temporary file could not be created. clean filename. */
454c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, *pszTmpFileName);
455c2c66affSColin Finck dwRet = MCIERR_FILE_NOT_FOUND;
456c2c66affSColin Finck }
457c2c66affSColin Finck }
458c2c66affSColin Finck return dwRet;
459c2c66affSColin Finck }
460c2c66affSColin Finck
WAVE_mciOpenFile(WINE_MCIWAVE * wmw,LPCWSTR filename)461c2c66affSColin Finck static LRESULT WAVE_mciOpenFile(WINE_MCIWAVE* wmw, LPCWSTR filename)
462c2c66affSColin Finck {
463c2c66affSColin Finck LRESULT dwRet = MMSYSERR_NOERROR;
464c2c66affSColin Finck LPWSTR fn;
465c2c66affSColin Finck
466c2c66affSColin Finck fn = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(filename) + 1) * sizeof(WCHAR));
467c2c66affSColin Finck if (!fn) return MCIERR_OUT_OF_MEMORY;
468*3aa689feSAmine Khaldi lstrcpyW(fn, filename);
469c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw->lpFileName);
470c2c66affSColin Finck wmw->lpFileName = fn;
471c2c66affSColin Finck
472c2c66affSColin Finck if (filename[0]) {
473c2c66affSColin Finck /* FIXME : what should be done if wmw->hFile is already != 0, or the driver is playin' */
474c2c66affSColin Finck TRACE("MCI_OPEN_ELEMENT %s!\n", debugstr_w(filename));
475c2c66affSColin Finck
476c2c66affSColin Finck wmw->hFile = mmioOpenW((LPWSTR)filename, NULL,
477c2c66affSColin Finck MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READ);
478c2c66affSColin Finck
479c2c66affSColin Finck if (wmw->hFile == 0) {
480c2c66affSColin Finck WARN("can't find file=%s!\n", debugstr_w(filename));
481c2c66affSColin Finck dwRet = MCIERR_FILE_NOT_FOUND;
482c2c66affSColin Finck }
483c2c66affSColin Finck else
484c2c66affSColin Finck {
485c2c66affSColin Finck LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF;
486c2c66affSColin Finck
487c2c66affSColin Finck /* make sure we're at the beginning of the file */
488c2c66affSColin Finck mmioSeek(wmw->hFile, 0, SEEK_SET);
489c2c66affSColin Finck
490c2c66affSColin Finck /* first reading of this file. read the waveformat chunk */
491c2c66affSColin Finck if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
492c2c66affSColin Finck dwRet = MCIERR_INVALID_FILE;
493c2c66affSColin Finck } else {
494c2c66affSColin Finck TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08X\n",
495c2c66affSColin Finck (LPSTR)&(lpckMainRIFF->ckid),
496c2c66affSColin Finck (LPSTR) &(lpckMainRIFF->fccType),
497c2c66affSColin Finck (lpckMainRIFF->cksize));
498c2c66affSColin Finck
499c2c66affSColin Finck if ((lpckMainRIFF->ckid != FOURCC_RIFF) ||
500c2c66affSColin Finck lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
501c2c66affSColin Finck dwRet = MCIERR_INVALID_FILE;
502c2c66affSColin Finck } else {
503c2c66affSColin Finck dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
504c2c66affSColin Finck }
505c2c66affSColin Finck }
506c2c66affSColin Finck }
507c2c66affSColin Finck }
508c2c66affSColin Finck return dwRet;
509c2c66affSColin Finck }
510c2c66affSColin Finck
511c2c66affSColin Finck /**************************************************************************
512c2c66affSColin Finck * WAVE_mciOpen [internal]
513c2c66affSColin Finck */
WAVE_mciOpen(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_WAVE_OPEN_PARMSW lpOpenParms)514c2c66affSColin Finck static LRESULT WAVE_mciOpen(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSW lpOpenParms)
515c2c66affSColin Finck {
516c2c66affSColin Finck DWORD dwRet = 0;
517c2c66affSColin Finck WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
518c2c66affSColin Finck
519c2c66affSColin Finck TRACE("(%04X, %08X, %p)\n", wDevID, dwFlags, lpOpenParms);
520c2c66affSColin Finck if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
521c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
522c2c66affSColin Finck
523c2c66affSColin Finck if (dwFlags & MCI_OPEN_SHAREABLE)
524c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
525c2c66affSColin Finck
526c2c66affSColin Finck if (wmw->nUseCount > 0) {
527c2c66affSColin Finck /* The driver is already opened on this channel
528c2c66affSColin Finck * Wave driver cannot be shared
529c2c66affSColin Finck */
530c2c66affSColin Finck return MCIERR_DEVICE_OPEN;
531c2c66affSColin Finck }
532c2c66affSColin Finck
533c2c66affSColin Finck wmw->nUseCount++;
534c2c66affSColin Finck
535c2c66affSColin Finck wmw->wInput = wmw->wOutput = WAVE_MAPPER;
536c2c66affSColin Finck wmw->fInput = FALSE;
537c2c66affSColin Finck wmw->hWave = 0;
538c2c66affSColin Finck wmw->dwStatus = MCI_MODE_NOT_READY;
539c2c66affSColin Finck wmw->hFile = 0;
540c2c66affSColin Finck wmw->lpFileName = NULL; /* will be set by WAVE_mciOpenFile */
541c2c66affSColin Finck wmw->hCallback = NULL;
542c2c66affSColin Finck WAVE_mciDefaultFmt(wmw);
543c2c66affSColin Finck
544c2c66affSColin Finck TRACE("wDevID=%04X (lpParams->wDeviceID=%08X)\n", wDevID, lpOpenParms->wDeviceID);
545c2c66affSColin Finck /* Logs show the native winmm calls us with 0 still in lpOpenParms.wDeviceID */
546c2c66affSColin Finck wmw->wNotifyDeviceID = wDevID;
547c2c66affSColin Finck
548c2c66affSColin Finck if (dwFlags & MCI_OPEN_ELEMENT) {
549c2c66affSColin Finck if (dwFlags & MCI_OPEN_ELEMENT_ID) {
550c2c66affSColin Finck /* could it be that (DWORD)lpOpenParms->lpstrElementName
551c2c66affSColin Finck * contains the hFile value ?
552c2c66affSColin Finck */
553c2c66affSColin Finck dwRet = MCIERR_UNRECOGNIZED_COMMAND;
554c2c66affSColin Finck } else {
555c2c66affSColin Finck dwRet = WAVE_mciOpenFile(wmw, lpOpenParms->lpstrElementName);
556c2c66affSColin Finck }
557c2c66affSColin Finck }
558c2c66affSColin Finck TRACE("hFile=%p\n", wmw->hFile);
559c2c66affSColin Finck
560c2c66affSColin Finck if (dwRet == 0) {
561c2c66affSColin Finck wmw->dwPosition = 0;
562c2c66affSColin Finck
563c2c66affSColin Finck wmw->dwStatus = MCI_MODE_STOP;
564c2c66affSColin Finck
565c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
566c2c66affSColin Finck WAVE_mciNotify(lpOpenParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
567c2c66affSColin Finck } else {
568c2c66affSColin Finck wmw->nUseCount--;
569c2c66affSColin Finck if (wmw->hFile != 0)
570c2c66affSColin Finck mmioClose(wmw->hFile, 0);
571c2c66affSColin Finck wmw->hFile = 0;
572c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw->lpFileName);
573c2c66affSColin Finck wmw->lpFileName = NULL;
574c2c66affSColin Finck }
575c2c66affSColin Finck return dwRet;
576c2c66affSColin Finck }
577c2c66affSColin Finck
578c2c66affSColin Finck /**************************************************************************
579c2c66affSColin Finck * WAVE_mciCue [internal]
580c2c66affSColin Finck */
WAVE_mciCue(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)581c2c66affSColin Finck static DWORD WAVE_mciCue(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
582c2c66affSColin Finck {
583c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
584c2c66affSColin Finck
585c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
586c2c66affSColin Finck
587c2c66affSColin Finck /* Tests on systems without sound drivers show that Cue, like
588c2c66affSColin Finck * Record and Play, opens winmm, returning MCIERR_WAVE_xyPUTSUNSUITABLE.
589c2c66affSColin Finck * The first Cue Notify does not immediately return the
590c2c66affSColin Finck * notification, as if a player or recorder thread is started.
591c2c66affSColin Finck * PAUSE mode is reported when successful, but this mode is
592c2c66affSColin Finck * different from the normal Pause, because a) Pause then returns
593c2c66affSColin Finck * NONAPPLICABLE_FUNCTION instead of 0 and b) Set Channels etc. is
594c2c66affSColin Finck * still accepted, returning the original notification as ABORTED.
595c2c66affSColin Finck * I.e. Cue allows subsequent format changes, unlike Record or
596c2c66affSColin Finck * Open file, closes winmm if the format changes and stops this
597c2c66affSColin Finck * thread.
598c2c66affSColin Finck * Wine creates one player or recorder thread per async. Play or
599c2c66affSColin Finck * Record command. Notification behaviour suggests that MS-W*
600c2c66affSColin Finck * reuses a single thread to improve response times. Having Cue
601c2c66affSColin Finck * start this thread early helps to improve Play/Record's initial
602c2c66affSColin Finck * response time. In effect, Cue is a performance hint, which
603c2c66affSColin Finck * justifies our almost no-op implementation.
604c2c66affSColin Finck */
605c2c66affSColin Finck
606c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
607c2c66affSColin Finck if (wmw->dwStatus != MCI_MODE_STOP) return MCIERR_NONAPPLICABLE_FUNCTION;
608c2c66affSColin Finck
609c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms)
610c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback,wmw,MCI_NOTIFY_SUCCESSFUL);
611c2c66affSColin Finck
612c2c66affSColin Finck return MMSYSERR_NOERROR;
613c2c66affSColin Finck }
614c2c66affSColin Finck
615c2c66affSColin Finck /**************************************************************************
616c2c66affSColin Finck * WAVE_mciStop [internal]
617c2c66affSColin Finck */
WAVE_mciStop(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)618c2c66affSColin Finck static DWORD WAVE_mciStop(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
619c2c66affSColin Finck {
620c2c66affSColin Finck DWORD dwRet = 0;
621c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
622c2c66affSColin Finck
623c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
624c2c66affSColin Finck
625c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
626c2c66affSColin Finck
627c2c66affSColin Finck if (wmw->dwStatus != MCI_MODE_STOP) {
628c2c66affSColin Finck HANDLE old = InterlockedExchangePointer(&wmw->hCallback, NULL);
629c2c66affSColin Finck if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_ABORTED);
630c2c66affSColin Finck }
631c2c66affSColin Finck
632c2c66affSColin Finck /* wait for playback thread (if any) to exit before processing further */
633c2c66affSColin Finck switch (wmw->dwStatus) {
634c2c66affSColin Finck case MCI_MODE_PAUSE:
635c2c66affSColin Finck case MCI_MODE_PLAY:
636c2c66affSColin Finck case MCI_MODE_RECORD:
637c2c66affSColin Finck {
638c2c66affSColin Finck int oldStat = wmw->dwStatus;
639c2c66affSColin Finck wmw->dwStatus = MCI_MODE_NOT_READY;
640c2c66affSColin Finck if (oldStat == MCI_MODE_PAUSE)
641c2c66affSColin Finck dwRet = (wmw->fInput) ? waveInReset(wmw->hWave) : waveOutReset(wmw->hWave);
642c2c66affSColin Finck }
643c2c66affSColin Finck while (wmw->dwStatus != MCI_MODE_STOP)
644c2c66affSColin Finck Sleep(10);
645c2c66affSColin Finck break;
646c2c66affSColin Finck }
647c2c66affSColin Finck
648c2c66affSColin Finck /* sanity resets */
649c2c66affSColin Finck wmw->dwStatus = MCI_MODE_STOP;
650c2c66affSColin Finck
651c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms && MMSYSERR_NOERROR==dwRet)
652c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
653c2c66affSColin Finck
654c2c66affSColin Finck return dwRet;
655c2c66affSColin Finck }
656c2c66affSColin Finck
657c2c66affSColin Finck /**************************************************************************
658c2c66affSColin Finck * WAVE_mciClose [internal]
659c2c66affSColin Finck */
WAVE_mciClose(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)660c2c66affSColin Finck static DWORD WAVE_mciClose(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
661c2c66affSColin Finck {
662c2c66affSColin Finck DWORD dwRet = 0;
663c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
664c2c66affSColin Finck
665c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
666c2c66affSColin Finck
667c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
668c2c66affSColin Finck
669c2c66affSColin Finck if (wmw->dwStatus != MCI_MODE_STOP) {
670c2c66affSColin Finck /* mciStop handles MCI_NOTIFY_ABORTED */
671c2c66affSColin Finck dwRet = WAVE_mciStop(wDevID, MCI_WAIT, lpParms);
672c2c66affSColin Finck }
673c2c66affSColin Finck
674c2c66affSColin Finck wmw->nUseCount--;
675c2c66affSColin Finck
676c2c66affSColin Finck if (wmw->nUseCount == 0) {
677c2c66affSColin Finck if (wmw->hFile != 0) {
678c2c66affSColin Finck mmioClose(wmw->hFile, 0);
679c2c66affSColin Finck wmw->hFile = 0;
680c2c66affSColin Finck }
681c2c66affSColin Finck }
682c2c66affSColin Finck
683c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef)
684c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
685c2c66affSColin Finck wmw->lpWaveFormat = &wmw->wfxRef;
686c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw->lpFileName);
687c2c66affSColin Finck wmw->lpFileName = NULL;
688c2c66affSColin Finck
689c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms) {
690c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw,
691c2c66affSColin Finck (dwRet == 0) ? MCI_NOTIFY_SUCCESSFUL : MCI_NOTIFY_FAILURE);
692c2c66affSColin Finck }
693c2c66affSColin Finck
694c2c66affSColin Finck return 0;
695c2c66affSColin Finck }
696c2c66affSColin Finck
697c2c66affSColin Finck /**************************************************************************
698c2c66affSColin Finck * WAVE_mciPlayCallback [internal]
699c2c66affSColin Finck */
WAVE_mciPlayCallback(HWAVEOUT hwo,UINT uMsg,DWORD_PTR dwInstance,LPARAM dwParam1,LPARAM dwParam2)700c2c66affSColin Finck static void CALLBACK WAVE_mciPlayCallback(HWAVEOUT hwo, UINT uMsg,
701c2c66affSColin Finck DWORD_PTR dwInstance,
702c2c66affSColin Finck LPARAM dwParam1, LPARAM dwParam2)
703c2c66affSColin Finck {
704c2c66affSColin Finck WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
705c2c66affSColin Finck
706c2c66affSColin Finck switch (uMsg) {
707c2c66affSColin Finck case WOM_OPEN:
708c2c66affSColin Finck case WOM_CLOSE:
709c2c66affSColin Finck break;
710c2c66affSColin Finck case WOM_DONE:
711c2c66affSColin Finck InterlockedIncrement(&wmw->dwEventCount);
712c2c66affSColin Finck TRACE("Returning waveHdr=%lx\n", dwParam1);
713c2c66affSColin Finck SetEvent(wmw->hEvent);
714c2c66affSColin Finck break;
715c2c66affSColin Finck default:
716c2c66affSColin Finck ERR("Unknown uMsg=%d\n", uMsg);
717c2c66affSColin Finck }
718c2c66affSColin Finck }
719c2c66affSColin Finck
720c2c66affSColin Finck /******************************************************************
721c2c66affSColin Finck * WAVE_mciPlayWaitDone [internal]
722c2c66affSColin Finck */
WAVE_mciPlayWaitDone(WINE_MCIWAVE * wmw)723c2c66affSColin Finck static void WAVE_mciPlayWaitDone(WINE_MCIWAVE* wmw)
724c2c66affSColin Finck {
725c2c66affSColin Finck for (;;) {
726c2c66affSColin Finck ResetEvent(wmw->hEvent);
727c2c66affSColin Finck if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
728c2c66affSColin Finck break;
729c2c66affSColin Finck }
730c2c66affSColin Finck InterlockedIncrement(&wmw->dwEventCount);
731c2c66affSColin Finck
732c2c66affSColin Finck WaitForSingleObject(wmw->hEvent, INFINITE);
733c2c66affSColin Finck }
734c2c66affSColin Finck }
735c2c66affSColin Finck
736c2c66affSColin Finck /**************************************************************************
737c2c66affSColin Finck * WAVE_mciPlay [internal]
738c2c66affSColin Finck */
WAVE_mciPlay(MCIDEVICEID wDevID,DWORD_PTR dwFlags,DWORD_PTR pmt,HANDLE hEvent)739c2c66affSColin Finck static DWORD WAVE_mciPlay(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
740c2c66affSColin Finck {
741c2c66affSColin Finck LPMCI_PLAY_PARMS lpParms = (void*)pmt;
742c2c66affSColin Finck DWORD end;
743c2c66affSColin Finck LONG bufsize, count, left;
744c2c66affSColin Finck DWORD dwRet;
745c2c66affSColin Finck LPWAVEHDR waveHdr = NULL;
746c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
747c2c66affSColin Finck HANDLE oldcb;
748c2c66affSColin Finck int whidx;
749c2c66affSColin Finck
750c2c66affSColin Finck TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
751c2c66affSColin Finck
752c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
753c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
754c2c66affSColin Finck
755c2c66affSColin Finck if (wmw->hFile == 0) {
756c2c66affSColin Finck WARN("Can't play: no file=%s!\n", debugstr_w(wmw->lpFileName));
757c2c66affSColin Finck return MCIERR_FILE_NOT_FOUND;
758c2c66affSColin Finck }
759c2c66affSColin Finck
760c2c66affSColin Finck if (wmw->dwStatus == MCI_MODE_PAUSE && !wmw->fInput && !(dwFlags & (MCI_FROM | MCI_TO))) {
761c2c66affSColin Finck /* FIXME: notification is different with Resume than Play */
762c2c66affSColin Finck return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
763c2c66affSColin Finck }
764c2c66affSColin Finck
765c2c66affSColin Finck /** This function will be called again by a thread when async is used.
766c2c66affSColin Finck * We have to set MCI_MODE_PLAY before we do this so that the app can spin
767c2c66affSColin Finck * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
768c2c66affSColin Finck */
769c2c66affSColin Finck if ( !(wmw->dwStatus == MCI_MODE_STOP) &&
770c2c66affSColin Finck !((wmw->dwStatus == MCI_MODE_PLAY) && (dwFlags & MCI_WAIT) && !wmw->hWave)) {
771c2c66affSColin Finck /* FIXME: Check FROM/TO parameters first. */
772c2c66affSColin Finck /* FIXME: Play; Play [notify|wait] must hook into the running player. */
773c2c66affSColin Finck dwRet = WAVE_mciStop(wDevID, MCI_WAIT, NULL);
774c2c66affSColin Finck if (dwRet) return dwRet;
775c2c66affSColin Finck }
776c2c66affSColin Finck
777c2c66affSColin Finck if (wmw->lpWaveFormat->wFormatTag == WAVE_FORMAT_PCM) {
778c2c66affSColin Finck if (wmw->lpWaveFormat->nBlockAlign !=
779c2c66affSColin Finck wmw->lpWaveFormat->nChannels * wmw->lpWaveFormat->wBitsPerSample/8) {
780c2c66affSColin Finck WARN("Incorrect nBlockAlign (%d), setting it to %d\n",
781c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign,
782c2c66affSColin Finck wmw->lpWaveFormat->nChannels *
783c2c66affSColin Finck wmw->lpWaveFormat->wBitsPerSample/8);
784c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign =
785c2c66affSColin Finck wmw->lpWaveFormat->nChannels *
786c2c66affSColin Finck wmw->lpWaveFormat->wBitsPerSample/8;
787c2c66affSColin Finck }
788c2c66affSColin Finck if (wmw->lpWaveFormat->nAvgBytesPerSec !=
789c2c66affSColin Finck wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
790c2c66affSColin Finck WARN("Incorrect nAvgBytesPerSec (%d), setting it to %d\n",
791c2c66affSColin Finck wmw->lpWaveFormat->nAvgBytesPerSec,
792c2c66affSColin Finck wmw->lpWaveFormat->nSamplesPerSec *
793c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign);
794c2c66affSColin Finck wmw->lpWaveFormat->nAvgBytesPerSec =
795c2c66affSColin Finck wmw->lpWaveFormat->nSamplesPerSec *
796c2c66affSColin Finck wmw->lpWaveFormat->nBlockAlign;
797c2c66affSColin Finck }
798c2c66affSColin Finck }
799c2c66affSColin Finck
800c2c66affSColin Finck end = wmw->ckWaveData.cksize;
801c2c66affSColin Finck if (dwFlags & MCI_TO) {
802c2c66affSColin Finck DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
803c2c66affSColin Finck if (position > end) return MCIERR_OUTOFRANGE;
804c2c66affSColin Finck end = position;
805c2c66affSColin Finck }
806c2c66affSColin Finck if (dwFlags & MCI_FROM) {
807c2c66affSColin Finck DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
808c2c66affSColin Finck if (position > end) return MCIERR_OUTOFRANGE;
809c2c66affSColin Finck /* Seek rounds down, so do we. */
810c2c66affSColin Finck position /= wmw->lpWaveFormat->nBlockAlign;
811c2c66affSColin Finck position *= wmw->lpWaveFormat->nBlockAlign;
812c2c66affSColin Finck wmw->dwPosition = position;
813c2c66affSColin Finck }
814c2c66affSColin Finck if (end < wmw->dwPosition) return MCIERR_OUTOFRANGE;
815c2c66affSColin Finck left = end - wmw->dwPosition;
816c2c66affSColin Finck if (0==left) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
817c2c66affSColin Finck
818c2c66affSColin Finck wmw->fInput = FALSE; /* FIXME: waveInOpen may have been called. */
819c2c66affSColin Finck wmw->dwStatus = MCI_MODE_PLAY;
820c2c66affSColin Finck
821c2c66affSColin Finck if (!(dwFlags & MCI_WAIT)) {
822c2c66affSColin Finck return MCI_SendCommandAsync(wDevID, WAVE_mciPlay, dwFlags,
823c2c66affSColin Finck (DWORD_PTR)lpParms, sizeof(MCI_PLAY_PARMS));
824c2c66affSColin Finck }
825c2c66affSColin Finck
826c2c66affSColin Finck TRACE("Playing from byte=%u to byte=%u\n", wmw->dwPosition, end);
827c2c66affSColin Finck
828c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmw->hCallback,
829c2c66affSColin Finck (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
830c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
831c2c66affSColin Finck oldcb = NULL;
832c2c66affSColin Finck
833c2c66affSColin Finck #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
834c2c66affSColin Finck ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
835c2c66affSColin Finck
836c2c66affSColin Finck /* go back to beginning of chunk plus the requested position */
837c2c66affSColin Finck /* FIXME: I'm not sure this is correct, notably because some data linked to
838c2c66affSColin Finck * the decompression state machine will not be correctly initialized.
839c2c66affSColin Finck * try it this way (other way would be to decompress from 0 up to dwPosition
840c2c66affSColin Finck * and to start sending to hWave when dwPosition is reached)
841c2c66affSColin Finck */
842c2c66affSColin Finck mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
843c2c66affSColin Finck
844c2c66affSColin Finck dwRet = waveOutOpen((HWAVEOUT *)&wmw->hWave, wmw->wOutput, wmw->lpWaveFormat,
845c2c66affSColin Finck (DWORD_PTR)WAVE_mciPlayCallback, (DWORD_PTR)wmw, CALLBACK_FUNCTION);
846c2c66affSColin Finck
847c2c66affSColin Finck if (dwRet != 0) {
848c2c66affSColin Finck TRACE("Can't open low level audio device %d\n", dwRet);
849c2c66affSColin Finck dwRet = MCIERR_DEVICE_OPEN;
850c2c66affSColin Finck wmw->hWave = 0;
851c2c66affSColin Finck goto cleanUp;
852c2c66affSColin Finck }
853c2c66affSColin Finck
854c2c66affSColin Finck /* make it so that 3 buffers per second are needed */
855c2c66affSColin Finck bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
856c2c66affSColin Finck
857c2c66affSColin Finck waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
858c2c66affSColin Finck waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
859c2c66affSColin Finck waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
860c2c66affSColin Finck waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
861c2c66affSColin Finck waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
862c2c66affSColin Finck waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
863c2c66affSColin Finck waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
864c2c66affSColin Finck if (waveOutPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
865c2c66affSColin Finck waveOutPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
866c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
867c2c66affSColin Finck goto cleanUp;
868c2c66affSColin Finck }
869c2c66affSColin Finck
870c2c66affSColin Finck whidx = 0;
871c2c66affSColin Finck wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
872c2c66affSColin Finck if (!wmw->hEvent) {
873c2c66affSColin Finck dwRet = MCIERR_OUT_OF_MEMORY;
874c2c66affSColin Finck goto cleanUp;
875c2c66affSColin Finck }
876c2c66affSColin Finck wmw->dwEventCount = 1L; /* for first buffer */
877c2c66affSColin Finck
878c2c66affSColin Finck TRACE("Playing (normalized) from byte=%u for %u bytes\n", wmw->dwPosition, left);
879c2c66affSColin Finck if (hEvent) SetEvent(hEvent);
880c2c66affSColin Finck
881c2c66affSColin Finck /* FIXME: this doesn't work if wmw->dwPosition != 0 */
882c2c66affSColin Finck while (left > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
883c2c66affSColin Finck count = mmioRead(wmw->hFile, waveHdr[whidx].lpData, min(bufsize, left));
884c2c66affSColin Finck TRACE("mmioRead bufsize=%d count=%d\n", bufsize, count);
885c2c66affSColin Finck if (count < 1)
886c2c66affSColin Finck break;
887c2c66affSColin Finck /* count is always <= bufsize, so this is correct regarding the
888c2c66affSColin Finck * waveOutPrepareHeader function
889c2c66affSColin Finck */
890c2c66affSColin Finck waveHdr[whidx].dwBufferLength = count;
891c2c66affSColin Finck waveHdr[whidx].dwFlags &= ~WHDR_DONE;
892c2c66affSColin Finck TRACE("before WODM_WRITE lpWaveHdr=%p dwBufferLength=%u\n",
893c2c66affSColin Finck &waveHdr[whidx], waveHdr[whidx].dwBufferLength);
894c2c66affSColin Finck dwRet = waveOutWrite(wmw->hWave, &waveHdr[whidx], sizeof(WAVEHDR));
895c2c66affSColin Finck if (dwRet) {
896c2c66affSColin Finck ERR("Aborting play loop, WODM_WRITE error %d\n", dwRet);
897c2c66affSColin Finck dwRet = MCIERR_HARDWARE;
898c2c66affSColin Finck break;
899c2c66affSColin Finck }
900c2c66affSColin Finck left -= count;
901c2c66affSColin Finck wmw->dwPosition += count;
902c2c66affSColin Finck TRACE("after WODM_WRITE dwPosition=%u\n", wmw->dwPosition);
903c2c66affSColin Finck /* InterlockedDecrement if and only if waveOutWrite is successful */
904c2c66affSColin Finck WAVE_mciPlayWaitDone(wmw);
905c2c66affSColin Finck whidx ^= 1;
906c2c66affSColin Finck }
907c2c66affSColin Finck
908c2c66affSColin Finck WAVE_mciPlayWaitDone(wmw); /* to balance first buffer */
909c2c66affSColin Finck
910c2c66affSColin Finck /* just to get rid of some race conditions between play, stop and pause */
911c2c66affSColin Finck waveOutReset(wmw->hWave);
912c2c66affSColin Finck
913c2c66affSColin Finck waveOutUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
914c2c66affSColin Finck waveOutUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
915c2c66affSColin Finck
916c2c66affSColin Finck cleanUp:
917c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
918c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
919c2c66affSColin Finck
920c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, waveHdr);
921c2c66affSColin Finck
922c2c66affSColin Finck if (wmw->hWave) {
923c2c66affSColin Finck waveOutClose(wmw->hWave);
924c2c66affSColin Finck wmw->hWave = 0;
925c2c66affSColin Finck }
926c2c66affSColin Finck CloseHandle(wmw->hEvent);
927c2c66affSColin Finck wmw->hEvent = NULL;
928c2c66affSColin Finck
929c2c66affSColin Finck wmw->dwStatus = MCI_MODE_STOP;
930c2c66affSColin Finck
931c2c66affSColin Finck /* Let the potentially asynchronous commands support FAILURE notification. */
932c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wDevID,
933c2c66affSColin Finck dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
934c2c66affSColin Finck
935c2c66affSColin Finck return dwRet;
936c2c66affSColin Finck }
937c2c66affSColin Finck
938c2c66affSColin Finck /**************************************************************************
939c2c66affSColin Finck * WAVE_mciRecordCallback [internal]
940c2c66affSColin Finck */
WAVE_mciRecordCallback(HWAVEOUT hwo,UINT uMsg,DWORD_PTR dwInstance,LPARAM dwParam1,LPARAM dwParam2)941c2c66affSColin Finck static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
942c2c66affSColin Finck DWORD_PTR dwInstance,
943c2c66affSColin Finck LPARAM dwParam1, LPARAM dwParam2)
944c2c66affSColin Finck {
945c2c66affSColin Finck WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
946c2c66affSColin Finck LPWAVEHDR lpWaveHdr;
947c2c66affSColin Finck LONG count = 0;
948c2c66affSColin Finck
949c2c66affSColin Finck switch (uMsg) {
950c2c66affSColin Finck case WIM_OPEN:
951c2c66affSColin Finck case WIM_CLOSE:
952c2c66affSColin Finck break;
953c2c66affSColin Finck case WIM_DATA:
954c2c66affSColin Finck lpWaveHdr = (LPWAVEHDR) dwParam1;
955c2c66affSColin Finck
956c2c66affSColin Finck InterlockedIncrement(&wmw->dwEventCount);
957c2c66affSColin Finck
958c2c66affSColin Finck count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
959c2c66affSColin Finck
960c2c66affSColin Finck lpWaveHdr->dwFlags &= ~WHDR_DONE;
961c2c66affSColin Finck if (count > 0)
962c2c66affSColin Finck wmw->dwPosition += count;
963c2c66affSColin Finck /* else error reporting ?? */
964c2c66affSColin Finck if (wmw->dwStatus == MCI_MODE_RECORD)
965c2c66affSColin Finck {
966c2c66affSColin Finck /* Only queue up another buffer if we are recording. We could receive this
967c2c66affSColin Finck message also when waveInReset() is called, since it notifies on all wave
968c2c66affSColin Finck buffers that are outstanding. Queueing up more sometimes causes waveInClose
969c2c66affSColin Finck to fail. */
970c2c66affSColin Finck waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
971c2c66affSColin Finck TRACE("after mmioWrite dwPosition=%u\n", wmw->dwPosition);
972c2c66affSColin Finck }
973c2c66affSColin Finck
974c2c66affSColin Finck SetEvent(wmw->hEvent);
975c2c66affSColin Finck break;
976c2c66affSColin Finck default:
977c2c66affSColin Finck ERR("Unknown uMsg=%d\n", uMsg);
978c2c66affSColin Finck }
979c2c66affSColin Finck }
980c2c66affSColin Finck
981c2c66affSColin Finck /******************************************************************
982c2c66affSColin Finck * WAVE_mciRecordWaitDone [internal]
983c2c66affSColin Finck */
WAVE_mciRecordWaitDone(WINE_MCIWAVE * wmw)984c2c66affSColin Finck static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
985c2c66affSColin Finck {
986c2c66affSColin Finck for (;;) {
987c2c66affSColin Finck ResetEvent(wmw->hEvent);
988c2c66affSColin Finck if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
989c2c66affSColin Finck break;
990c2c66affSColin Finck }
991c2c66affSColin Finck InterlockedIncrement(&wmw->dwEventCount);
992c2c66affSColin Finck
993c2c66affSColin Finck WaitForSingleObject(wmw->hEvent, INFINITE);
994c2c66affSColin Finck }
995c2c66affSColin Finck }
996c2c66affSColin Finck
997c2c66affSColin Finck /**************************************************************************
998c2c66affSColin Finck * WAVE_mciRecord [internal]
999c2c66affSColin Finck */
WAVE_mciRecord(MCIDEVICEID wDevID,DWORD_PTR dwFlags,DWORD_PTR pmt,HANDLE hEvent)1000c2c66affSColin Finck static DWORD WAVE_mciRecord(MCIDEVICEID wDevID, DWORD_PTR dwFlags, DWORD_PTR pmt, HANDLE hEvent)
1001c2c66affSColin Finck {
1002c2c66affSColin Finck LPMCI_RECORD_PARMS lpParms = (void*)pmt;
1003c2c66affSColin Finck DWORD end;
1004c2c66affSColin Finck DWORD dwRet = MMSYSERR_NOERROR;
1005c2c66affSColin Finck LONG bufsize;
1006c2c66affSColin Finck LPWAVEHDR waveHdr = NULL;
1007c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1008c2c66affSColin Finck HANDLE oldcb;
1009c2c66affSColin Finck
1010c2c66affSColin Finck TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
1011c2c66affSColin Finck
1012c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1013c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1014c2c66affSColin Finck
1015c2c66affSColin Finck if (wmw->dwStatus == MCI_MODE_PAUSE && wmw->fInput) {
1016c2c66affSColin Finck /* FIXME: parameters (start/end) in lpParams may not be used */
1017c2c66affSColin Finck return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
1018c2c66affSColin Finck }
1019c2c66affSColin Finck
1020c2c66affSColin Finck /** This function will be called again by a thread when async is used.
1021c2c66affSColin Finck * We have to set MCI_MODE_RECORD before we do this so that the app can spin
1022c2c66affSColin Finck * on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
1023c2c66affSColin Finck */
1024c2c66affSColin Finck if ( !(wmw->dwStatus == MCI_MODE_STOP) &&
1025c2c66affSColin Finck !((wmw->dwStatus == MCI_MODE_RECORD) && (dwFlags & MCI_WAIT) && !wmw->hWave)) {
1026c2c66affSColin Finck return MCIERR_INTERNAL;
1027c2c66affSColin Finck }
1028c2c66affSColin Finck
1029c2c66affSColin Finck wmw->fInput = TRUE; /* FIXME: waveOutOpen may have been called. */
1030c2c66affSColin Finck wmw->dwStatus = MCI_MODE_RECORD;
1031c2c66affSColin Finck
1032c2c66affSColin Finck if (!(dwFlags & MCI_WAIT)) {
1033c2c66affSColin Finck return MCI_SendCommandAsync(wDevID, WAVE_mciRecord, dwFlags,
1034c2c66affSColin Finck (DWORD_PTR)lpParms, sizeof(MCI_RECORD_PARMS));
1035c2c66affSColin Finck }
1036c2c66affSColin Finck
1037c2c66affSColin Finck /* FIXME: we only re-create the RIFF structure from an existing file (if any)
1038c2c66affSColin Finck * we don't modify the wave part of an existing file (ie. we always erase an
1039c2c66affSColin Finck * existing content, we don't overwrite)
1040c2c66affSColin Finck */
1041c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmw->lpFileName);
1042c2c66affSColin Finck dwRet = create_tmp_file(&wmw->hFile, (WCHAR**)&wmw->lpFileName);
1043c2c66affSColin Finck if (dwRet != 0) return dwRet;
1044c2c66affSColin Finck
1045c2c66affSColin Finck /* new RIFF file, lpWaveFormat now valid */
1046c2c66affSColin Finck dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
1047c2c66affSColin Finck if (dwRet != 0) return dwRet;
1048c2c66affSColin Finck
1049c2c66affSColin Finck if (dwFlags & MCI_TO) {
1050c2c66affSColin Finck end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1051c2c66affSColin Finck } else end = 0xFFFFFFFF;
1052c2c66affSColin Finck if (dwFlags & MCI_FROM) {
1053c2c66affSColin Finck DWORD position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
1054c2c66affSColin Finck if (wmw->ckWaveData.cksize < position) return MCIERR_OUTOFRANGE;
1055c2c66affSColin Finck /* Seek rounds down, so do we. */
1056c2c66affSColin Finck position /= wmw->lpWaveFormat->nBlockAlign;
1057c2c66affSColin Finck position *= wmw->lpWaveFormat->nBlockAlign;
1058c2c66affSColin Finck wmw->dwPosition = position;
1059c2c66affSColin Finck }
1060c2c66affSColin Finck if (end==wmw->dwPosition) return MMSYSERR_NOERROR; /* FIXME: NOTIFY */
1061c2c66affSColin Finck
1062c2c66affSColin Finck TRACE("Recording from byte=%u to byte=%u\n", wmw->dwPosition, end);
1063c2c66affSColin Finck
1064c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmw->hCallback,
1065c2c66affSColin Finck (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
1066c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_ABORTED);
1067c2c66affSColin Finck oldcb = NULL;
1068c2c66affSColin Finck
1069c2c66affSColin Finck #define WAVE_ALIGN_ON_BLOCK(wmw,v) \
1070c2c66affSColin Finck ((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
1071c2c66affSColin Finck
1072c2c66affSColin Finck wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
1073c2c66affSColin Finck
1074c2c66affSColin Finck /* Go back to the beginning of the chunk plus the requested position */
1075c2c66affSColin Finck /* FIXME: I'm not sure this is correct, notably because some data linked to
1076c2c66affSColin Finck * the decompression state machine will not be correctly initialized.
1077c2c66affSColin Finck * Try it this way (other way would be to decompress from 0 up to dwPosition
1078c2c66affSColin Finck * and to start sending to hWave when dwPosition is reached).
1079c2c66affSColin Finck */
1080c2c66affSColin Finck mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
1081c2c66affSColin Finck
1082c2c66affSColin Finck dwRet = waveInOpen((HWAVEIN*)&wmw->hWave, wmw->wInput, wmw->lpWaveFormat,
1083c2c66affSColin Finck (DWORD_PTR)WAVE_mciRecordCallback, (DWORD_PTR)wmw, CALLBACK_FUNCTION);
1084c2c66affSColin Finck
1085c2c66affSColin Finck if (dwRet != MMSYSERR_NOERROR) {
1086c2c66affSColin Finck TRACE("Can't open low level audio device %d\n", dwRet);
1087c2c66affSColin Finck dwRet = MCIERR_DEVICE_OPEN;
1088c2c66affSColin Finck wmw->hWave = 0;
1089c2c66affSColin Finck goto cleanUp;
1090c2c66affSColin Finck }
1091c2c66affSColin Finck
1092c2c66affSColin Finck /* make it so that 3 buffers per second are needed */
1093c2c66affSColin Finck bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
1094c2c66affSColin Finck
1095c2c66affSColin Finck waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
1096c2c66affSColin Finck waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
1097c2c66affSColin Finck waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
1098c2c66affSColin Finck waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
1099c2c66affSColin Finck waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
1100c2c66affSColin Finck waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
1101c2c66affSColin Finck waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
1102c2c66affSColin Finck
1103c2c66affSColin Finck if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1104c2c66affSColin Finck waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1105c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1106c2c66affSColin Finck goto cleanUp;
1107c2c66affSColin Finck }
1108c2c66affSColin Finck
1109c2c66affSColin Finck if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
1110c2c66affSColin Finck waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
1111c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1112c2c66affSColin Finck goto cleanUp;
1113c2c66affSColin Finck }
1114c2c66affSColin Finck
1115c2c66affSColin Finck wmw->hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
1116c2c66affSColin Finck wmw->dwEventCount = 1L; /* for first buffer */
1117c2c66affSColin Finck
1118c2c66affSColin Finck TRACE("Recording (normalized) from byte=%u for %u bytes\n", wmw->dwPosition, end - wmw->dwPosition);
1119c2c66affSColin Finck
1120c2c66affSColin Finck waveInStart(wmw->hWave);
1121c2c66affSColin Finck
1122c2c66affSColin Finck if (hEvent) SetEvent(hEvent);
1123c2c66affSColin Finck
1124c2c66affSColin Finck while (wmw->dwPosition < end && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
1125c2c66affSColin Finck WAVE_mciRecordWaitDone(wmw);
1126c2c66affSColin Finck }
1127c2c66affSColin Finck /* Grab callback before another thread kicks in after we change dwStatus. */
1128c2c66affSColin Finck if (dwFlags & MCI_NOTIFY) {
1129c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
1130c2c66affSColin Finck dwFlags &= ~MCI_NOTIFY;
1131c2c66affSColin Finck }
1132c2c66affSColin Finck /* needed so that the callback above won't add again the buffers returned by the reset */
1133c2c66affSColin Finck wmw->dwStatus = MCI_MODE_STOP;
1134c2c66affSColin Finck
1135c2c66affSColin Finck waveInReset(wmw->hWave);
1136c2c66affSColin Finck
1137c2c66affSColin Finck waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
1138c2c66affSColin Finck waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
1139c2c66affSColin Finck
1140c2c66affSColin Finck dwRet = 0;
1141c2c66affSColin Finck
1142c2c66affSColin Finck cleanUp:
1143c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
1144c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmw->hCallback, NULL);
1145c2c66affSColin Finck
1146c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, waveHdr);
1147c2c66affSColin Finck
1148c2c66affSColin Finck if (wmw->hWave) {
1149c2c66affSColin Finck waveInClose(wmw->hWave);
1150c2c66affSColin Finck wmw->hWave = 0;
1151c2c66affSColin Finck }
1152c2c66affSColin Finck CloseHandle(wmw->hEvent);
1153c2c66affSColin Finck
1154c2c66affSColin Finck wmw->dwStatus = MCI_MODE_STOP;
1155c2c66affSColin Finck
1156c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wDevID,
1157c2c66affSColin Finck dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1158c2c66affSColin Finck
1159c2c66affSColin Finck return dwRet;
1160c2c66affSColin Finck
1161c2c66affSColin Finck }
1162c2c66affSColin Finck
1163c2c66affSColin Finck /**************************************************************************
1164c2c66affSColin Finck * WAVE_mciPause [internal]
1165c2c66affSColin Finck */
WAVE_mciPause(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)1166c2c66affSColin Finck static DWORD WAVE_mciPause(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1167c2c66affSColin Finck {
1168c2c66affSColin Finck DWORD dwRet;
1169c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1170c2c66affSColin Finck
1171c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1172c2c66affSColin Finck
1173c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1174c2c66affSColin Finck
1175c2c66affSColin Finck switch (wmw->dwStatus) {
1176c2c66affSColin Finck case MCI_MODE_PLAY:
1177c2c66affSColin Finck dwRet = waveOutPause(wmw->hWave);
1178c2c66affSColin Finck if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1179c2c66affSColin Finck else { /* When playthread was not started yet, winmm not opened, error 5 MMSYSERR_INVALHANDLE */
1180c2c66affSColin Finck ERR("waveOutPause error %d\n",dwRet);
1181c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1182c2c66affSColin Finck }
1183c2c66affSColin Finck break;
1184c2c66affSColin Finck case MCI_MODE_RECORD:
1185c2c66affSColin Finck dwRet = waveInStop(wmw->hWave);
1186c2c66affSColin Finck if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PAUSE;
1187c2c66affSColin Finck else {
1188c2c66affSColin Finck ERR("waveInStop error %d\n",dwRet);
1189c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1190c2c66affSColin Finck }
1191c2c66affSColin Finck break;
1192c2c66affSColin Finck case MCI_MODE_PAUSE:
1193c2c66affSColin Finck dwRet = MMSYSERR_NOERROR;
1194c2c66affSColin Finck break;
1195c2c66affSColin Finck default:
1196c2c66affSColin Finck dwRet = MCIERR_NONAPPLICABLE_FUNCTION;
1197c2c66affSColin Finck }
1198c2c66affSColin Finck if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1199c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1200c2c66affSColin Finck return dwRet;
1201c2c66affSColin Finck }
1202c2c66affSColin Finck
1203c2c66affSColin Finck /**************************************************************************
1204c2c66affSColin Finck * WAVE_mciResume [internal]
1205c2c66affSColin Finck */
WAVE_mciResume(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)1206c2c66affSColin Finck static DWORD WAVE_mciResume(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1207c2c66affSColin Finck {
1208c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1209c2c66affSColin Finck DWORD dwRet;
1210c2c66affSColin Finck
1211c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1212c2c66affSColin Finck
1213c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1214c2c66affSColin Finck
1215c2c66affSColin Finck switch (wmw->dwStatus) {
1216c2c66affSColin Finck case MCI_MODE_PAUSE:
1217c2c66affSColin Finck /* Only update dwStatus if wave* succeeds and will exchange buffers buffers. */
1218c2c66affSColin Finck if (wmw->fInput) {
1219c2c66affSColin Finck dwRet = waveInStart(wmw->hWave);
1220c2c66affSColin Finck if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_RECORD;
1221c2c66affSColin Finck else {
1222c2c66affSColin Finck ERR("waveInStart error %d\n",dwRet);
1223c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1224c2c66affSColin Finck }
1225c2c66affSColin Finck } else {
1226c2c66affSColin Finck dwRet = waveOutRestart(wmw->hWave);
1227c2c66affSColin Finck if (dwRet==MMSYSERR_NOERROR) wmw->dwStatus = MCI_MODE_PLAY;
1228c2c66affSColin Finck else {
1229c2c66affSColin Finck ERR("waveOutRestart error %d\n",dwRet);
1230c2c66affSColin Finck dwRet = MCIERR_INTERNAL;
1231c2c66affSColin Finck }
1232c2c66affSColin Finck }
1233c2c66affSColin Finck break;
1234c2c66affSColin Finck case MCI_MODE_PLAY:
1235c2c66affSColin Finck case MCI_MODE_RECORD:
1236c2c66affSColin Finck dwRet = MMSYSERR_NOERROR;
1237c2c66affSColin Finck break;
1238c2c66affSColin Finck default:
1239c2c66affSColin Finck dwRet = MCIERR_NONAPPLICABLE_FUNCTION;
1240c2c66affSColin Finck }
1241c2c66affSColin Finck if (MMSYSERR_NOERROR==dwRet && (dwFlags & MCI_NOTIFY) && lpParms)
1242c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1243c2c66affSColin Finck return dwRet;
1244c2c66affSColin Finck }
1245c2c66affSColin Finck
1246c2c66affSColin Finck /**************************************************************************
1247c2c66affSColin Finck * WAVE_mciSeek [internal]
1248c2c66affSColin Finck */
WAVE_mciSeek(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_SEEK_PARMS lpParms)1249c2c66affSColin Finck static DWORD WAVE_mciSeek(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1250c2c66affSColin Finck {
1251c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1252c2c66affSColin Finck DWORD position, dwRet;
1253c2c66affSColin Finck
1254c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1255c2c66affSColin Finck
1256c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1257c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1258c2c66affSColin Finck
1259c2c66affSColin Finck position = dwFlags & (MCI_SEEK_TO_START|MCI_SEEK_TO_END|MCI_TO);
1260c2c66affSColin Finck if (!position) return MCIERR_MISSING_PARAMETER;
1261c2c66affSColin Finck if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
1262c2c66affSColin Finck
1263c2c66affSColin Finck /* Stop sends MCI_NOTIFY_ABORTED when needed */
1264c2c66affSColin Finck dwRet = WAVE_mciStop(wDevID, MCI_WAIT, 0);
1265c2c66affSColin Finck if (dwRet != MMSYSERR_NOERROR) return dwRet;
1266c2c66affSColin Finck
1267c2c66affSColin Finck if (dwFlags & MCI_TO) {
1268c2c66affSColin Finck position = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
1269c2c66affSColin Finck if (position > wmw->ckWaveData.cksize)
1270c2c66affSColin Finck return MCIERR_OUTOFRANGE;
1271c2c66affSColin Finck } else if (dwFlags & MCI_SEEK_TO_START) {
1272c2c66affSColin Finck position = 0;
1273c2c66affSColin Finck } else {
1274c2c66affSColin Finck position = wmw->ckWaveData.cksize;
1275c2c66affSColin Finck }
1276c2c66affSColin Finck /* Seek rounds down, unless at end */
1277c2c66affSColin Finck if (position != wmw->ckWaveData.cksize) {
1278c2c66affSColin Finck position /= wmw->lpWaveFormat->nBlockAlign;
1279c2c66affSColin Finck position *= wmw->lpWaveFormat->nBlockAlign;
1280c2c66affSColin Finck }
1281c2c66affSColin Finck wmw->dwPosition = position;
1282c2c66affSColin Finck TRACE("Seeking to position=%u bytes\n", position);
1283c2c66affSColin Finck
1284c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
1285c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1286c2c66affSColin Finck
1287c2c66affSColin Finck return MMSYSERR_NOERROR;
1288c2c66affSColin Finck }
1289c2c66affSColin Finck
1290c2c66affSColin Finck /**************************************************************************
1291c2c66affSColin Finck * WAVE_mciSet [internal]
1292c2c66affSColin Finck */
WAVE_mciSet(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_WAVE_SET_PARMS lpParms)1293c2c66affSColin Finck static DWORD WAVE_mciSet(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_WAVE_SET_PARMS lpParms)
1294c2c66affSColin Finck {
1295c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1296c2c66affSColin Finck
1297c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1298c2c66affSColin Finck
1299c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1300c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1301c2c66affSColin Finck
1302c2c66affSColin Finck if (dwFlags & MCI_SET_TIME_FORMAT) {
1303c2c66affSColin Finck switch (lpParms->dwTimeFormat) {
1304c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
1305c2c66affSColin Finck TRACE("MCI_FORMAT_MILLISECONDS !\n");
1306c2c66affSColin Finck wmw->dwMciTimeFormat = MCI_FORMAT_MILLISECONDS;
1307c2c66affSColin Finck break;
1308c2c66affSColin Finck case MCI_FORMAT_BYTES:
1309c2c66affSColin Finck TRACE("MCI_FORMAT_BYTES !\n");
1310c2c66affSColin Finck wmw->dwMciTimeFormat = MCI_FORMAT_BYTES;
1311c2c66affSColin Finck break;
1312c2c66affSColin Finck case MCI_FORMAT_SAMPLES:
1313c2c66affSColin Finck TRACE("MCI_FORMAT_SAMPLES !\n");
1314c2c66affSColin Finck wmw->dwMciTimeFormat = MCI_FORMAT_SAMPLES;
1315c2c66affSColin Finck break;
1316c2c66affSColin Finck default:
1317c2c66affSColin Finck WARN("Bad time format %u!\n", lpParms->dwTimeFormat);
1318c2c66affSColin Finck return MCIERR_BAD_TIME_FORMAT;
1319c2c66affSColin Finck }
1320c2c66affSColin Finck }
1321c2c66affSColin Finck if (dwFlags & MCI_SET_VIDEO) {
1322c2c66affSColin Finck TRACE("No support for video !\n");
1323c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1324c2c66affSColin Finck }
1325c2c66affSColin Finck if (dwFlags & MCI_SET_DOOR_OPEN) {
1326c2c66affSColin Finck TRACE("No support for door open !\n");
1327c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1328c2c66affSColin Finck }
1329c2c66affSColin Finck if (dwFlags & MCI_SET_DOOR_CLOSED) {
1330c2c66affSColin Finck TRACE("No support for door close !\n");
1331c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1332c2c66affSColin Finck }
1333c2c66affSColin Finck if (dwFlags & MCI_SET_AUDIO) {
1334c2c66affSColin Finck if (dwFlags & MCI_SET_ON) {
1335c2c66affSColin Finck TRACE("MCI_SET_ON audio !\n");
1336c2c66affSColin Finck } else if (dwFlags & MCI_SET_OFF) {
1337c2c66affSColin Finck TRACE("MCI_SET_OFF audio !\n");
1338c2c66affSColin Finck } else {
1339c2c66affSColin Finck WARN("MCI_SET_AUDIO without SET_ON or SET_OFF\n");
1340c2c66affSColin Finck return MCIERR_BAD_INTEGER;
1341c2c66affSColin Finck }
1342c2c66affSColin Finck
1343c2c66affSColin Finck switch (lpParms->dwAudio)
1344c2c66affSColin Finck {
1345c2c66affSColin Finck case MCI_SET_AUDIO_ALL: TRACE("MCI_SET_AUDIO_ALL !\n"); break;
1346c2c66affSColin Finck case MCI_SET_AUDIO_LEFT: TRACE("MCI_SET_AUDIO_LEFT !\n"); break;
1347c2c66affSColin Finck case MCI_SET_AUDIO_RIGHT: TRACE("MCI_SET_AUDIO_RIGHT !\n"); break;
1348c2c66affSColin Finck default: WARN("Unknown audio channel %u\n", lpParms->dwAudio); break;
1349c2c66affSColin Finck }
1350c2c66affSColin Finck }
1351c2c66affSColin Finck if (dwFlags & MCI_WAVE_INPUT) {
1352c2c66affSColin Finck TRACE("MCI_WAVE_INPUT = %d\n", lpParms->wInput);
1353c2c66affSColin Finck if (lpParms->wInput >= waveInGetNumDevs())
1354c2c66affSColin Finck return MCIERR_OUTOFRANGE;
1355c2c66affSColin Finck if (wmw->wInput != (WORD)lpParms->wInput)
1356c2c66affSColin Finck WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1357c2c66affSColin Finck wmw->wInput = lpParms->wInput;
1358c2c66affSColin Finck }
1359c2c66affSColin Finck if (dwFlags & MCI_WAVE_OUTPUT) {
1360c2c66affSColin Finck TRACE("MCI_WAVE_OUTPUT = %d\n", lpParms->wOutput);
1361c2c66affSColin Finck if (lpParms->wOutput >= waveOutGetNumDevs())
1362c2c66affSColin Finck return MCIERR_OUTOFRANGE;
1363c2c66affSColin Finck if (wmw->wOutput != (WORD)lpParms->wOutput)
1364c2c66affSColin Finck WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1365c2c66affSColin Finck wmw->wOutput = lpParms->wOutput;
1366c2c66affSColin Finck }
1367c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_ANYINPUT) {
1368c2c66affSColin Finck TRACE("MCI_WAVE_SET_ANYINPUT\n");
1369c2c66affSColin Finck if (wmw->wInput != (WORD)lpParms->wInput)
1370c2c66affSColin Finck WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1371c2c66affSColin Finck wmw->wInput = WAVE_MAPPER;
1372c2c66affSColin Finck }
1373c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_ANYOUTPUT) {
1374c2c66affSColin Finck TRACE("MCI_WAVE_SET_ANYOUTPUT\n");
1375c2c66affSColin Finck if (wmw->wOutput != (WORD)lpParms->wOutput)
1376c2c66affSColin Finck WAVE_mciStop(wDevID, MCI_WAIT, NULL);
1377c2c66affSColin Finck wmw->wOutput = WAVE_MAPPER;
1378c2c66affSColin Finck }
1379c2c66affSColin Finck /* Set wave format parameters is refused after Open or Record.*/
1380c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_FORMATTAG) {
1381c2c66affSColin Finck TRACE("MCI_WAVE_SET_FORMATTAG = %d\n", lpParms->wFormatTag);
1382c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1383c2c66affSColin Finck if (lpParms->wFormatTag != WAVE_FORMAT_PCM)
1384c2c66affSColin Finck return MCIERR_OUTOFRANGE;
1385c2c66affSColin Finck }
1386c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_AVGBYTESPERSEC) {
1387c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1388c2c66affSColin Finck wmw->wfxRef.nAvgBytesPerSec = lpParms->nAvgBytesPerSec;
1389c2c66affSColin Finck TRACE("MCI_WAVE_SET_AVGBYTESPERSEC = %d\n", wmw->wfxRef.nAvgBytesPerSec);
1390c2c66affSColin Finck }
1391c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_BITSPERSAMPLE) {
1392c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1393c2c66affSColin Finck wmw->wfxRef.wBitsPerSample = lpParms->wBitsPerSample;
1394c2c66affSColin Finck TRACE("MCI_WAVE_SET_BITSPERSAMPLE = %d\n", wmw->wfxRef.wBitsPerSample);
1395c2c66affSColin Finck }
1396c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_BLOCKALIGN) {
1397c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1398c2c66affSColin Finck wmw->wfxRef.nBlockAlign = lpParms->nBlockAlign;
1399c2c66affSColin Finck TRACE("MCI_WAVE_SET_BLOCKALIGN = %d\n", wmw->wfxRef.nBlockAlign);
1400c2c66affSColin Finck }
1401c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_CHANNELS) {
1402c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1403c2c66affSColin Finck wmw->wfxRef.nChannels = lpParms->nChannels;
1404c2c66affSColin Finck TRACE("MCI_WAVE_SET_CHANNELS = %d\n", wmw->wfxRef.nChannels);
1405c2c66affSColin Finck }
1406c2c66affSColin Finck if (dwFlags & MCI_WAVE_SET_SAMPLESPERSEC) {
1407c2c66affSColin Finck if (wmw->lpWaveFormat != &wmw->wfxRef) return MCIERR_NONAPPLICABLE_FUNCTION;
1408c2c66affSColin Finck wmw->wfxRef.nSamplesPerSec = lpParms->nSamplesPerSec;
1409c2c66affSColin Finck TRACE("MCI_WAVE_SET_SAMPLESPERSEC = %d\n", wmw->wfxRef.nSamplesPerSec);
1410c2c66affSColin Finck }
1411c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
1412c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1413c2c66affSColin Finck return 0;
1414c2c66affSColin Finck }
1415c2c66affSColin Finck
1416c2c66affSColin Finck /**************************************************************************
1417c2c66affSColin Finck * WAVE_mciSave [internal]
1418c2c66affSColin Finck */
WAVE_mciSave(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_SAVE_PARMSW lpParms)1419c2c66affSColin Finck static DWORD WAVE_mciSave(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_SAVE_PARMSW lpParms)
1420c2c66affSColin Finck {
1421c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1422c2c66affSColin Finck DWORD ret = MCIERR_FILE_NOT_SAVED, tmpRet;
1423c2c66affSColin Finck
1424c2c66affSColin Finck TRACE("%d, %08X, %p);\n", wDevID, dwFlags, lpParms);
1425c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1426c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1427c2c66affSColin Finck
1428c2c66affSColin Finck if (dwFlags & MCI_WAIT)
1429c2c66affSColin Finck {
1430c2c66affSColin Finck FIXME("MCI_WAIT not implemented\n");
1431c2c66affSColin Finck }
1432c2c66affSColin Finck WAVE_mciStop(wDevID, 0, NULL);
1433c2c66affSColin Finck
1434c2c66affSColin Finck ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
1435c2c66affSColin Finck ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
1436c2c66affSColin Finck
1437c2c66affSColin Finck ret = mmioClose(wmw->hFile, 0);
1438c2c66affSColin Finck wmw->hFile = 0;
1439c2c66affSColin Finck
1440c2c66affSColin Finck /*
1441c2c66affSColin Finck If the destination file already exists, it has to be overwritten. (Behaviour
1442c2c66affSColin Finck verified in Windows (2000)). If it doesn't overwrite, it is breaking one of
1443c2c66affSColin Finck my applications. We are making use of mmioRename, which WILL NOT overwrite
1444c2c66affSColin Finck the destination file (which is what Windows does, also verified in Win2K)
1445c2c66affSColin Finck So, lets delete the destination file before calling mmioRename. If the
1446c2c66affSColin Finck destination file DOESN'T exist, the delete will fail silently. Let's also be
1447c2c66affSColin Finck careful not to lose our previous error code.
1448c2c66affSColin Finck */
1449c2c66affSColin Finck tmpRet = GetLastError();
1450c2c66affSColin Finck DeleteFileW (lpParms->lpfilename);
1451c2c66affSColin Finck SetLastError(tmpRet);
1452c2c66affSColin Finck
1453c2c66affSColin Finck /* FIXME: Open file.wav; Save; must not rename the original file.
1454c2c66affSColin Finck * Nor must Save a.wav; Save b.wav rename a. */
1455c2c66affSColin Finck if (0 == mmioRenameW(wmw->lpFileName, lpParms->lpfilename, 0, 0 )) {
1456c2c66affSColin Finck ret = MMSYSERR_NOERROR;
1457c2c66affSColin Finck }
1458c2c66affSColin Finck
1459c2c66affSColin Finck if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
1460c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1461c2c66affSColin Finck
1462c2c66affSColin Finck if (ret == MMSYSERR_NOERROR)
1463c2c66affSColin Finck ret = WAVE_mciOpenFile(wmw, lpParms->lpfilename);
1464c2c66affSColin Finck
1465c2c66affSColin Finck return ret;
1466c2c66affSColin Finck }
1467c2c66affSColin Finck
1468c2c66affSColin Finck /**************************************************************************
1469c2c66affSColin Finck * WAVE_mciStatus [internal]
1470c2c66affSColin Finck */
WAVE_mciStatus(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_STATUS_PARMS lpParms)1471c2c66affSColin Finck static DWORD WAVE_mciStatus(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
1472c2c66affSColin Finck {
1473c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1474c2c66affSColin Finck DWORD ret = 0;
1475c2c66affSColin Finck
1476c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1477c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1478c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1479c2c66affSColin Finck if (!(dwFlags & MCI_STATUS_ITEM)) return MCIERR_MISSING_PARAMETER;
1480c2c66affSColin Finck
1481c2c66affSColin Finck if (dwFlags & MCI_STATUS_ITEM) {
1482c2c66affSColin Finck switch (lpParms->dwItem) {
1483c2c66affSColin Finck case MCI_STATUS_CURRENT_TRACK:
1484c2c66affSColin Finck lpParms->dwReturn = 1;
1485c2c66affSColin Finck TRACE("MCI_STATUS_CURRENT_TRACK => %lu\n", lpParms->dwReturn);
1486c2c66affSColin Finck break;
1487c2c66affSColin Finck case MCI_STATUS_LENGTH:
1488c2c66affSColin Finck if (!wmw->hFile) {
1489c2c66affSColin Finck lpParms->dwReturn = 0;
1490c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1491c2c66affSColin Finck }
1492c2c66affSColin Finck /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1493c2c66affSColin Finck lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize);
1494c2c66affSColin Finck TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
1495c2c66affSColin Finck break;
1496c2c66affSColin Finck case MCI_STATUS_MODE:
1497c2c66affSColin Finck TRACE("MCI_STATUS_MODE => %u\n", wmw->dwStatus);
1498c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwStatus, wmw->dwStatus);
1499c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1500c2c66affSColin Finck break;
1501c2c66affSColin Finck case MCI_STATUS_MEDIA_PRESENT:
1502c2c66affSColin Finck TRACE("MCI_STATUS_MEDIA_PRESENT => TRUE!\n");
1503c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1504c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1505c2c66affSColin Finck break;
1506c2c66affSColin Finck case MCI_STATUS_NUMBER_OF_TRACKS:
1507c2c66affSColin Finck /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1508c2c66affSColin Finck lpParms->dwReturn = 1;
1509c2c66affSColin Finck TRACE("MCI_STATUS_NUMBER_OF_TRACKS => %lu\n", lpParms->dwReturn);
1510c2c66affSColin Finck break;
1511c2c66affSColin Finck case MCI_STATUS_POSITION:
1512c2c66affSColin Finck if (!wmw->hFile) {
1513c2c66affSColin Finck lpParms->dwReturn = 0;
1514c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1515c2c66affSColin Finck }
1516c2c66affSColin Finck /* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
1517c2c66affSColin Finck lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw,
1518c2c66affSColin Finck (dwFlags & MCI_STATUS_START) ? 0 : wmw->dwPosition);
1519c2c66affSColin Finck TRACE("MCI_STATUS_POSITION %s => %lu\n",
1520c2c66affSColin Finck (dwFlags & MCI_STATUS_START) ? "start" : "current", lpParms->dwReturn);
1521c2c66affSColin Finck break;
1522c2c66affSColin Finck case MCI_STATUS_READY:
1523c2c66affSColin Finck lpParms->dwReturn = (wmw->dwStatus == MCI_MODE_NOT_READY) ?
1524c2c66affSColin Finck MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1525c2c66affSColin Finck TRACE("MCI_STATUS_READY => %u!\n", LOWORD(lpParms->dwReturn));
1526c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1527c2c66affSColin Finck break;
1528c2c66affSColin Finck case MCI_STATUS_TIME_FORMAT:
1529c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(wmw->dwMciTimeFormat, MCI_FORMAT_RETURN_BASE + wmw->dwMciTimeFormat);
1530c2c66affSColin Finck TRACE("MCI_STATUS_TIME_FORMAT => %lu\n", lpParms->dwReturn);
1531c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1532c2c66affSColin Finck break;
1533c2c66affSColin Finck case MCI_WAVE_INPUT:
1534c2c66affSColin Finck if (wmw->wInput != (WORD)WAVE_MAPPER)
1535c2c66affSColin Finck lpParms->dwReturn = wmw->wInput;
1536c2c66affSColin Finck else {
1537c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_MAPPER, WAVE_MAPPER_S);
1538c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1539c2c66affSColin Finck }
1540c2c66affSColin Finck TRACE("MCI_WAVE_INPUT => %d\n", (signed)wmw->wInput);
1541c2c66affSColin Finck break;
1542c2c66affSColin Finck case MCI_WAVE_OUTPUT:
1543c2c66affSColin Finck if (wmw->wOutput != (WORD)WAVE_MAPPER)
1544c2c66affSColin Finck lpParms->dwReturn = wmw->wOutput;
1545c2c66affSColin Finck else {
1546c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_MAPPER, WAVE_MAPPER_S);
1547c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1548c2c66affSColin Finck }
1549c2c66affSColin Finck TRACE("MCI_WAVE_OUTPUT => %d\n", (signed)wmw->wOutput);
1550c2c66affSColin Finck break;
1551c2c66affSColin Finck /* It is always ok to query wave format parameters,
1552c2c66affSColin Finck * except on auto-open yield MCIERR_UNSUPPORTED_FUNCTION. */
1553c2c66affSColin Finck case MCI_WAVE_STATUS_FORMATTAG:
1554c2c66affSColin Finck if (wmw->lpWaveFormat->wFormatTag != WAVE_FORMAT_PCM)
1555c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->wFormatTag;
1556c2c66affSColin Finck else {
1557c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(WAVE_FORMAT_PCM, WAVE_FORMAT_PCM_S);
1558c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1559c2c66affSColin Finck }
1560c2c66affSColin Finck TRACE("MCI_WAVE_FORMATTAG => %lu\n", lpParms->dwReturn);
1561c2c66affSColin Finck break;
1562c2c66affSColin Finck case MCI_WAVE_STATUS_AVGBYTESPERSEC:
1563c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->nAvgBytesPerSec;
1564c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_AVGBYTESPERSEC => %lu\n", lpParms->dwReturn);
1565c2c66affSColin Finck break;
1566c2c66affSColin Finck case MCI_WAVE_STATUS_BITSPERSAMPLE:
1567c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->wBitsPerSample;
1568c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_BITSPERSAMPLE => %lu\n", lpParms->dwReturn);
1569c2c66affSColin Finck break;
1570c2c66affSColin Finck case MCI_WAVE_STATUS_BLOCKALIGN:
1571c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->nBlockAlign;
1572c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_BLOCKALIGN => %lu\n", lpParms->dwReturn);
1573c2c66affSColin Finck break;
1574c2c66affSColin Finck case MCI_WAVE_STATUS_CHANNELS:
1575c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->nChannels;
1576c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_CHANNELS => %lu\n", lpParms->dwReturn);
1577c2c66affSColin Finck break;
1578c2c66affSColin Finck case MCI_WAVE_STATUS_SAMPLESPERSEC:
1579c2c66affSColin Finck lpParms->dwReturn = wmw->lpWaveFormat->nSamplesPerSec;
1580c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_SAMPLESPERSEC => %lu\n", lpParms->dwReturn);
1581c2c66affSColin Finck break;
1582c2c66affSColin Finck case MCI_WAVE_STATUS_LEVEL:
1583c2c66affSColin Finck TRACE("MCI_WAVE_STATUS_LEVEL !\n");
1584c2c66affSColin Finck lpParms->dwReturn = 0xAAAA5555;
1585c2c66affSColin Finck break;
1586c2c66affSColin Finck default:
1587c2c66affSColin Finck WARN("unknown command %08X !\n", lpParms->dwItem);
1588c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1589c2c66affSColin Finck }
1590c2c66affSColin Finck }
1591c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1592c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1593c2c66affSColin Finck return ret;
1594c2c66affSColin Finck }
1595c2c66affSColin Finck
1596c2c66affSColin Finck /**************************************************************************
1597c2c66affSColin Finck * WAVE_mciGetDevCaps [internal]
1598c2c66affSColin Finck */
WAVE_mciGetDevCaps(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_GETDEVCAPS_PARMS lpParms)1599c2c66affSColin Finck static DWORD WAVE_mciGetDevCaps(MCIDEVICEID wDevID, DWORD dwFlags,
1600c2c66affSColin Finck LPMCI_GETDEVCAPS_PARMS lpParms)
1601c2c66affSColin Finck {
1602c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1603c2c66affSColin Finck DWORD ret = 0;
1604c2c66affSColin Finck
1605c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1606c2c66affSColin Finck
1607c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1608c2c66affSColin Finck if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
1609c2c66affSColin Finck
1610c2c66affSColin Finck if (dwFlags & MCI_GETDEVCAPS_ITEM) {
1611c2c66affSColin Finck switch(lpParms->dwItem) {
1612c2c66affSColin Finck case MCI_GETDEVCAPS_DEVICE_TYPE:
1613c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_WAVEFORM_AUDIO, MCI_DEVTYPE_WAVEFORM_AUDIO);
1614c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1615c2c66affSColin Finck break;
1616c2c66affSColin Finck case MCI_GETDEVCAPS_HAS_AUDIO:
1617c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1618c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1619c2c66affSColin Finck break;
1620c2c66affSColin Finck case MCI_GETDEVCAPS_HAS_VIDEO:
1621c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1622c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1623c2c66affSColin Finck break;
1624c2c66affSColin Finck case MCI_GETDEVCAPS_USES_FILES:
1625c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1626c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1627c2c66affSColin Finck break;
1628c2c66affSColin Finck case MCI_GETDEVCAPS_COMPOUND_DEVICE:
1629c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1630c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1631c2c66affSColin Finck break;
1632c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_RECORD:
1633c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1634c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1635c2c66affSColin Finck break;
1636c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_EJECT:
1637c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
1638c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1639c2c66affSColin Finck break;
1640c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_PLAY:
1641c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1642c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1643c2c66affSColin Finck break;
1644c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_SAVE:
1645c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
1646c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
1647c2c66affSColin Finck break;
1648c2c66affSColin Finck case MCI_WAVE_GETDEVCAPS_INPUTS:
1649c2c66affSColin Finck lpParms->dwReturn = waveInGetNumDevs();
1650c2c66affSColin Finck break;
1651c2c66affSColin Finck case MCI_WAVE_GETDEVCAPS_OUTPUTS:
1652c2c66affSColin Finck lpParms->dwReturn = waveOutGetNumDevs();
1653c2c66affSColin Finck break;
1654c2c66affSColin Finck default:
1655c2c66affSColin Finck FIXME("Unknown capability (%08x) !\n", lpParms->dwItem);
1656c2c66affSColin Finck return MCIERR_UNRECOGNIZED_COMMAND;
1657c2c66affSColin Finck }
1658c2c66affSColin Finck } else {
1659c2c66affSColin Finck WARN("No GetDevCaps-Item !\n");
1660c2c66affSColin Finck return MCIERR_UNRECOGNIZED_COMMAND;
1661c2c66affSColin Finck }
1662c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
1663c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1664c2c66affSColin Finck return ret;
1665c2c66affSColin Finck }
1666c2c66affSColin Finck
1667c2c66affSColin Finck /**************************************************************************
1668c2c66affSColin Finck * WAVE_mciInfo [internal]
1669c2c66affSColin Finck */
WAVE_mciInfo(MCIDEVICEID wDevID,DWORD dwFlags,LPMCI_INFO_PARMSW lpParms)1670c2c66affSColin Finck static DWORD WAVE_mciInfo(MCIDEVICEID wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
1671c2c66affSColin Finck {
1672c2c66affSColin Finck DWORD ret = 0;
1673c2c66affSColin Finck LPCWSTR str = 0;
1674c2c66affSColin Finck WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
1675c2c66affSColin Finck
1676c2c66affSColin Finck TRACE("(%u, %08X, %p);\n", wDevID, dwFlags, lpParms);
1677c2c66affSColin Finck
1678c2c66affSColin Finck if (!lpParms || !lpParms->lpstrReturn)
1679c2c66affSColin Finck return MCIERR_NULL_PARAMETER_BLOCK;
1680c2c66affSColin Finck
1681c2c66affSColin Finck TRACE("buf=%p, len=%u\n", lpParms->lpstrReturn, lpParms->dwRetSize);
1682c2c66affSColin Finck
1683c2c66affSColin Finck if (wmw == NULL) {
1684c2c66affSColin Finck ret = MCIERR_INVALID_DEVICE_ID;
1685c2c66affSColin Finck } else {
1686c2c66affSColin Finck static const WCHAR wszAudio [] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','p','l','a','y','e','r',0};
1687c2c66affSColin Finck static const WCHAR wszWaveIn [] = {'W','i','n','e',' ','W','a','v','e',' ','I','n',0};
1688c2c66affSColin Finck static const WCHAR wszWaveOut[] = {'W','i','n','e',' ','W','a','v','e',' ','O','u','t',0};
1689c2c66affSColin Finck
1690c2c66affSColin Finck switch (dwFlags & ~(MCI_WAIT|MCI_NOTIFY)) {
1691c2c66affSColin Finck case MCI_INFO_PRODUCT: str = wszAudio; break;
1692c2c66affSColin Finck case MCI_INFO_FILE: str = wmw->lpFileName; break;
1693c2c66affSColin Finck case MCI_WAVE_INPUT: str = wszWaveIn; break;
1694c2c66affSColin Finck case MCI_WAVE_OUTPUT: str = wszWaveOut; break;
1695c2c66affSColin Finck default:
1696c2c66affSColin Finck WARN("Don't know this info command (%u)\n", dwFlags);
1697c2c66affSColin Finck ret = MCIERR_UNRECOGNIZED_KEYWORD;
1698c2c66affSColin Finck }
1699c2c66affSColin Finck }
1700c2c66affSColin Finck if (!ret) {
1701c2c66affSColin Finck if (lpParms->dwRetSize) {
1702c2c66affSColin Finck WCHAR zero = 0;
1703c2c66affSColin Finck /* FIXME? Since NT, mciwave, mciseq and mcicda set dwRetSize
1704c2c66affSColin Finck * to the number of characters written, excluding \0. */
1705c2c66affSColin Finck lstrcpynW(lpParms->lpstrReturn, str ? str : &zero, lpParms->dwRetSize);
1706c2c66affSColin Finck } else ret = MCIERR_PARAM_OVERFLOW;
1707c2c66affSColin Finck }
1708c2c66affSColin Finck if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
1709c2c66affSColin Finck WAVE_mciNotify(lpParms->dwCallback, wmw, MCI_NOTIFY_SUCCESSFUL);
1710c2c66affSColin Finck return ret;
1711c2c66affSColin Finck }
1712c2c66affSColin Finck
1713c2c66affSColin Finck /**************************************************************************
1714c2c66affSColin Finck * DriverProc (MCIWAVE.@)
1715c2c66affSColin Finck */
MCIWAVE_DriverProc(DWORD_PTR dwDevID,HDRVR hDriv,UINT wMsg,LPARAM dwParam1,LPARAM dwParam2)1716c2c66affSColin Finck LRESULT CALLBACK MCIWAVE_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1717c2c66affSColin Finck LPARAM dwParam1, LPARAM dwParam2)
1718c2c66affSColin Finck {
1719c2c66affSColin Finck TRACE("(%08lX, %p, %08X, %08lX, %08lX)\n",
1720c2c66affSColin Finck dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1721c2c66affSColin Finck
1722c2c66affSColin Finck switch (wMsg) {
1723c2c66affSColin Finck case DRV_LOAD: return 1;
1724c2c66affSColin Finck case DRV_FREE: return 1;
1725c2c66affSColin Finck case DRV_OPEN: return WAVE_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1726c2c66affSColin Finck case DRV_CLOSE: return WAVE_drvClose(dwDevID);
1727c2c66affSColin Finck case DRV_ENABLE: return 1;
1728c2c66affSColin Finck case DRV_DISABLE: return 1;
1729c2c66affSColin Finck case DRV_QUERYCONFIGURE: return 1;
1730c2c66affSColin Finck case DRV_CONFIGURE: MessageBoxA(0, "MCI waveaudio Driver !", "Wine Driver", MB_OK); return 1;
1731c2c66affSColin Finck case DRV_INSTALL: return DRVCNF_RESTART;
1732c2c66affSColin Finck case DRV_REMOVE: return DRVCNF_RESTART;
1733c2c66affSColin Finck }
1734c2c66affSColin Finck
1735c2c66affSColin Finck if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1736c2c66affSColin Finck
1737c2c66affSColin Finck switch (wMsg) {
1738c2c66affSColin Finck case MCI_OPEN_DRIVER: return WAVE_mciOpen (dwDevID, dwParam1, (LPMCI_WAVE_OPEN_PARMSW) dwParam2);
1739c2c66affSColin Finck case MCI_CLOSE_DRIVER: return WAVE_mciClose (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1740c2c66affSColin Finck case MCI_CUE: return WAVE_mciCue (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1741c2c66affSColin Finck case MCI_PLAY: return WAVE_mciPlay (dwDevID, dwParam1, dwParam2, NULL);
1742c2c66affSColin Finck case MCI_RECORD: return WAVE_mciRecord (dwDevID, dwParam1, dwParam2, NULL);
1743c2c66affSColin Finck case MCI_STOP: return WAVE_mciStop (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1744c2c66affSColin Finck case MCI_SET: return WAVE_mciSet (dwDevID, dwParam1, (LPMCI_WAVE_SET_PARMS) dwParam2);
1745c2c66affSColin Finck case MCI_PAUSE: return WAVE_mciPause (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1746c2c66affSColin Finck case MCI_RESUME: return WAVE_mciResume (dwDevID, dwParam1, (LPMCI_GENERIC_PARMS) dwParam2);
1747c2c66affSColin Finck case MCI_STATUS: return WAVE_mciStatus (dwDevID, dwParam1, (LPMCI_STATUS_PARMS) dwParam2);
1748c2c66affSColin Finck case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
1749c2c66affSColin Finck case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSW) dwParam2);
1750c2c66affSColin Finck case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
1751c2c66affSColin Finck case MCI_SAVE: return WAVE_mciSave (dwDevID, dwParam1, (LPMCI_SAVE_PARMSW) dwParam2);
1752c2c66affSColin Finck /* commands that should be supported */
1753c2c66affSColin Finck case MCI_LOAD:
1754c2c66affSColin Finck case MCI_FREEZE:
1755c2c66affSColin Finck case MCI_PUT:
1756c2c66affSColin Finck case MCI_REALIZE:
1757c2c66affSColin Finck case MCI_UNFREEZE:
1758c2c66affSColin Finck case MCI_UPDATE:
1759c2c66affSColin Finck case MCI_WHERE:
1760c2c66affSColin Finck case MCI_STEP:
1761c2c66affSColin Finck case MCI_SPIN:
1762c2c66affSColin Finck case MCI_ESCAPE:
1763c2c66affSColin Finck case MCI_COPY:
1764c2c66affSColin Finck case MCI_CUT:
1765c2c66affSColin Finck case MCI_DELETE:
1766c2c66affSColin Finck case MCI_PASTE:
1767c2c66affSColin Finck FIXME("Unsupported command [%u]\n", wMsg);
1768c2c66affSColin Finck break;
1769c2c66affSColin Finck case MCI_WINDOW:
1770c2c66affSColin Finck TRACE("Unsupported command [%u]\n", wMsg);
1771c2c66affSColin Finck break;
1772c2c66affSColin Finck /* option which can be silenced */
1773c2c66affSColin Finck case MCI_CONFIGURE:
1774c2c66affSColin Finck return 0;
1775c2c66affSColin Finck case MCI_OPEN:
1776c2c66affSColin Finck case MCI_CLOSE:
1777c2c66affSColin Finck ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1778c2c66affSColin Finck break;
1779c2c66affSColin Finck default:
1780c2c66affSColin Finck FIXME("is probably wrong msg [%u]\n", wMsg);
1781c2c66affSColin Finck return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1782c2c66affSColin Finck }
1783c2c66affSColin Finck return MCIERR_UNRECOGNIZED_COMMAND;
1784c2c66affSColin Finck }
1785