Skip to content
Snippets Groups Projects
Commit 3732965c authored by Francois Jacques's avatar Francois Jacques Committed by Alexandre Julliard
Browse files

Added asynchronous recording in MCI layer.

parent d747b76c
No related branches found
No related tags found
No related merge requests found
......@@ -4,12 +4,10 @@
*
* Copyright 1994 Martin Ayotte
* 1999 Eric Pouech
*/
/*
* FIXME:
* - record/play should and must be done asynchronous
* 2000 Francois Jacques
*/
#include "winerror.h"
#include "windef.h"
#include "wingdi.h"
#include "winuser.h"
......@@ -31,11 +29,13 @@ typedef struct {
BOOL fInput; /* FALSE = Output, TRUE = Input */
volatile WORD dwStatus; /* one from MCI_MODE_xxxx */
DWORD dwMciTimeFormat;/* One of the supported MCI_FORMAT_xxxx */
DWORD dwFileOffset; /* Offset of chunk in mmio file */
DWORD dwLength; /* number of bytes in chunk for playing */
DWORD dwPosition; /* position in bytes in chunk for playing */
DWORD dwRemaining; /* remaining bytes to play or record */
DWORD dwPosition; /* position in bytes in chunk */
HANDLE hEvent; /* for synchronization */
DWORD dwEventCount; /* for synchronization */
BOOL bTemporaryFile; /* temporary file (MCI_RECORD) */
MMCKINFO ckMainRIFF; /* main RIFF chunk */
MMCKINFO ckWaveData; /* data chunk */
} WINE_MCIWAVE;
/* ===================================================================
......@@ -172,8 +172,8 @@ static WINE_MCIWAVE* WAVE_mciGetOpenDev(UINT wDevID)
*/
static DWORD WAVE_ConvertByteToTimeFormat(WINE_MCIWAVE* wmw, DWORD val, LPDWORD lpRet)
{
DWORD ret = 0;
DWORD ret = 0;
switch (wmw->dwMciTimeFormat) {
case MCI_FORMAT_MILLISECONDS:
ret = (val * 1000) / wmw->lpWaveFormat->nAvgBytesPerSec;
......@@ -245,20 +245,84 @@ static DWORD WAVE_mciReadFmt(WINE_MCIWAVE* wmw, MMCKINFO* pckMainRIFF)
TRACE("cbSize=%u !\n", wmw->lpWaveFormat->cbSize);
mmioAscend(wmw->hFile, &mmckInfo, 0);
mmckInfo.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(wmw->hFile, &mmckInfo, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
wmw->ckWaveData.ckid = mmioFOURCC('d', 'a', 't', 'a');
if (mmioDescend(wmw->hFile, &wmw->ckWaveData, pckMainRIFF, MMIO_FINDCHUNK) != 0) {
TRACE("can't find data chunk\n");
return MCIERR_INVALID_FILE;
}
TRACE("Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
(LPSTR)&mmckInfo.ckid, (LPSTR)&mmckInfo.fccType, mmckInfo.cksize);
(LPSTR)&wmw->ckWaveData.ckid, (LPSTR)&wmw->ckWaveData.fccType, wmw->ckWaveData.cksize);
TRACE("nChannels=%d nSamplesPerSec=%ld\n",
wmw->lpWaveFormat->nChannels, wmw->lpWaveFormat->nSamplesPerSec);
wmw->dwLength = mmckInfo.cksize;
wmw->dwFileOffset = mmckInfo.dwDataOffset;
return 0;
}
/**************************************************************************
* WAVE_mciCreateRIFFSkeleton [internal]
*/
static DWORD WAVE_mciCreateRIFFSkeleton(WINE_MCIWAVE* wmw)
{
MMCKINFO ckWaveFormat;
LPMMCKINFO lpckRIFF = &(wmw->ckMainRIFF);
LPMMCKINFO lpckWaveData = &(wmw->ckWaveData);
LPWAVEFORMATEX lpWaveFormat = wmw->lpWaveFormat;
HMMIO hmmio = wmw->hFile;
lpckRIFF->ckid = FOURCC_RIFF;
lpckRIFF->fccType = mmioFOURCC('W', 'A', 'V', 'E');
lpckRIFF->cksize = 0;
if (MMSYSERR_NOERROR != mmioCreateChunk(hmmio, lpckRIFF, MMIO_CREATERIFF))
goto err;
ckWaveFormat.fccType = 0;
ckWaveFormat.ckid = mmioFOURCC('f', 'm', 't', ' ');
ckWaveFormat.cksize = 16;
if (!lpWaveFormat)
{
TRACE("allocating waveformat with default waveformat 11khz/8bit/mono \n");
lpWaveFormat = wmw->lpWaveFormat = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*lpWaveFormat));
lpWaveFormat->wFormatTag = WAVE_FORMAT_PCM;
lpWaveFormat->nChannels = 1; /* MONO */
lpWaveFormat->nSamplesPerSec = 11025;
lpWaveFormat->nAvgBytesPerSec = 11025;
lpWaveFormat->nBlockAlign = 1;
lpWaveFormat->wBitsPerSample = 8;
lpWaveFormat->cbSize = 0; /* don't care */
}
if (MMSYSERR_NOERROR != mmioCreateChunk(hmmio, &ckWaveFormat, 0))
goto err;
/* only the first 16 bytes are serialized */
if (-1 == mmioWrite(hmmio, (HPCSTR) lpWaveFormat, 16))
goto err;
if (MMSYSERR_NOERROR != mmioAscend(hmmio, &ckWaveFormat, 0))
goto err;
lpckWaveData->cksize = 0;
lpckWaveData->fccType = 0;
lpckWaveData->ckid = mmioFOURCC('d', 'a', 't', 'a');
/* create data chunk */
if (MMSYSERR_NOERROR != mmioCreateChunk(hmmio, lpckWaveData, 0))
goto err;
return 0;
err:
HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
return MCIERR_INVALID_FILE;
}
/**************************************************************************
* WAVE_mciOpen [internal]
*/
......@@ -267,6 +331,7 @@ static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpO
DWORD dwRet = 0;
DWORD dwDeviceID;
WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)mciGetDriverData(wDevID);
CHAR* pszTmpFileName = 0;
TRACE("(%04X, %08lX, %p)\n", wDevID, dwFlags, lpOpenParms);
if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
......@@ -281,12 +346,14 @@ static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpO
*/
return MCIERR_DEVICE_OPEN;
}
wmw->nUseCount++;
dwDeviceID = lpOpenParms->wDeviceID;
wmw->fInput = FALSE;
wmw->hWave = 0;
wmw->dwStatus = MCI_MODE_NOT_READY;
TRACE("wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID, dwDeviceID);
......@@ -297,46 +364,101 @@ static DWORD WAVE_mciOpen(UINT wDevID, DWORD dwFlags, LPMCI_WAVE_OPEN_PARMSA lpO
*/
dwRet = MCIERR_UNRECOGNIZED_COMMAND;
} else {
LPCSTR lpstrElementName = lpOpenParms->lpstrElementName;
if (strlen(lpOpenParms->lpstrElementName) > 0) {
lpOpenParms->lpstrElementName = lpOpenParms->lpstrElementName;
/* FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpOpenParms->lpstrElementName);
if (lpOpenParms->lpstrElementName && (strlen(lpOpenParms->lpstrElementName) > 0)) {
wmw->hFile = mmioOpenA((LPSTR)lpOpenParms->lpstrElementName, NULL,
MMIO_ALLOCBUF | MMIO_DENYWRITE | MMIO_READWRITE);
if (wmw->hFile == 0) {
WARN("can't find file='%s' !\n", lpOpenParms->lpstrElementName);
dwRet = MCIERR_FILE_NOT_FOUND;
}
else
{
LPMMCKINFO lpckMainRIFF = &wmw->ckMainRIFF;
/* make sure we're are the beginning of the file */
mmioSeek(wmw->hFile, 0, SEEK_SET);
/* first reading of this file. read the waveformat chunk */
if (mmioDescend(wmw->hFile, lpckMainRIFF, NULL, 0) != 0) {
dwRet = MCIERR_INVALID_FILE;
} else {
TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
(LPSTR)&(lpckMainRIFF->ckid),
(LPSTR) &(lpckMainRIFF->fccType),
(lpckMainRIFF->cksize));
if ((lpckMainRIFF->ckid != FOURCC_RIFF) ||
lpckMainRIFF->fccType != mmioFOURCC('W', 'A', 'V', 'E')) {
dwRet = MCIERR_INVALID_FILE;
} else {
dwRet = WAVE_mciReadFmt(wmw, lpckMainRIFF);
}
}
}
}
else {
wmw->hFile = 0;
}
}
else {
CHAR szTmpPath[MAX_PATH];
CHAR szPrefix[4] = "TMP\0";
pszTmpFileName = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
MAX_PATH * sizeof(*pszTmpFileName));
if (!GetTempPathA(sizeof(szTmpPath), szTmpPath)) {
WARN("can't retrieve temp path!\n");
HeapFree(GetProcessHeap(), 0, pszTmpFileName);
return MCIERR_FILE_NOT_FOUND;
}
if (!GetTempFileNameA(szTmpPath, szPrefix, 0, pszTmpFileName)) {
WARN("can't retrieve temp file name!\n");
HeapFree(GetProcessHeap(), 0, pszTmpFileName);
return MCIERR_FILE_NOT_FOUND;
}
wmw->bTemporaryFile = TRUE;
TRACE("MCI_OPEN_ELEMENT '%s' !\n", pszTmpFileName);
/*FIXME : what should be done id wmw->hFile is already != 0, or the driver is playin' */
TRACE("MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName);
if (lpstrElementName && (strlen(lpstrElementName) > 0)) {
wmw->hFile = mmioOpenA((LPSTR)lpstrElementName, NULL,
MMIO_ALLOCBUF | MMIO_READ | MMIO_DENYWRITE);
if (wmw->hFile == 0) {
WARN("can't find file='%s' !\n", lpstrElementName);
dwRet = MCIERR_FILE_NOT_FOUND;
if (pszTmpFileName && (strlen(pszTmpFileName) > 0)) {
wmw->hFile = mmioOpenA(pszTmpFileName, NULL,
MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE);
if (wmw->hFile == 0) {
/* temporary file could not be created. clean filename. */
HeapFree(GetProcessHeap(), 0, pszTmpFileName);
WARN("can't create file='%s' !\n", pszTmpFileName);
dwRet = MCIERR_FILE_NOT_FOUND;
}
}
} else {
wmw->hFile = 0;
}
}
}
}
TRACE("hFile=%u\n", wmw->hFile);
memcpy(&wmw->openParms, lpOpenParms, sizeof(MCI_WAVE_OPEN_PARMSA));
if (wmw->bTemporaryFile == TRUE)
{
/* Additional openParms is temporary file's name */
wmw->openParms.lpstrElementName = pszTmpFileName;
}
wmw->wNotifyDeviceID = dwDeviceID;
wmw->dwStatus = MCI_MODE_NOT_READY; /* while loading file contents */
if (dwRet == 0 && wmw->hFile != 0) {
MMCKINFO ckMainRIFF;
if (mmioDescend(wmw->hFile, &ckMainRIFF, NULL, 0) != 0) {
dwRet = MCIERR_INVALID_FILE;
} else {
TRACE("ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
(LPSTR)&ckMainRIFF.ckid, (LPSTR)&ckMainRIFF.fccType, ckMainRIFF.cksize);
if ((ckMainRIFF.ckid != FOURCC_RIFF) ||
(ckMainRIFF.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) {
dwRet = MCIERR_INVALID_FILE;
} else {
dwRet = WAVE_mciReadFmt(wmw, &ckMainRIFF);
}
}
} else {
wmw->dwLength = 0;
}
if (dwRet == 0) {
if (wmw->lpWaveFormat) {
switch (wmw->lpWaveFormat->wFormatTag) {
......@@ -475,6 +597,16 @@ static DWORD WAVE_mciClose(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpPar
wmw->hFile = 0;
}
}
/* That string got allocated in mciOpen because no filename was specified
* in MCI_OPEN_PARMS stucture. Cast-away const from string since it was
* allocated by mciOpen, *NOT* the application.
*/
if (wmw->bTemporaryFile)
{
HeapFree(GetProcessHeap(), 0, (CHAR*) wmw->openParms.lpstrElementName);
wmw->openParms.lpstrElementName = NULL;
}
HeapFree(GetProcessHeap(), 0, wmw->lpWaveFormat);
wmw->lpWaveFormat = NULL;
......@@ -535,26 +667,31 @@ static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
LPWAVEHDR waveHdr = NULL;
WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
int whidx;
TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
/* FIXME : since there is no way to determine in which mode the device is
* open (recording/playback) automatically switch from a mode to another
*/
wmw->fInput = FALSE;
if (wmw->fInput) {
WARN("cannot play on input device\n");
return MCIERR_NONAPPLICABLE_FUNCTION;
}
if (wmw->hFile == 0) {
WARN("Can't play: no file='%s' !\n", wmw->openParms.lpstrElementName);
return MCIERR_FILE_NOT_FOUND;
}
if (wmw->dwStatus == MCI_MODE_PAUSE) {
/* FIXME: parameters (start/end) in lpParams may not be used */
return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
}
if (wmw->dwStatus == MCI_MODE_PAUSE) {
/* FIXME: parameters (start/end) in lpParams may not be used */
return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
}
/** This function will be called again by a thread when async is used.
* We have to set MCI_MODE_PLAY before we do this so that the app can spin
......@@ -584,18 +721,43 @@ static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
if (end <= wmw->dwPosition)
return TRUE;
#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
wmw->dwLength = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwLength);
wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
if (dwRet == 0) {
if (wmw->lpWaveFormat) {
switch (wmw->lpWaveFormat->wFormatTag) {
case WAVE_FORMAT_PCM:
if (wmw->lpWaveFormat->nAvgBytesPerSec !=
wmw->lpWaveFormat->nSamplesPerSec * wmw->lpWaveFormat->nBlockAlign) {
WARN("Incorrect nAvgBytesPerSec (%ld), setting it to %ld\n",
wmw->lpWaveFormat->nAvgBytesPerSec,
wmw->lpWaveFormat->nSamplesPerSec *
wmw->lpWaveFormat->nBlockAlign);
wmw->lpWaveFormat->nAvgBytesPerSec =
wmw->lpWaveFormat->nSamplesPerSec *
wmw->lpWaveFormat->nBlockAlign;
}
break;
}
}
} else {
TRACE("can't retrieve wave format %ld\n", dwRet);
goto cleanUp;
}
/* go back to begining of chunk plus the requested position */
/* FIXME: I'm not sure this is correct, notably because some data linked to
* the decompression state machine will not be correcly initialized.
* try it this way (other way would be to decompress from 0 up to dwPosition
* and to start sending to hWave when dwPosition is reached)
*/
mmioSeek(wmw->hFile, wmw->dwFileOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
/* By default the device will be opened for output, the MCI_CUE function is there to
* change from output to input and back
......@@ -628,7 +790,7 @@ static DWORD WAVE_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
}
whidx = 0;
left = min(wmw->dwLength, end - wmw->dwPosition);
left = min(wmw->ckWaveData.cksize, end - wmw->dwPosition);
wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
wmw->dwEventCount = 1L; /* for first buffer */
......@@ -687,64 +849,212 @@ cleanUp:
return dwRet;
}
/**************************************************************************
* WAVE_mciPlayCallback [internal]
*/
static void CALLBACK WAVE_mciRecordCallback(HWAVEOUT hwo, UINT uMsg,
DWORD dwInstance,
DWORD dwParam1, DWORD dwParam2)
{
WINE_MCIWAVE* wmw = (WINE_MCIWAVE*)dwInstance;
LPWAVEHDR lpWaveHdr = NULL;
LONG count = 0;
switch (uMsg) {
case WIM_OPEN:
case WIM_CLOSE:
break;
case WIM_DATA:
lpWaveHdr = (LPWAVEHDR) dwParam1;
InterlockedIncrement(&wmw->dwEventCount);
count = mmioWrite(wmw->hFile, lpWaveHdr->lpData, lpWaveHdr->dwBytesRecorded);
lpWaveHdr->dwFlags &= ~WHDR_DONE;
wmw->dwPosition += count;
wmw->dwRemaining -= count;
waveInAddBuffer(wmw->hWave, lpWaveHdr, sizeof(*lpWaveHdr));
TRACE("after mmioWrite dwPosition=%lu\n", wmw->dwPosition);
SetEvent(wmw->hEvent);
break;
default:
ERR("Unknown uMsg=%d\n", uMsg);
}
}
static void WAVE_mciRecordWaitDone(WINE_MCIWAVE* wmw)
{
for (;;) {
ResetEvent(wmw->hEvent);
if (InterlockedDecrement(&wmw->dwEventCount) >= 0) {
break;
}
InterlockedIncrement(&wmw->dwEventCount);
WaitForSingleObject(wmw->hEvent, INFINITE);
}
}
/**************************************************************************
* WAVE_mciRecord [internal]
*/
static DWORD WAVE_mciRecord(UINT wDevID, DWORD dwFlags, LPMCI_RECORD_PARMS lpParms)
{
int start, end;
LONG bufsize;
WAVEHDR waveHdr;
DWORD dwRet;
DWORD end;
DWORD dwRet = 0;
LONG bufsize;
LPWAVEHDR waveHdr = NULL;
WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
TRACE("(%u, %08lX, %p);\n", wDevID, dwFlags, lpParms);
if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
/* FIXME : since there is no way to determine in which mode the device is
* open (recording/playback) automatically switch from a mode to another
*/
wmw->fInput = TRUE;
if (!wmw->fInput) {
WARN("cannot record on output device\n");
return MCIERR_NONAPPLICABLE_FUNCTION;
}
if (wmw->dwStatus == MCI_MODE_PAUSE) {
/* FIXME: parameters (start/end) in lpParams may not be used */
return WAVE_mciResume(wDevID, dwFlags, (LPMCI_GENERIC_PARMS)lpParms);
}
if (wmw->hFile == 0) {
WARN("can't find file='%s' !\n",
wmw->openParms.lpstrElementName);
return MCIERR_FILE_NOT_FOUND;
/** This function will be called again by a thread when async is used.
* We have to set MCI_MODE_PLAY before we do this so that the app can spin
* on MCI_STATUS, so we have to allow it here if we're not going to start this thread.
*/
if ((wmw->dwStatus != MCI_MODE_STOP) && ((wmw->dwStatus != MCI_MODE_RECORD) && (dwFlags & MCI_WAIT))) {
return MCIERR_INTERNAL;
}
start = 1; end = 99999;
if (dwFlags & MCI_FROM) {
start = lpParms->dwFrom;
TRACE("MCI_FROM=%d \n", start);
}
if (dwFlags & MCI_TO) {
end = lpParms->dwTo;
TRACE("MCI_TO=%d \n", end);
}
bufsize = 64000;
waveHdr.lpData = HeapAlloc(GetProcessHeap(), 0, bufsize);
waveHdr.dwBufferLength = bufsize;
waveHdr.dwUser = 0L;
waveHdr.dwFlags = 0L;
waveHdr.dwLoops = 0L;
dwRet = waveInPrepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
for (;;) { /* FIXME: I don't see any waveInAddBuffer ? */
waveHdr.dwBytesRecorded = 0;
dwRet = waveInStart(wmw->hWave);
TRACE("waveInStart => lpWaveHdr=%p dwBytesRecorded=%lu\n",
&waveHdr, waveHdr.dwBytesRecorded);
if (waveHdr.dwBytesRecorded == 0) break;
}
dwRet = waveInUnprepareHeader(wmw->hWave, &waveHdr, sizeof(WAVEHDR));
HeapFree(GetProcessHeap(), 0, waveHdr.lpData);
if (dwFlags & MCI_NOTIFY) {
wmw->dwStatus = MCI_MODE_RECORD;
if (!(dwFlags & MCI_WAIT)) {
return MCI_SendCommandAsync(wmw->wNotifyDeviceID, MCI_RECORD, dwFlags,
(DWORD)lpParms, sizeof(MCI_RECORD_PARMS));
}
if (!wmw->lpWaveFormat)
{
/* new RIFF file */
dwRet = WAVE_mciCreateRIFFSkeleton(wmw);
}
end = 0xFFFFFFFF;
if (lpParms && (dwFlags & MCI_FROM)) {
wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwFrom);
}
if (lpParms && (dwFlags & MCI_TO)) {
end = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
}
TRACE("Recording from byte=%lu to byte=%lu\n", wmw->dwPosition, end);
if (end <= wmw->dwPosition)
{
return TRUE;
}
#define WAVE_ALIGN_ON_BLOCK(wmw,v) \
((((v) + (wmw)->lpWaveFormat->nBlockAlign - 1) / (wmw)->lpWaveFormat->nBlockAlign) * (wmw)->lpWaveFormat->nBlockAlign)
wmw->dwPosition = WAVE_ALIGN_ON_BLOCK(wmw, wmw->dwPosition);
wmw->ckWaveData.cksize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->ckWaveData.cksize);
/* go back to begining of chunk plus the requested position */
/* FIXME: I'm not sure this is correct, notably because some data linked to
* the decompression state machine will not be correcly initialized.
* try it this way (other way would be to decompress from 0 up to dwPosition
* and to start sending to hWave when dwPosition is reached)
*/
mmioSeek(wmw->hFile, wmw->ckWaveData.dwDataOffset + wmw->dwPosition, SEEK_SET); /* >= 0 */
/* By default the device will be opened for output, the MCI_CUE function is there to
* change from output to input and back
*/
/* FIXME: how to choose between several output channels ? here mapper is forced */
dwRet = waveInOpen(&wmw->hWave, WAVE_MAPPER, wmw->lpWaveFormat,
(DWORD)WAVE_mciRecordCallback, (DWORD)wmw, CALLBACK_FUNCTION);
if (dwRet != 0) {
TRACE("Can't open low level audio device %ld\n", dwRet);
dwRet = MCIERR_DEVICE_OPEN;
wmw->hWave = 0;
goto cleanUp;
}
/* make it so that 3 buffers per second are needed */
bufsize = WAVE_ALIGN_ON_BLOCK(wmw, wmw->lpWaveFormat->nAvgBytesPerSec / 3);
waveHdr = HeapAlloc(GetProcessHeap(), 0, 2 * sizeof(WAVEHDR) + 2 * bufsize);
waveHdr[0].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR);
waveHdr[1].lpData = (char*)waveHdr + 2 * sizeof(WAVEHDR) + bufsize;
waveHdr[0].dwUser = waveHdr[1].dwUser = 0L;
waveHdr[0].dwLoops = waveHdr[1].dwLoops = 0L;
waveHdr[0].dwFlags = waveHdr[1].dwFlags = 0L;
waveHdr[0].dwBufferLength = waveHdr[1].dwBufferLength = bufsize;
if (waveInPrepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
waveInPrepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
dwRet = MCIERR_INTERNAL;
goto cleanUp;
}
if (waveInAddBuffer(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR)) ||
waveInAddBuffer(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR))) {
dwRet = MCIERR_INTERNAL;
goto cleanUp;
}
wmw->hEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
wmw->dwEventCount = 1L; /* for first buffer */
wmw->dwRemaining = end - wmw->dwPosition;
TRACE("Recording (normalized) from byte=%lu for %lu bytes\n", wmw->dwPosition, wmw->dwRemaining);
dwRet = waveInStart(wmw->hWave);
while ( wmw->dwRemaining > 0 && wmw->dwStatus != MCI_MODE_STOP && wmw->dwStatus != MCI_MODE_NOT_READY) {
WAVE_mciRecordWaitDone(wmw);
}
waveInReset(wmw->hWave);
waveInUnprepareHeader(wmw->hWave, &waveHdr[0], sizeof(WAVEHDR));
waveInUnprepareHeader(wmw->hWave, &waveHdr[1], sizeof(WAVEHDR));
dwRet = 0;
cleanUp:
HeapFree(GetProcessHeap(), 0, waveHdr);
if (wmw->hWave) {
waveInClose(wmw->hWave);
wmw->hWave = 0;
}
CloseHandle(wmw->hEvent);
if (lpParms && (dwFlags & MCI_NOTIFY)) {
mciDriverNotify((HWND)LOWORD(lpParms->dwCallback),
wmw->wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
wmw->wNotifyDeviceID,
dwRet ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
}
return 0;
wmw->dwStatus = MCI_MODE_STOP;
return dwRet;
}
/**************************************************************************
......@@ -811,7 +1121,7 @@ static DWORD WAVE_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
if (dwFlags & MCI_SEEK_TO_START) {
wmw->dwPosition = 0;
} else if (dwFlags & MCI_SEEK_TO_END) {
wmw->dwPosition = wmw->dwLength;
wmw->dwPosition = wmw->ckWaveData.cksize;
} else if (dwFlags & MCI_TO) {
wmw->dwPosition = WAVE_ConvertTimeFormatToByte(wmw, lpParms->dwTo);
} else {
......@@ -912,6 +1222,45 @@ static DWORD WAVE_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
return 0;
}
/**************************************************************************
* WAVE_mciSave [internal]
*/
static DWORD WAVE_mciSave(UINT wDevID, DWORD dwFlags, LPMCI_SAVE_PARMS lpParms)
{
WINE_MCIWAVE* wmw = WAVE_mciGetOpenDev(wDevID);
DWORD ret = MCIERR_FILE_NOT_SAVED;
WPARAM wparam = MCI_NOTIFY_FAILURE;
TRACE("%d, %08lX, %p);\n", wDevID, dwFlags, lpParms);
if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
if (wmw == NULL) return MCIERR_INVALID_DEVICE_ID;
if (dwFlags & MCI_WAIT)
{
FIXME("MCI_WAIT not implemented\n");
}
ret = mmioAscend(wmw->hFile, &wmw->ckWaveData, 0);
ret = mmioAscend(wmw->hFile, &wmw->ckMainRIFF, 0);
ret = mmioClose(wmw->hFile, 0);
if (0 == mmioRenameA(wmw->openParms.lpstrElementName, lpParms->lpfilename, 0, 0 )) {
ret = ERROR_SUCCESS;
}
if (dwFlags & MCI_NOTIFY) {
if (ret == ERROR_SUCCESS) wparam = MCI_NOTIFY_SUCCESSFUL;
mciDriverNotify( (HWND) LOWORD(lpParms->dwCallback),
wmw->wNotifyDeviceID,
wparam);
}
return ret;
}
/**************************************************************************
* WAVE_mciStatus [internal]
*/
......@@ -936,7 +1285,7 @@ static DWORD WAVE_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpPar
return MCIERR_UNSUPPORTED_FUNCTION;
}
/* only one track in file is currently handled, so don't take care of MCI_TRACK flag */
lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->dwLength, &ret);
lpParms->dwReturn = WAVE_ConvertByteToTimeFormat(wmw, wmw->ckWaveData.cksize, &ret);
TRACE("MCI_STATUS_LENGTH => %lu\n", lpParms->dwReturn);
break;
case MCI_STATUS_MODE:
......@@ -1209,9 +1558,9 @@ LONG CALLBACK MCIWAVE_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
case MCI_GETDEVCAPS: return WAVE_mciGetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS) dwParam2);
case MCI_INFO: return WAVE_mciInfo (dwDevID, dwParam1, (LPMCI_INFO_PARMSA) dwParam2);
case MCI_SEEK: return WAVE_mciSeek (dwDevID, dwParam1, (LPMCI_SEEK_PARMS) dwParam2);
case MCI_SAVE: return WAVE_mciSave (dwDevID, dwParam1, (LPMCI_SAVE_PARMS) dwParam2);
/* commands that should be supported */
case MCI_LOAD:
case MCI_SAVE:
case MCI_FREEZE:
case MCI_PUT:
case MCI_REALIZE:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment