Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
wine
Manage
Activity
Members
Labels
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Terraform modules
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Felix Münchhalfen
wine
Commits
3732965c
Commit
3732965c
authored
24 years ago
by
Francois Jacques
Committed by
Alexandre Julliard
24 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Added asynchronous recording in MCI layer.
parent
d747b76c
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
dlls/winmm/mciwave/mciwave.c
+447
-98
447 additions, 98 deletions
dlls/winmm/mciwave/mciwave.c
with
447 additions
and
98 deletions
dlls/winmm/mciwave/mciwave.c
+
447
−
98
View file @
3732965c
...
...
@@ -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
->
dwFile
Offset
+
wmw
->
dwPosition
,
SEEK_SET
);
/* >= 0 */
mmioSeek
(
wmw
->
hFile
,
wmw
->
ckWaveData
.
dwData
Offset
+
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
:
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment