Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
ed69f0bf
Commit
ed69f0bf
authored
Jan 09, 2004
by
Jeremy Shaw
Committed by
Alexandre Julliard
Jan 09, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added wave-in support and fixed a few bugs in the wave-out code.
parent
19dfc3ce
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1629 additions
and
181 deletions
+1629
-181
audio.c
dlls/winmm/winearts/audio.c
+696
-51
winearts.drv.spec
dlls/winmm/winearts/winearts.drv.spec
+1
-0
audio.c
dlls/winmm/winejack/audio.c
+931
-130
winejack.drv.spec
dlls/winmm/winejack/winejack.drv.spec
+1
-0
No files found.
dlls/winmm/winearts/audio.c
View file @
ed69f0bf
...
...
@@ -32,8 +32,7 @@
* FIXME:
* pause in waveOut does not work correctly in loop mode
*
* TODO:
* implement wave-in support with artsc
* does something need to be done in for WaveIn DirectSound?
*/
/*#define EMULATE_SB16*/
...
...
@@ -65,10 +64,32 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave);
#include <artsc.h>
#define BUFFER_SIZE 16 * 1024
#define SPACE_THRESHOLD 5 * 1024
/* The following four #defines allow you to fine-tune the packet
* settings in arts for better low-latency support. You must also
* adjust the latency in the KDE arts control panel. I recommend 4
* fragments, 1024 bytes.
*
* The following is from the ARTS documentation and explains what CCCC
* and SSSS mean:
*
* @li ARTS_P_PACKET_SETTINGS (rw) This is a way to configure packet
* size & packet count at the same time. The format is 0xCCCCSSSS,
* where 2^SSSS is the packet size, and CCCC is the packet count. Note
* that when writing this, you don't necessarily get the settings you
* requested.
*/
#define WAVEOUT_PACKET_CCCC 0x000C
#define WAVEOUT_PACKET_SSSS 0x0008
#define WAVEIN_PACKET_CCCC 0x000C
#define WAVEIN_PACKET_SSSS 0x0008
#define BUFFER_REFILL_THRESHOLD 4
#define WAVEOUT_PACKET_SETTINGS ((WAVEOUT_PACKET_CCCC << 16) | (WAVEOUT_PACKET_SSSS))
#define WAVEIN_PACKET_SETTINGS ((WAVEIN_PACKET_CCCC << 16) | (WAVEIN_PACKET_SSSS))
#define MAX_WAVEOUTDRV (10)
#define MAX_WAVEINDRV (10)
/* state diagram for waveOut writing:
*
...
...
@@ -96,7 +117,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave);
/* events to be send to device */
enum
win_wm_message
{
WINE_WM_PAUSING
=
WM_USER
+
1
,
WINE_WM_RESTARTING
,
WINE_WM_RESETTING
,
WINE_WM_HEADER
,
WINE_WM_UPDATE
,
WINE_WM_BREAKLOOP
,
WINE_WM_CLOSING
WINE_WM_UPDATE
,
WINE_WM_BREAKLOOP
,
WINE_WM_CLOSING
,
WINE_WM_STARTING
,
WINE_WM_STOPPING
};
typedef
struct
{
...
...
@@ -126,14 +147,16 @@ typedef struct {
PCMWAVEFORMAT
format
;
WAVEOUTCAPSA
caps
;
DWORD
dwSleepTime
;
/* Num of milliseconds to sleep between filling the dsp buffers */
/* arts information */
arts_stream_t
play_stream
;
/* the stream structure we get from arts when opening a stream for playing */
DWORD
dwBufferSize
;
/* size of whole buffer in bytes */
int
packetSettings
;
char
*
sound_buffer
;
long
buffer_size
;
DWORD
volume_left
;
/* volume control information */
DWORD
volume_right
;
...
...
@@ -154,7 +177,29 @@ typedef struct {
ARTS_MSG_RING
msgRing
;
}
WINE_WAVEOUT
;
typedef
struct
{
volatile
int
state
;
/* one of the WINE_WS_ manifest constants */
WAVEOPENDESC
waveDesc
;
WORD
wFlags
;
PCMWAVEFORMAT
format
;
WAVEINCAPSA
caps
;
/* arts information */
arts_stream_t
record_stream
;
/* the stream structure we get from arts when opening a stream for recording */
int
packetSettings
;
LPWAVEHDR
lpQueuePtr
;
DWORD
dwRecordedTotal
;
/* synchronization stuff */
HANDLE
hStartUpEvent
;
HANDLE
hThread
;
DWORD
dwThreadID
;
ARTS_MSG_RING
msgRing
;
}
WINE_WAVEIN
;
static
WINE_WAVEOUT
WOutDev
[
MAX_WAVEOUTDRV
];
static
WINE_WAVEIN
WInDev
[
MAX_WAVEINDRV
];
static
DWORD
wodDsCreate
(
UINT
wDevID
,
PIDSDRIVER
*
drv
);
static
DWORD
wodDsDesc
(
UINT
wDevID
,
PDSDRIVERDESC
desc
);
...
...
@@ -169,6 +214,8 @@ static const char *wodPlayerCmdString[] = {
"WINE_WM_UPDATE"
,
"WINE_WM_BREAKLOOP"
,
"WINE_WM_CLOSING"
,
"WINE_WM_STARTING"
,
"WINE_WM_STOPPING"
,
};
/*======================================================================*
...
...
@@ -229,22 +276,35 @@ void volume_effect8(void *bufin, void* bufout, int length, int left,
}
/******************************************************************
* ARTS_CloseDevice
* ARTS_Close
WaveOut
Device
*
*/
void
ARTS_CloseDevice
(
WINE_WAVEOUT
*
wwo
)
void
ARTS_Close
WaveOut
Device
(
WINE_WAVEOUT
*
wwo
)
{
arts_close_stream
(
wwo
->
play_stream
);
/* close the arts stream */
wwo
->
play_stream
=
(
arts_stream_t
*
)
-
1
;
/* free up the buffer we use for volume and reset the size */
if
(
wwo
->
sound_buffer
)
{
HeapFree
(
GetProcessHeap
(),
0
,
wwo
->
sound_buffer
);
wwo
->
sound_buffer
=
NULL
;
}
wwo
->
buffer_size
=
0
;
}
/******************************************************************
* ARTS_CloseWaveInDevice
*
*/
void
ARTS_CloseWaveInDevice
(
WINE_WAVEIN
*
wwi
)
{
arts_close_stream
(
wwi
->
record_stream
);
/* close the arts stream */
wwi
->
record_stream
=
(
arts_stream_t
*
)
-
1
;
}
/******************************************************************
* ARTS_Init
*/
static
int
ARTS_Init
(
void
)
...
...
@@ -264,7 +324,15 @@ LONG ARTS_WaveClose(void)
{
if
(
WOutDev
[
iDevice
].
play_stream
!=
(
arts_stream_t
*
)
-
1
)
{
ARTS_CloseDevice
(
&
WOutDev
[
iDevice
]);
ARTS_CloseWaveOutDevice
(
&
WOutDev
[
iDevice
]);
}
}
for
(
iDevice
=
0
;
iDevice
<
MAX_WAVEINDRV
;
iDevice
++
)
{
if
(
WInDev
[
iDevice
].
record_stream
!=
(
arts_stream_t
*
)
-
1
)
{
ARTS_CloseWaveInDevice
(
&
WInDev
[
iDevice
]);
}
}
...
...
@@ -331,7 +399,44 @@ LONG ARTS_WaveInit(void)
WOutDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1S16
;
}
for
(
i
=
0
;
i
<
MAX_WAVEINDRV
;
++
i
)
{
WInDev
[
i
].
record_stream
=
(
arts_stream_t
*
)
-
1
;
memset
(
&
WInDev
[
i
].
caps
,
0
,
sizeof
(
WInDev
[
i
].
caps
));
/* zero out
caps values */
/* FIXME: some programs compare this string against the content of the registry
* for MM drivers. The names have to match in order for the program to work
* (e.g. MS win9x mplayer.exe)
*/
#ifdef EMULATE_SB16
WInDev
[
i
].
caps
.
wMid
=
0x0002
;
WInDev
[
i
].
caps
.
wPid
=
0x0104
;
strcpy
(
WInDev
[
i
].
caps
.
szPname
,
"SB16 Wave In"
);
#else
WInDev
[
i
].
caps
.
wMid
=
0x00FF
;
WInDev
[
i
].
caps
.
wPid
=
0x0001
;
strcpy
(
WInDev
[
i
].
caps
.
szPname
,
"CS4236/37/38"
);
#endif
WInDev
[
i
].
caps
.
vDriverVersion
=
0x0100
;
WInDev
[
i
].
caps
.
dwFormats
=
0x00000000
;
WInDev
[
i
].
caps
.
wChannels
=
2
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4M08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4S08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4S16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4M16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2M08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2S08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2M16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2S16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1M08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1S08
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1M16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1S16
;
WInDev
[
i
].
caps
.
wReserved1
=
0
;
}
return
0
;
}
...
...
@@ -360,6 +465,7 @@ static int ARTS_DestroyRingMessage(ARTS_MSG_RING* mr)
{
CloseHandle
(
mr
->
msg_event
);
HeapFree
(
GetProcessHeap
(),
0
,
mr
->
messages
);
mr
->
messages
=
NULL
;
DeleteCriticalSection
(
&
mr
->
msg_crst
);
return
0
;
}
...
...
@@ -376,9 +482,22 @@ static int ARTS_AddRingMessage(ARTS_MSG_RING* mr, enum win_wm_message msg, DWORD
EnterCriticalSection
(
&
mr
->
msg_crst
);
if
((
mr
->
msg_toget
==
((
mr
->
msg_tosave
+
1
)
%
mr
->
ring_buffer_size
)))
{
int
old_ring_buffer_size
=
mr
->
ring_buffer_size
;
mr
->
ring_buffer_size
+=
ARTS_RING_BUFFER_INCREMENT
;
TRACE
(
"mr->ring_buffer_size=%d
\n
"
,
mr
->
ring_buffer_size
);
mr
->
messages
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
mr
->
messages
,
mr
->
ring_buffer_size
*
sizeof
(
RING_MSG
));
/* Now we need to rearrange the ring buffer so that the new
buffers just allocated are in between mr->msg_tosave and
mr->msg_toget.
*/
if
(
mr
->
msg_tosave
<
mr
->
msg_toget
)
{
memmove
(
&
(
mr
->
messages
[
mr
->
msg_toget
+
ARTS_RING_BUFFER_INCREMENT
]),
&
(
mr
->
messages
[
mr
->
msg_toget
]),
sizeof
(
RING_MSG
)
*
(
old_ring_buffer_size
-
mr
->
msg_toget
)
);
mr
->
msg_toget
+=
ARTS_RING_BUFFER_INCREMENT
;
}
}
if
(
wait
)
{
...
...
@@ -554,25 +673,6 @@ static LPWAVEHDR wodPlayer_PlayPtrNext(WINE_WAVEOUT* wwo)
}
/**************************************************************************
* wodPlayer_DSPWait [internal]
* Returns the number of milliseconds to wait for the DSP buffer to clear.
* This is based on the number of fragments we want to be clear before
* writing and the number of free fragments we already have.
*/
static
DWORD
wodPlayer_DSPWait
(
const
WINE_WAVEOUT
*
wwo
)
{
int
waitvalue
=
(
wwo
->
dwBufferSize
-
arts_stream_get
(
wwo
->
play_stream
,
ARTS_P_BUFFER_SPACE
))
/
((
wwo
->
format
.
wf
.
nSamplesPerSec
*
wwo
->
format
.
wBitsPerSample
*
wwo
->
format
.
wf
.
nChannels
)
/
1000
);
TRACE
(
"wait value of %d
\n
"
,
waitvalue
);
/* return the time left to play the buffer */
return
waitvalue
;
}
/**************************************************************************
* wodPlayer_NotifyWait [internal]
* Returns the number of milliseconds to wait before attempting to notify
* completion of the specified wavehdr.
...
...
@@ -618,7 +718,10 @@ static int wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes)
if
(
wwo
->
buffer_size
<
toWrite
)
{
if
(
wwo
->
sound_buffer
)
HeapFree
(
GetProcessHeap
(),
0
,
wwo
->
sound_buffer
);
{
HeapRealloc
(
GetProcessHeap
(),
0
,
wwo
->
sound_buffer
,
toWrite
);
wwo
->
buffer_size
=
toWrite
;
}
}
/* if we don't have a buffer then get one */
...
...
@@ -664,14 +767,22 @@ static int wodPlayer_WriteMaxFrags(WINE_WAVEOUT* wwo, DWORD* bytes)
TRACE
(
"written = %d
\n
"
,
written
);
if
(
written
<=
0
)
return
written
;
/* if we wrote nothing just return */
if
(
written
<=
0
)
{
*
bytes
=
0
;
/* apparently arts is actually full */
return
written
;
/* if we wrote nothing just return */
}
if
(
written
>=
dwLength
)
wodPlayer_PlayPtrNext
(
wwo
);
/* If we wrote all current wavehdr, skip to the next one */
else
wwo
->
dwPartialOffset
+=
written
;
/* Remove the amount written */
*
bytes
-=
written
;
if
(
written
<
toWrite
)
*
bytes
=
0
;
else
*
bytes
-=
written
;
wwo
->
dwWrittenTotal
+=
written
;
/* update stats on this wave device */
return
written
;
/* return the number of bytes written */
...
...
@@ -690,6 +801,23 @@ static DWORD wodPlayer_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
{
LPWAVEHDR
lpWaveHdr
;
if
(
wwo
->
lpQueuePtr
)
{
TRACE
(
"lpWaveHdr=(%p), lpPlayPtr=(%p), lpLoopPtr=(%p), reserved=(%ld), dwWrittenTotal=(%ld), force=(%d)
\n
"
,
wwo
->
lpQueuePtr
,
wwo
->
lpPlayPtr
,
wwo
->
lpLoopPtr
,
wwo
->
lpQueuePtr
->
reserved
,
wwo
->
dwWrittenTotal
,
force
);
}
else
{
TRACE
(
"lpWaveHdr=(%p), lpPlayPtr=(%p), lpLoopPtr=(%p), dwWrittenTotal=(%ld), force=(%d)
\n
"
,
wwo
->
lpQueuePtr
,
wwo
->
lpPlayPtr
,
wwo
->
lpLoopPtr
,
wwo
->
dwWrittenTotal
,
force
);
}
/* Start from lpQueuePtr and keep notifying until:
* - we hit an unwritten wavehdr
* - we hit the beginning of a running loop
...
...
@@ -699,7 +827,7 @@ static DWORD wodPlayer_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
(
force
||
(
lpWaveHdr
!=
wwo
->
lpPlayPtr
&&
lpWaveHdr
!=
wwo
->
lpLoopPtr
&&
lpWaveHdr
->
reserved
<=
wwo
->
dwPlayed
Total
)))
{
lpWaveHdr
->
reserved
<=
wwo
->
dwWritten
Total
)))
{
wwo
->
lpQueuePtr
=
lpWaveHdr
->
lpNext
;
...
...
@@ -854,10 +982,9 @@ static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo)
availInQ
=
arts_stream_get
(
wwo
->
play_stream
,
ARTS_P_BUFFER_SPACE
);
TRACE
(
"availInQ = %ld
\n
"
,
availInQ
);
/* input queue empty
and output buffer with no space
*/
if
(
!
wwo
->
lpPlayPtr
&&
availInQ
)
{
/* input queue empty */
if
(
!
wwo
->
lpPlayPtr
)
{
TRACE
(
"Run out of wavehdr:s... flushing
\n
"
);
wwo
->
dwPlayedTotal
=
wwo
->
dwWrittenTotal
;
return
INFINITE
;
}
...
...
@@ -865,7 +992,7 @@ static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo)
if
(
!
availInQ
)
{
TRACE
(
"no more room, no need to try to feed
\n
"
);
return
w
odPlayer_DSPWait
(
wwo
)
;
return
w
wo
->
dwSleepTime
;
}
/* Feed from partial wavehdr */
...
...
@@ -878,16 +1005,26 @@ static DWORD wodPlayer_FeedDSP(WINE_WAVEOUT* wwo)
/* Feed wavehdrs until we run out of wavehdrs or DSP space */
if
(
!
wwo
->
dwPartialOffset
)
{
while
(
wwo
->
lpPlayPtr
&&
availInQ
>
SPACE_THRESHOLD
)
{
TRACE
(
"feeding waveheaders until we run out of space
\n
"
);
/* note the value that dwPlayedTotal will return when this wave finishes playing */
wwo
->
lpPlayPtr
->
reserved
=
wwo
->
dwWrittenTotal
+
wwo
->
lpPlayPtr
->
dwBufferLength
;
wodPlayer_WriteMaxFrags
(
wwo
,
&
availInQ
);
}
while
(
wwo
->
lpPlayPtr
&&
availInQ
)
{
TRACE
(
"feeding waveheaders until we run out of space
\n
"
);
/* note the value that dwPlayedTotal will return when this wave finishes playing */
wwo
->
lpPlayPtr
->
reserved
=
wwo
->
dwWrittenTotal
+
wwo
->
lpPlayPtr
->
dwBufferLength
;
TRACE
(
"reserved=(%ld) dwWrittenTotal=(%ld) dwBufferLength=(%ld)
\n
"
,
wwo
->
lpPlayPtr
->
reserved
,
wwo
->
dwWrittenTotal
,
wwo
->
lpPlayPtr
->
dwBufferLength
);
wodPlayer_WriteMaxFrags
(
wwo
,
&
availInQ
);
}
}
if
(
!
wwo
->
lpPlayPtr
)
{
TRACE
(
"Ran out of wavehdrs
\n
"
);
return
INFINITE
;
}
return
w
odPlayer_DSPWait
(
wwo
)
;
return
w
wo
->
dwSleepTime
;
}
...
...
@@ -1010,14 +1147,19 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
if
(
!
wwo
->
play_stream
)
return
MMSYSERR_ALLOCATED
;
/* Try to set buffer size from constant and store the value that it
was set to for future use */
wwo
->
dwBufferSize
=
arts_stream_set
(
wwo
->
play_stream
,
ARTS_P_BUFFER_SIZE
,
BUFFER_SIZE
);
TRACE
(
"Tried to set BUFFER_SIZE of %d, wwo->dwBufferSize is actually %ld
\n
"
,
BUFFER_SIZE
,
wwo
->
dwBufferSize
);
/* Try to set the packet settings from constant and store the value that it
was actually set to for future use */
wwo
->
packetSettings
=
arts_stream_set
(
wwo
->
play_stream
,
ARTS_P_PACKET_SETTINGS
,
WAVEOUT_PACKET_SETTINGS
);
TRACE
(
"Tried to set ARTS_P_PACKET_SETTINGS to (%x), actually set to (%x)
\n
"
,
WAVEOUT_PACKET_SETTINGS
,
wwo
->
packetSettings
);
wwo
->
dwBufferSize
=
arts_stream_get
(
wwo
->
play_stream
,
ARTS_P_BUFFER_SIZE
);
TRACE
(
"Buffer size is now (%ld)
\n
"
,
wwo
->
dwBufferSize
);
wwo
->
dwPlayedTotal
=
0
;
wwo
->
dwWrittenTotal
=
0
;
wwo
->
dwSleepTime
=
((
1
<<
(
wwo
->
packetSettings
&
0xFFFF
))
*
1000
*
BUFFER_REFILL_THRESHOLD
)
/
wwo
->
format
.
wf
.
nAvgBytesPerSec
;
/* Initialize volume to full level */
wwo
->
volume_left
=
100
;
wwo
->
volume_right
=
100
;
...
...
@@ -1076,7 +1218,7 @@ static DWORD wodClose(WORD wDevID)
ARTS_DestroyRingMessage
(
&
wwo
->
msgRing
);
ARTS_CloseDevice
(
wwo
);
/* close the stream and clean things up */
ARTS_Close
WaveOut
Device
(
wwo
);
/* close the stream and clean things up */
ret
=
wodNotifyClient
(
wwo
,
WOM_CLOSE
,
0L
,
0L
);
}
...
...
@@ -1399,6 +1541,499 @@ DWORD WINAPI ARTS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
}
/*======================================================================*
* Low level WAVE IN implementation *
*======================================================================*/
/**************************************************************************
* widGetNumDevs [internal]
*/
static
DWORD
widGetNumDevs
(
void
)
{
TRACE
(
"%d
\n
"
,
MAX_WAVEINDRV
);
return
MAX_WAVEINDRV
;
}
/**************************************************************************
* widNotifyClient [internal]
*/
static
DWORD
widNotifyClient
(
WINE_WAVEIN
*
wwi
,
WORD
wMsg
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX
\n
"
,
wMsg
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
WIM_OPEN
:
case
WIM_CLOSE
:
case
WIM_DATA
:
if
(
wwi
->
wFlags
!=
DCB_NULL
&&
!
DriverCallback
(
wwi
->
waveDesc
.
dwCallback
,
wwi
->
wFlags
,
(
HDRVR
)
wwi
->
waveDesc
.
hWave
,
wMsg
,
wwi
->
waveDesc
.
dwInstance
,
dwParam1
,
dwParam2
))
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_ERROR
;
}
break
;
default:
FIXME
(
"Unknown callback message %u
\n
"
,
wMsg
);
return
MMSYSERR_INVALPARAM
;
}
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widGetDevCaps [internal]
*/
static
DWORD
widGetDevCaps
(
WORD
wDevID
,
LPWAVEINCAPSA
lpCaps
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpCaps
,
dwSize
);
if
(
lpCaps
==
NULL
)
return
MMSYSERR_NOTENABLED
;
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
TRACE
(
"MAX_WAVINDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
memcpy
(
lpCaps
,
&
WInDev
[
wDevID
].
caps
,
min
(
dwSize
,
sizeof
(
*
lpCaps
)));
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widRecorder [internal]
*/
static
DWORD
CALLBACK
widRecorder
(
LPVOID
pmt
)
{
WORD
uDevID
=
(
DWORD
)
pmt
;
WINE_WAVEIN
*
wwi
=
(
WINE_WAVEIN
*
)
&
WInDev
[
uDevID
];
WAVEHDR
*
lpWaveHdr
;
DWORD
dwSleepTime
;
DWORD
bytesRead
;
int
dwBufferSpace
;
enum
win_wm_message
msg
;
DWORD
param
;
HANDLE
ev
;
SetEvent
(
wwi
->
hStartUpEvent
);
/* make sleep time to be # of ms to record one packet */
dwSleepTime
=
((
1
<<
(
wwi
->
packetSettings
&
0xFFFF
))
*
1000
)
/
wwi
->
format
.
wf
.
nAvgBytesPerSec
;
TRACE
(
"sleeptime=%ld ms
\n
"
,
dwSleepTime
);
for
(;;)
{
/* Oddly enough, dwBufferSpace is sometimes negative....
*
* NOTE: If you remove this call to arts_stream_get() and
* remove the && (dwBufferSpace > 0) the code will still
* function correctly. I don't know which way is
* faster/better.
*/
dwBufferSpace
=
arts_stream_get
(
wwi
->
record_stream
,
ARTS_P_BUFFER_SPACE
);
TRACE
(
"wwi->lpQueuePtr=(%p), wwi->state=(%d), dwBufferSpace=(%d)
\n
"
,
wwi
->
lpQueuePtr
,
wwi
->
state
,
dwBufferSpace
);
/* read all data is arts input buffer. */
if
((
wwi
->
lpQueuePtr
!=
NULL
)
&&
(
wwi
->
state
==
WINE_WS_PLAYING
)
&&
(
dwBufferSpace
>
0
))
{
lpWaveHdr
=
wwi
->
lpQueuePtr
;
TRACE
(
"read as much as we can
\n
"
);
while
(
wwi
->
lpQueuePtr
)
{
TRACE
(
"attempt to read %ld bytes
\n
"
,
lpWaveHdr
->
dwBufferLength
-
lpWaveHdr
->
dwBytesRecorded
);
bytesRead
=
arts_read
(
wwi
->
record_stream
,
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
,
lpWaveHdr
->
dwBufferLength
-
lpWaveHdr
->
dwBytesRecorded
);
TRACE
(
"bytesRead=%ld
\n
"
,
bytesRead
);
if
(
bytesRead
==
0
)
break
;
lpWaveHdr
->
dwBytesRecorded
+=
bytesRead
;
wwi
->
dwRecordedTotal
+=
bytesRead
;
/* buffer full. notify client */
if
(
lpWaveHdr
->
dwBytesRecorded
>=
lpWaveHdr
->
dwBufferLength
)
{
/* must copy the value of next waveHdr, because we have no idea of what
* will be done with the content of lpWaveHdr in callback
*/
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
TRACE
(
"waveHdr full.
\n
"
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
lpWaveHdr
=
wwi
->
lpQueuePtr
=
lpNext
;
}
}
}
/* wait for dwSleepTime or an event in thread's queue */
WaitForSingleObject
(
wwi
->
msgRing
.
msg_event
,
dwSleepTime
);
while
(
ARTS_RetrieveRingMessage
(
&
wwi
->
msgRing
,
&
msg
,
&
param
,
&
ev
))
{
TRACE
(
"msg=%s param=0x%lx
\n
"
,
wodPlayerCmdString
[
msg
-
WM_USER
-
1
],
param
);
switch
(
msg
)
{
case
WINE_WM_PAUSING
:
wwi
->
state
=
WINE_WS_PAUSED
;
/* Put code here to "pause" arts recording
*/
SetEvent
(
ev
);
break
;
case
WINE_WM_STARTING
:
wwi
->
state
=
WINE_WS_PLAYING
;
/* Put code here to "start" arts recording
*/
SetEvent
(
ev
);
break
;
case
WINE_WM_HEADER
:
lpWaveHdr
=
(
LPWAVEHDR
)
param
;
/* insert buffer at end of queue */
{
LPWAVEHDR
*
wh
;
int
num_headers
=
0
;
for
(
wh
=
&
(
wwi
->
lpQueuePtr
);
*
wh
;
wh
=
&
((
*
wh
)
->
lpNext
))
{
num_headers
++
;
}
*
wh
=
lpWaveHdr
;
}
break
;
case
WINE_WM_STOPPING
:
if
(
wwi
->
state
!=
WINE_WS_STOPPED
)
{
/* Put code here to "stop" arts recording
*/
/* return current buffer to app */
lpWaveHdr
=
wwi
->
lpQueuePtr
;
if
(
lpWaveHdr
)
{
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
TRACE
(
"stop %p %p
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
wwi
->
lpQueuePtr
=
lpNext
;
}
}
wwi
->
state
=
WINE_WS_STOPPED
;
SetEvent
(
ev
);
break
;
case
WINE_WM_RESETTING
:
wwi
->
state
=
WINE_WS_STOPPED
;
wwi
->
dwRecordedTotal
=
0
;
/* return all buffers to the app */
for
(
lpWaveHdr
=
wwi
->
lpQueuePtr
;
lpWaveHdr
;
lpWaveHdr
=
lpWaveHdr
->
lpNext
)
{
TRACE
(
"reset %p %p
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
}
wwi
->
lpQueuePtr
=
NULL
;
SetEvent
(
ev
);
break
;
case
WINE_WM_CLOSING
:
wwi
->
hThread
=
0
;
wwi
->
state
=
WINE_WS_CLOSED
;
SetEvent
(
ev
);
ExitThread
(
0
);
/* shouldn't go here */
default:
FIXME
(
"unknown message %d
\n
"
,
msg
);
break
;
}
}
}
ExitThread
(
0
);
/* just for not generating compilation warnings... should never be executed */
return
0
;
}
/**************************************************************************
* widOpen [internal]
*/
static
DWORD
widOpen
(
WORD
wDevID
,
LPWAVEOPENDESC
lpDesc
,
DWORD
dwFlags
)
{
WINE_WAVEIN
*
wwi
;
TRACE
(
"(%u, %p %08lX);
\n
"
,
wDevID
,
lpDesc
,
dwFlags
);
if
(
lpDesc
==
NULL
)
{
WARN
(
"Invalid Parametr (lpDesc == NULL)!
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
TRACE
(
"MAX_WAVEINDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
/* if this device is already open tell the app that it is allocated */
if
(
WInDev
[
wDevID
].
record_stream
!=
(
arts_stream_t
*
)
-
1
)
{
TRACE
(
"device already allocated
\n
"
);
return
MMSYSERR_ALLOCATED
;
}
/* only PCM format is support so far... */
if
(
lpDesc
->
lpFormat
->
wFormatTag
!=
WAVE_FORMAT_PCM
||
lpDesc
->
lpFormat
->
nChannels
==
0
||
lpDesc
->
lpFormat
->
nSamplesPerSec
==
0
)
{
WARN
(
"Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
WAVERR_BADFORMAT
;
}
if
(
dwFlags
&
WAVE_FORMAT_QUERY
)
{
TRACE
(
"Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
MMSYSERR_NOERROR
;
}
wwi
=
&
WInDev
[
wDevID
];
/* direct sound not supported, ignore the flag */
dwFlags
&=
~
WAVE_DIRECTSOUND
;
wwi
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
memcpy
(
&
wwi
->
waveDesc
,
lpDesc
,
sizeof
(
WAVEOPENDESC
));
memcpy
(
&
wwi
->
format
,
lpDesc
->
lpFormat
,
sizeof
(
PCMWAVEFORMAT
));
if
(
wwi
->
format
.
wBitsPerSample
==
0
)
{
WARN
(
"Resetting zerod wBitsPerSample
\n
"
);
wwi
->
format
.
wBitsPerSample
=
8
*
(
wwi
->
format
.
wf
.
nAvgBytesPerSec
/
wwi
->
format
.
wf
.
nSamplesPerSec
)
/
wwi
->
format
.
wf
.
nChannels
;
}
wwi
->
record_stream
=
arts_record_stream
(
wwi
->
format
.
wf
.
nSamplesPerSec
,
wwi
->
format
.
wBitsPerSample
,
wwi
->
format
.
wf
.
nChannels
,
"winearts"
);
TRACE
(
"(wwi->record_stream=%p)
\n
"
,
wwi
->
record_stream
);
wwi
->
state
=
WINE_WS_STOPPED
;
wwi
->
packetSettings
=
arts_stream_set
(
wwi
->
record_stream
,
ARTS_P_PACKET_SETTINGS
,
WAVEIN_PACKET_SETTINGS
);
TRACE
(
"Tried to set ARTS_P_PACKET_SETTINGS to (%x), actually set to (%x)
\n
"
,
WAVEIN_PACKET_SETTINGS
,
wwi
->
packetSettings
);
TRACE
(
"Buffer size is now (%d)
\n
"
,
arts_stream_get
(
wwi
->
record_stream
,
ARTS_P_BUFFER_SIZE
));
if
(
wwi
->
lpQueuePtr
)
{
WARN
(
"Should have an empty queue (%p)
\n
"
,
wwi
->
lpQueuePtr
);
wwi
->
lpQueuePtr
=
NULL
;
}
arts_stream_set
(
wwi
->
record_stream
,
ARTS_P_BLOCKING
,
0
);
/* disable blocking on this stream */
if
(
!
wwi
->
record_stream
)
return
MMSYSERR_ALLOCATED
;
wwi
->
dwRecordedTotal
=
0
;
wwi
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
ARTS_InitRingMessage
(
&
wwi
->
msgRing
);
/* create recorder thread */
if
(
!
(
dwFlags
&
WAVE_DIRECTSOUND
))
{
wwi
->
hStartUpEvent
=
CreateEventA
(
NULL
,
FALSE
,
FALSE
,
NULL
);
wwi
->
hThread
=
CreateThread
(
NULL
,
0
,
widRecorder
,
(
LPVOID
)(
DWORD
)
wDevID
,
0
,
&
(
wwi
->
dwThreadID
));
WaitForSingleObject
(
wwi
->
hStartUpEvent
,
INFINITE
);
CloseHandle
(
wwi
->
hStartUpEvent
);
}
else
{
wwi
->
hThread
=
INVALID_HANDLE_VALUE
;
wwi
->
dwThreadID
=
0
;
}
wwi
->
hStartUpEvent
=
INVALID_HANDLE_VALUE
;
TRACE
(
"wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!
\n
"
,
wwi
->
format
.
wBitsPerSample
,
wwi
->
format
.
wf
.
nAvgBytesPerSec
,
wwi
->
format
.
wf
.
nSamplesPerSec
,
wwi
->
format
.
wf
.
nChannels
,
wwi
->
format
.
wf
.
nBlockAlign
);
return
widNotifyClient
(
wwi
,
WIM_OPEN
,
0L
,
0L
);
}
/**************************************************************************
* widClose [internal]
*/
static
DWORD
widClose
(
WORD
wDevID
)
{
WINE_WAVEIN
*
wwi
;
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't close !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
wwi
=
&
WInDev
[
wDevID
];
if
(
wwi
->
lpQueuePtr
!=
NULL
)
{
WARN
(
"still buffers open !
\n
"
);
return
WAVERR_STILLPLAYING
;
}
ARTS_AddRingMessage
(
&
wwi
->
msgRing
,
WINE_WM_CLOSING
,
0
,
TRUE
);
ARTS_CloseWaveInDevice
(
wwi
);
wwi
->
state
=
WINE_WS_CLOSED
;
ARTS_DestroyRingMessage
(
&
wwi
->
msgRing
);
return
widNotifyClient
(
wwi
,
WIM_CLOSE
,
0L
,
0L
);
}
/**************************************************************************
* widAddBuffer [internal]
*/
static
DWORD
widAddBuffer
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't do it !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
!
(
lpWaveHdr
->
dwFlags
&
WHDR_PREPARED
))
{
TRACE
(
"never been prepared !
\n
"
);
return
WAVERR_UNPREPARED
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
{
TRACE
(
"header already in use !
\n
"
);
return
WAVERR_STILLPLAYING
;
}
lpWaveHdr
->
dwFlags
|=
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwBytesRecorded
=
0
;
lpWaveHdr
->
lpNext
=
NULL
;
ARTS_AddRingMessage
(
&
WInDev
[
wDevID
].
msgRing
,
WINE_WM_HEADER
,
(
DWORD
)
lpWaveHdr
,
FALSE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widPrepare [internal]
*/
static
DWORD
widPrepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MMSYSERR_INVALHANDLE
;
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
|=
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwBytesRecorded
=
0
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widUnprepare [internal]
*/
static
DWORD
widUnprepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
{
TRACE
(
"Still playing...
\n
"
);
return
WAVERR_STILLPLAYING
;
}
lpWaveHdr
->
dwFlags
&=
~
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStart [internal]
*/
static
DWORD
widStart
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't start recording !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
ARTS_AddRingMessage
(
&
WInDev
[
wDevID
].
msgRing
,
WINE_WM_STARTING
,
0
,
TRUE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStop [internal]
*/
static
DWORD
widStop
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't stop !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
ARTS_AddRingMessage
(
&
WInDev
[
wDevID
].
msgRing
,
WINE_WM_STOPPING
,
0
,
TRUE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widReset [internal]
*/
static
DWORD
widReset
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't reset !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
ARTS_AddRingMessage
(
&
WInDev
[
wDevID
].
msgRing
,
WINE_WM_RESETTING
,
0
,
TRUE
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widMessage (WINEARTS.6)
*/
DWORD
WINAPI
ARTS_widMessage
(
UINT
wDevID
,
UINT
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"(%u, %04X, %08lX, %08lX, %08lX);
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
DRVM_INIT
:
case
DRVM_EXIT
:
case
DRVM_ENABLE
:
case
DRVM_DISABLE
:
/* FIXME: Pretend this is supported */
return
0
;
case
WIDM_OPEN
:
return
widOpen
(
wDevID
,
(
LPWAVEOPENDESC
)
dwParam1
,
dwParam2
);
case
WIDM_CLOSE
:
return
widClose
(
wDevID
);
case
WIDM_ADDBUFFER
:
return
widAddBuffer
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_PREPARE
:
return
widPrepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_UNPREPARE
:
return
widUnprepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_GETDEVCAPS
:
return
widGetDevCaps
(
wDevID
,
(
LPWAVEINCAPSA
)
dwParam1
,
dwParam2
);
case
WIDM_GETNUMDEVS
:
return
widGetNumDevs
();
case
WIDM_RESET
:
return
widReset
(
wDevID
);
case
WIDM_START
:
return
widStart
(
wDevID
);
case
WIDM_STOP
:
return
widStop
(
wDevID
);
default:
FIXME
(
"unknown message %d!
\n
"
,
wMsg
);
}
return
MMSYSERR_NOTSUPPORTED
;
}
/*======================================================================*
* Low level DSOUND implementation *
*======================================================================*/
static
DWORD
wodDsCreate
(
UINT
wDevID
,
PIDSDRIVER
*
drv
)
...
...
@@ -1436,4 +2071,14 @@ DWORD WINAPI ARTS_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
return
MMSYSERR_NOTENABLED
;
}
/**************************************************************************
* widMessage (WINEARTS.6)
*/
DWORD
WINAPI
ARTS_widMessage
(
UINT
wDevID
,
UINT
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
FIXME
(
"(%u, %04X, %08lX, %08lX, %08lX):stub
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
return
MMSYSERR_NOTENABLED
;
}
#endif
/* HAVE_ARTS */
dlls/winmm/winearts/winearts.drv.spec
View file @
ed69f0bf
@ stdcall DriverProc(long long long long long) ARTS_DriverProc
@ stdcall wodMessage(long long long long long) ARTS_wodMessage
@ stdcall widMessage(long long long long long) ARTS_widMessage
dlls/winmm/winejack/audio.c
View file @
ed69f0bf
/* -*- tab-width: 8; c-basic-offset:
4
-*- */
/* -*- tab-width: 8; c-basic-offset:
2
-*- */
/*
* Wine Driver for jack Sound Server
* http://jackit.sourceforge.net
...
...
@@ -29,7 +29,6 @@
* right now we use the winmm layer to do resampling although it would
* be nice to have a full set of algorithms to choose from based on cpu
* time
* implement wave-in support with jack
*
* FIXME:
* pause in waveOut during loop is not handled correctly
...
...
@@ -83,6 +82,7 @@ MAKE_FUNCPTR(jack_port_register);
MAKE_FUNCPTR
(
jack_port_get_buffer
);
MAKE_FUNCPTR
(
jack_get_ports
);
MAKE_FUNCPTR
(
jack_port_name
);
MAKE_FUNCPTR
(
jack_get_buffer_size
);
#undef MAKE_FUNCPTR
/* define the below to work around a bug in jack where closing a port */
...
...
@@ -96,7 +96,7 @@ typedef jack_nframes_t nframes_t;
/* only allow 10 output devices through this driver, this ought to be adequate */
#define MAX_WAVEOUTDRV (10)
#define MAX_WAVEINDRV (1)
#define MAX_WAVEINDRV (1
0
)
/* state diagram for waveOut writing:
*
...
...
@@ -170,6 +170,19 @@ typedef struct {
DWORD
dwTotalRecorded
;
WAVEINCAPSA
caps
;
BOOL
bTriggerSupport
;
WORD
wDevID
;
jack_port_t
*
in_port_l
;
/* ports for left and right channels */
jack_port_t
*
in_port_r
;
jack_client_t
*
client
;
long
sample_rate
;
/* jack server sample rate */
#if JACK_CLOSE_HACK
BOOL
in_use
;
/* TRUE if this device is in use */
#endif
char
*
sound_buffer
;
unsigned
long
buffer_size
;
/* synchronization stuff */
CRITICAL_SECTION
access_crst
;
...
...
@@ -185,12 +198,19 @@ static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);
static
LPWAVEHDR
wodHelper_PlayPtrNext
(
WINE_WAVEOUT
*
wwo
);
static
DWORD
wodHelper_NotifyCompletions
(
WINE_WAVEOUT
*
wwo
,
BOOL
force
);
static
int
JACK_OpenDevice
(
WINE_WAVEOUT
*
wwo
);
static
int
JACK_OpenWaveOutDevice
(
WINE_WAVEOUT
*
wwo
);
static
int
JACK_OpenWaveInDevice
(
WINE_WAVEIN
*
wwi
,
WORD
nChannels
);
#if JACK_CLOSE_HACK
static
void
JACK_CloseWaveOutDevice
(
WINE_WAVEOUT
*
wwo
,
BOOL
close_client
);
#else
static
void
JACK_CloseWaveOutDevice
(
WINE_WAVEOUT
*
wwo
);
#endif
#if JACK_CLOSE_HACK
static
void
JACK_Close
Device
(
WINE_WAVEOUT
*
wwo
,
BOOL
close_client
);
static
void
JACK_Close
WaveInDevice
(
WINE_WAVEIN
*
wwi
,
BOOL
close_client
);
#else
static
void
JACK_Close
Device
(
WINE_WAVEOUT
*
wwo
);
static
void
JACK_Close
WaveInDevice
(
WINE_WAVEIN
*
wwi
);
#endif
...
...
@@ -253,6 +273,25 @@ void sample_move_d16_s16 (sample_t *dst, short *src,
}
}
/* convert from floating point to 16 bit */
/* allow for copying of a buffer that will hold a single channel stream */
/* to stereo data with alternating left/right channels */
/* nsamples is in terms of float samples */
/* dst_skip is in terms of 16bit samples */
void
sample_move_s16_d16
(
short
*
dst
,
sample_t
*
src
,
unsigned
long
nsamples
,
unsigned
long
dst_skip
)
{
/* ALERT: signed sign-extension portability !!! */
while
(
nsamples
--
)
{
*
dst
=
(
*
src
)
*
SAMPLE_MAX_16BIT
;
/* TRACE("src=(%.8f,%p) dst=(%d,%p)\n",*src,src,*dst,dst); */
dst
+=
dst_skip
;
src
++
;
}
}
/* fill dst buffer with nsamples worth of silence */
void
sample_silence_dS
(
sample_t
*
dst
,
unsigned
long
nsamples
)
{
...
...
@@ -265,39 +304,30 @@ void sample_silence_dS (sample_t *dst, unsigned long nsamples)
}
/******************************************************************
* JACK_callback
* JACK_callback
_wwo
*/
/* everytime the jack server wants something from us it calls this
function, so we either deliver it some sound to play or deliver it nothing
to play */
int
JACK_callback
(
nframes_t
nframes
,
void
*
arg
)
int
JACK_callback
_wwo
(
nframes_t
nframes
,
void
*
arg
)
{
sample_t
*
out_l
;
sample_t
*
out_r
;
WINE_WAVEOUT
*
wwo
=
(
WINE_WAVEOUT
*
)
arg
;
TRACE
(
"wDevID: %
d, nframes %ld
\n
"
,
wwo
->
wDevID
,
nframes
);
TRACE
(
"wDevID: %
u, nframes %u state=%u
\n
"
,
wwo
->
wDevID
,
nframes
,
wwo
->
state
);
if
(
!
wwo
->
client
)
ERR
(
"client is closed, this is weird...
\n
"
);
out_l
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwo
->
out_port_l
,
nframes
);
out_r
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwo
->
out_port_r
,
nframes
);
EnterCriticalSection
(
&
wwo
->
access_crst
);
out_l
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwo
->
out_port_l
,
nframes
);
out_r
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwo
->
out_port_r
,
nframes
);
if
(
wwo
->
state
==
WINE_WS_PLAYING
)
{
DWORD
jackBytesAvailableThisCallback
=
sizeof
(
sample_t
)
*
nframes
;
DWORD
jackBytesLeft
=
sizeof
(
sample_t
)
*
nframes
;
DWORD
inputBytesAvailable
;
/* number of bytes we have from the app, after conversion to 16bit stereo */
DWORD
jackBytesToWrite
;
/* number of bytes we are going to write out, after conversion */
DWORD
bytesInput
;
/* the number of bytes from the app */
DWORD
appBytesToWrite
;
/* number of bytes from the app we are going to write */
DWORD
jackFramesAvailable
=
nframes
;
DWORD
outputFramesAvailable
;
DWORD
numFramesToWrite
;
long
written
=
0
;
char
*
buffer
;
...
...
@@ -315,65 +345,53 @@ int JACK_callback (nframes_t nframes, void *arg)
TRACE
(
"wwo.state == WINE_WS_PLAYING
\n
"
);
/* see if our
buffer is large enough for the data we are writing
*/
/*
ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop)
*/
if
(
wwo
->
buffer_size
<
jackBytesAvailableThisCallback
)
/* see if our
sound_buffer is large enough to hold the number of frames jack requested
*/
/*
Note: sound_buffer is always filled with 16-bit stereo data, even for mono mode
*/
if
(
wwo
->
buffer_size
<
(
nframes
*
sizeof
(
short
)
*
2
)
)
{
ERR
(
"for some reason JACK_BufSize() didn't allocate enough memory
\n
"
);
ERR
(
"allocated %ld bytes, need %ld bytes
\n
"
,
wwo
->
buffer_size
,
jackBytesAvailableThisCallback
);
LeaveCriticalSection
(
&
wwo
->
access_crst
);
ERR
(
"allocated %ld bytes, need %d bytes
\n
"
,
wwo
->
buffer_size
,
(
nframes
*
sizeof
(
short
)
*
2
));
return
0
;
}
/* while we have jack
BytesLeft
and a wave header to be played */
while
(
jack
BytesLeft
&&
wwo
->
lpPlayPtr
)
/* while we have jack
FramesAvailable
and a wave header to be played */
while
(
jack
FramesAvailable
&&
wwo
->
lpPlayPtr
)
{
/* find the amount of audio to be played at this time */
bytesInput
=
wwo
->
lpPlayPtr
->
dwBufferLength
-
wwo
->
dwPartialOffset
;
inputBytesAvailable
=
bytesInput
;
/* calculate inputBytesAvailable based on audio format conversion */
if
(
wwo
->
format
.
wf
.
nChannels
==
1
)
inputBytesAvailable
<<=
1
;
/* multiply by two for mono->stereo conversion */
outputFramesAvailable
=
(
wwo
->
lpPlayPtr
->
dwBufferLength
-
wwo
->
dwPartialOffset
)
/
wwo
->
format
.
wf
.
nBlockAlign
;
/* find the minimum of the inputBytesAvailable and the space available */
jackBytesToWrite
=
min
(
jackBytesLeft
,
inputBytesAvailable
);
/* calculate appBytesToWrite based on audio format conversion */
appBytesToWrite
=
jackBytesToWrite
;
if
(
wwo
->
format
.
wf
.
nChannels
==
1
)
appBytesToWrite
>>=
1
;
/* divide by two for stereo->mono conversion */
TRACE
(
"jackBytesToWrite == %ld, appBytesToWrite == %ld
\n
"
,
jackBytesToWrite
,
appBytesToWrite
);
numFramesToWrite
=
min
(
jackFramesAvailable
,
outputFramesAvailable
);
TRACE
(
"dwBufferLength=(%ld) dwPartialOffset=(%ld)
\n
"
,
wwo
->
lpPlayPtr
->
dwBufferLength
,
wwo
->
dwPartialOffset
);
TRACE
(
"outputFramesAvailable == %ld, jackFramesAvailable == %ld
\n
"
,
outputFramesAvailable
,
jackFramesAvailable
);
buffer
=
wwo
->
lpPlayPtr
->
lpData
+
wwo
->
dwPartialOffset
;
/* convert from mono to stereo if necessary */
/* otherwise just memcpy to the output buffer */
if
(
wwo
->
format
.
wf
.
nChannels
==
1
)
{
sample_move_d16_d16
((
short
*
)
wwo
->
sound_buffer
+
((
jackBytesAvailableThisCallback
-
jackBytesLeft
)
/
sizeof
(
short
)),
(
short
*
)
buffer
,
jackByt
esToWrite
,
wwo
->
format
.
wf
.
nChannels
);
sample_move_d16_d16
((
short
*
)
wwo
->
sound_buffer
+
((
nframes
-
jackFramesAvailable
)
*
sizeof
(
short
)),
(
short
*
)
buffer
,
numFram
esToWrite
,
wwo
->
format
.
wf
.
nChannels
);
}
else
/* just copy the memory over */
{
memcpy
(
wwo
->
sound_buffer
+
(
jackBytesAvailableThisCallback
-
jackBytesLeft
),
buffer
,
jackBytesToWrite
);
memcpy
(
wwo
->
sound_buffer
+
(
(
nframes
-
jackFramesAvailable
)
*
wwo
->
format
.
wf
.
nBlockAlign
),
buffer
,
numFramesToWrite
*
wwo
->
format
.
wf
.
nBlockAlign
);
}
/* advance to the next wave header if possible, or advance pointer */
/* inside of the current header if we haven't completed it */
if
(
appBytesToWrite
==
bytesInput
)
if
(
numFramesToWrite
==
outputFramesAvailable
)
{
wodHelper_PlayPtrNext
(
wwo
);
/* we wrote the whole waveheader, skip to the next one*/
}
else
{
wwo
->
dwPartialOffset
+=
appBytesToWrite
;
/* else advance by the bytes we took in to write */
wwo
->
dwPartialOffset
+=
(
numFramesToWrite
*
wwo
->
format
.
wf
.
nBlockAlign
)
;
/* else advance by the bytes we took in to write */
}
written
+=
appBytesToWrite
;
/* add on what we wrote */
jack
BytesLeft
-=
jackByt
esToWrite
;
/* take away what was written in terms of output bytes */
written
+=
(
numFramesToWrite
*
wwo
->
format
.
wf
.
nBlockAlign
)
;
/* add on what we wrote */
jack
FramesAvailable
-=
numFram
esToWrite
;
/* take away what was written in terms of output bytes */
}
wwo
->
tickCountMS
=
GetTickCount
();
/* record the current time */
...
...
@@ -386,25 +404,22 @@ int JACK_callback (nframes_t nframes, void *arg)
/* the audio to the jack server */
/* apply volume to the buffer */
/* NOTE: buffer_size >> 2 to convert from bytes to 16 bit stereo(32bit) samples */
volume_effect32
(
wwo
->
sound_buffer
,
(
jackBytesAvailableThisCallback
-
jackBytesLeft
)
>>
2
,
wwo
->
volume_left
,
wwo
->
volume_right
);
volume_effect32
(
wwo
->
sound_buffer
,
(
nframes
-
jackFramesAvailable
),
wwo
->
volume_left
,
wwo
->
volume_right
);
/* convert from stereo 16 bit to single channel 32 bit float */
/* for each jack server channel */
/* NOTE: we skip over two sample since we want to only get either the left or right channel */
sample_move_d16_s16
(
out_l
,
(
short
*
)
wwo
->
sound_buffer
,
(
jackBytesAvailableThisCallback
-
jackBytesLeft
)
>>
2
,
2
);
sample_move_d16_s16
(
out_r
,
(
short
*
)
wwo
->
sound_buffer
+
1
,
(
jackBytesAvailableThisCallback
-
jackBytesLeft
)
>>
2
,
2
);
sample_move_d16_s16
(
out_l
,
(
short
*
)
wwo
->
sound_buffer
,
(
nframes
-
jackFramesAvailable
),
2
);
sample_move_d16_s16
(
out_r
,
(
short
*
)
wwo
->
sound_buffer
+
1
,
(
nframes
-
jackFramesAvailable
),
2
);
/* see if we still have jackBytesLeft here, if we do that means that we
ran out of wave data to play and had a buffer underrun, fill in
the rest of the space with zero bytes */
if
(
jack
BytesLeft
)
if
(
jack
FramesAvailable
)
{
ERR
(
"buffer underrun of %ld
bytes
\n
"
,
jackBytesLeft
);
sample_silence_dS
(
out_l
+
(
(
jackBytesAvailableThisCallback
-
jackBytesLeft
)
/
sizeof
(
sample_t
)),
jackBytesLeft
/
sizeof
(
sample_t
)
);
sample_silence_dS
(
out_r
+
(
(
jackBytesAvailableThisCallback
-
jackBytesLeft
)
/
sizeof
(
sample_t
)),
jackBytesLeft
/
sizeof
(
sample_t
)
);
ERR
(
"buffer underrun of %ld
frames
\n
"
,
jackFramesAvailable
);
sample_silence_dS
(
out_l
+
(
nframes
-
jackFramesAvailable
),
jackFramesAvailable
);
sample_silence_dS
(
out_r
+
(
nframes
-
jackFramesAvailable
),
jackFramesAvailable
);
}
}
else
if
(
wwo
->
state
==
WINE_WS_PAUSED
||
...
...
@@ -417,33 +432,34 @@ int JACK_callback (nframes_t nframes, void *arg)
}
/* notify the client of completed wave headers */
EnterCriticalSection
(
&
wwo
->
access_crst
);
wodHelper_NotifyCompletions
(
wwo
,
FALSE
);
LeaveCriticalSection
(
&
wwo
->
access_crst
);
TRACE
(
"ending
\n
"
);
return
0
;
}
/******************************************************************
* JACK_bufsize
* JACK_bufsize
_wwo
*
* Called whenever the jack server changes the the max number
* of frames passed to JACK_callback
*/
int
JACK_bufsize
(
nframes_t
nframes
,
void
*
arg
)
int
JACK_bufsize
_wwo
(
nframes_t
nframes
,
void
*
arg
)
{
WINE_WAVEOUT
*
wwo
=
(
WINE_WAVEOUT
*
)
arg
;
DWORD
buffer_required
;
TRACE
(
"the maximum buffer size is now %lu frames
\n
"
,
nframes
);
TRACE
(
"wDevID=%d
\n
"
,
wwo
->
wDevID
);
TRACE
(
"the maximum buffer size is now %u frames
\n
"
,
nframes
);
/* make sure the callback routine has adequate memory */
/* see if our buffer is large enough for the data we are writing */
/* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
EnterCriticalSection
(
&
wwo
->
access_crst
);
buffer_required
=
sizeof
(
sample_t
)
*
nframes
;
/* wwo->sound_buffer is always filled with 16-bit stereo data, even for mono streams */
buffer_required
=
nframes
*
sizeof
(
short
)
*
2
;
TRACE
(
"wwo->buffer_size (%ld) buffer_required (%ld).
\n
"
,
wwo
->
buffer_size
,
buffer_required
);
if
(
wwo
->
buffer_size
<
buffer_required
)
{
TRACE
(
"expanding buffer from wwo->buffer_size == %ld, to %ld
\n
"
,
...
...
@@ -452,9 +468,9 @@ int JACK_bufsize (nframes_t nframes, void *arg)
wwo
->
buffer_size
=
buffer_required
;
if
(
wwo
->
sound_buffer
)
wwo
->
sound_buffer
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
wwo
->
sound_buffer
,
wwo
->
buffer_size
);
wwo
->
sound_buffer
=
HeapReAlloc
(
GetProcessHeap
(),
0
,
wwo
->
sound_buffer
,
wwo
->
buffer_size
);
else
wwo
->
sound_buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
wwo
->
buffer_size
);
wwo
->
sound_buffer
=
HeapAlloc
(
GetProcessHeap
(),
0
,
wwo
->
buffer_size
);
/* if we don't have a buffer then error out */
if
(
!
wwo
->
sound_buffer
)
...
...
@@ -467,26 +483,37 @@ int JACK_bufsize (nframes_t nframes, void *arg)
LeaveCriticalSection
(
&
wwo
->
access_crst
);
TRACE
(
"
called
\n
"
);
TRACE
(
"
ending
\n
"
);
return
0
;
}
/******************************************************************
* JACK_bufsize_wwi
*
* Called whenever the jack server changes the the max number
* of frames passed to JACK_callback
*/
int
JACK_bufsize_wwi
(
nframes_t
nframes
,
void
*
arg
)
{
TRACE
(
"the maximum buffer size is now %u frames
\n
"
,
nframes
);
return
0
;
}
/******************************************************************
* JACK_srate
*/
int
JACK_srate
(
nframes_t
nframes
,
void
*
arg
)
{
TRACE
(
"the sample rate is now %
l
u/sec
\n
"
,
nframes
);
TRACE
(
"the sample rate is now %u/sec
\n
"
,
nframes
);
return
0
;
}
/******************************************************************
* JACK_shutdown
* JACK_shutdown
_wwo
*/
/* if this is called then jack shut down... handle this appropriately */
void
JACK_shutdown
(
void
*
arg
)
void
JACK_shutdown
_wwo
(
void
*
arg
)
{
WINE_WAVEOUT
*
wwo
=
(
WINE_WAVEOUT
*
)
arg
;
...
...
@@ -496,7 +523,27 @@ void JACK_shutdown(void* arg)
/* lets see if we can't reestablish the connection */
Sleep
(
750
);
/* pause for a short period of time */
if
(
!
JACK_OpenDevice
(
wwo
))
if
(
!
JACK_OpenWaveOutDevice
(
wwo
))
{
ERR
(
"unable to reconnect with jack...
\n
"
);
}
}
/******************************************************************
* JACK_shutdown_wwi
*/
/* if this is called then jack shut down... handle this appropriately */
void
JACK_shutdown_wwi
(
void
*
arg
)
{
WINE_WAVEIN
*
wwi
=
(
WINE_WAVEIN
*
)
arg
;
wwi
->
client
=
0
;
/* reset client */
TRACE
(
"trying to reconnect after sleeping for a short while...
\n
"
);
/* lets see if we can't reestablish the connection */
Sleep
(
750
);
/* pause for a short period of time */
if
(
!
JACK_OpenWaveInDevice
(
wwi
,
wwi
->
format
.
wf
.
nChannels
))
{
ERR
(
"unable to reconnect with jack...
\n
"
);
}
...
...
@@ -504,9 +551,9 @@ void JACK_shutdown(void* arg)
/******************************************************************
* JACK_OpenDevice
* JACK_Open
WaveOut
Device
*/
static
int
JACK_OpenDevice
(
WINE_WAVEOUT
*
wwo
)
static
int
JACK_Open
WaveOut
Device
(
WINE_WAVEOUT
*
wwo
)
{
const
char
**
ports
;
int
i
;
...
...
@@ -537,8 +584,8 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
wwo
->
buffer_size
=
0
;
/* try to become a client of the JACK server */
snprintf
(
client_name
,
sizeof
(
client_name
),
"wine_jack_
client
%d"
,
wwo
->
wDevID
);
TRACE
(
"client name '%s'
\n
"
,
client_name
);
snprintf
(
client_name
,
sizeof
(
client_name
),
"wine_jack_
out_
%d"
,
wwo
->
wDevID
);
TRACE
(
"client name '%s'
\n
"
,
client_name
);
if
((
client
=
fp_jack_client_new
(
client_name
))
==
0
)
{
/* jack has problems with shutting down clients, so lets */
...
...
@@ -550,16 +597,16 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
return
0
;
}
}
/* tell the JACK server to call `JACK_callback()' whenever
/* tell the JACK server to call `JACK_callback
_wwo
()' whenever
there is work to be done. */
fp_jack_set_process_callback
(
client
,
JACK_callback
,
wwo
);
fp_jack_set_process_callback
(
client
,
JACK_callback
_wwo
,
wwo
);
/* tell the JACK server to call `JACK_bufsize()' whenever
/* tell the JACK server to call `JACK_bufsize
_wwo
()' whenever
the maximum number of frames that will be passed
to `JACK_Callback()' changes */
fp_jack_set_buffer_size_callback
(
client
,
JACK_bufsize
,
wwo
);
fp_jack_set_buffer_size_callback
(
client
,
JACK_bufsize
_wwo
,
wwo
);
/* tell the JACK server to call `srate()' whenever
the sample rate of the system changes. */
fp_jack_set_sample_rate_callback
(
client
,
JACK_srate
,
wwo
);
...
...
@@ -567,7 +614,7 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
/* tell the JACK server to call `jack_shutdown()' if
it ever shuts down, either entirely, or if it
just decides to stop calling us. */
fp_jack_on_shutdown
(
client
,
JACK_shutdown
,
wwo
);
fp_jack_on_shutdown
(
client
,
JACK_shutdown
_wwo
,
wwo
);
/* display the current sample rate. once the client is activated
(see below), you should rely on your own sample rate
...
...
@@ -583,6 +630,8 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
out_port_r
=
fp_jack_port_register
(
client
,
"out_r"
,
JACK_DEFAULT_AUDIO_TYPE
,
JackPortIsOutput
,
0
);
TRACE
(
"Created ports. (%p) (%p)
\n
"
,
out_port_l
,
out_port_r
);
/* save away important values to the WINE_WAVEOUT struct */
wwo
->
client
=
client
;
wwo
->
out_port_l
=
out_port_l
;
...
...
@@ -592,6 +641,9 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
wwo
->
in_use
=
TRUE
;
/* mark this device as in use since it now is ;-) */
#endif
/* set initial buffer size */
JACK_bufsize_wwo
(
fp_jack_get_buffer_size
(
client
),
wwo
);
/* tell the JACK server that we are ready to roll */
if
(
fp_jack_activate
(
client
))
{
...
...
@@ -599,6 +651,7 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
return
0
;
}
TRACE
(
"jack activate.
\n
"
);
/* figure out what the ports that we want to output on are */
/* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
/* this way works if names are changed */
...
...
@@ -637,7 +690,11 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
/* if something failed we need to shut the client down and return 0 */
if
(
failed
)
{
JACK_CloseDevice
(
wwo
,
TRUE
);
#if JACK_CLOSE_HACK
JACK_CloseWaveOutDevice
(
wwo
,
TRUE
);
#else
JACK_CloseWaveOutDevice
(
wwo
);
#endif
return
0
;
}
...
...
@@ -645,20 +702,20 @@ static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
}
/******************************************************************
* JACK_CloseDevice
* JACK_Close
WaveOut
Device
*
* Close the connection to the server cleanly.
* If close_client is TRUE we close the client for this device instead of
* just marking the device as in_use(JACK_CLOSE_HACK only)
*/
#if JACK_CLOSE_HACK
static
void
JACK_CloseDevice
(
WINE_WAVEOUT
*
wwo
,
BOOL
close_client
)
static
void
JACK_Close
WaveOut
Device
(
WINE_WAVEOUT
*
wwo
,
BOOL
close_client
)
#else
static
void
JACK_CloseDevice
(
WINE_WAVEOUT
*
wwo
)
static
void
JACK_Close
WaveOut
Device
(
WINE_WAVEOUT
*
wwo
)
#endif
{
#if JACK_CLOSE_HACK
TRACE
(
"wDevID: %d, close_client: %d
\n
"
,
wwo
->
wDevID
,
close_client
);
TRACE
(
"wDevID: %d, close_client
(wwo)
: %d
\n
"
,
wwo
->
wDevID
,
close_client
);
#else
TRACE
(
"wDevID: %d
\n
"
,
wwo
->
wDevID
);
#endif
...
...
@@ -688,6 +745,49 @@ static void JACK_CloseDevice(WINE_WAVEOUT* wwo)
}
/******************************************************************
* JACK_CloseWaveInDevice
*
* Close the connection to the server cleanly.
* If close_client is TRUE we close the client for this device instead of
* just marking the device as in_use(JACK_CLOSE_HACK only)
*/
#if JACK_CLOSE_HACK
static
void
JACK_CloseWaveInDevice
(
WINE_WAVEIN
*
wwi
,
BOOL
close_client
)
#else
static
void
JACK_CloseWaveInDevice
(
WINE_WAVEIN
*
wwi
)
#endif
{
#if JACK_CLOSE_HACK
TRACE
(
"wDevID: %d, close_client (wwi): %d
\n
"
,
wwi
->
wDevID
,
close_client
);
#else
TRACE
(
"wDevID: %d
\n
"
,
wwi
->
wDevID
);
#endif
#if JACK_CLOSE_HACK
if
(
close_client
)
{
#endif
fp_jack_deactivate
(
wwi
->
client
);
/* supposed to help the jack_client_close() to succeed */
fp_jack_client_close
(
wwi
->
client
);
EnterCriticalSection
(
&
wwi
->
access_crst
);
wwi
->
client
=
0
;
/* reset client */
HeapFree
(
GetProcessHeap
(),
0
,
wwi
->
sound_buffer
);
/* free buffer memory */
wwi
->
sound_buffer
=
0
;
wwi
->
buffer_size
=
0
;
/* zero out size of the buffer */
LeaveCriticalSection
(
&
wwi
->
access_crst
);
#if JACK_CLOSE_HACK
}
else
{
EnterCriticalSection
(
&
wwi
->
access_crst
);
TRACE
(
"setting in_use to FALSE
\n
"
);
wwi
->
in_use
=
FALSE
;
LeaveCriticalSection
(
&
wwi
->
access_crst
);
}
#endif
}
/******************************************************************
* JACK_WaveRelease
*
*
...
...
@@ -696,23 +796,40 @@ LONG JACK_WaveRelease(void)
{
int
iDevice
;
TRACE
(
"closing all open devices
\n
"
);
TRACE
(
"closing all open
waveout
devices
\n
"
);
/* close all open devices */
/* close all open
output
devices */
for
(
iDevice
=
0
;
iDevice
<
MAX_WAVEOUTDRV
;
iDevice
++
)
{
TRACE
(
"iDevice == %d
\n
"
,
iDevice
);
if
(
WOutDev
[
iDevice
].
client
)
{
#if JACK_CLOSE_HACK
JACK_CloseDevice
(
&
WOutDev
[
iDevice
],
TRUE
);
/* close the device, FORCE the client to close */
JACK_Close
WaveOut
Device
(
&
WOutDev
[
iDevice
],
TRUE
);
/* close the device, FORCE the client to close */
#else
JACK_CloseDevice
(
&
WOutDev
[
iDevice
]);
/* close the device, FORCE the client to close */
JACK_Close
WaveOut
Device
(
&
WOutDev
[
iDevice
]);
/* close the device, FORCE the client to close */
#endif
DeleteCriticalSection
(
&
(
WOutDev
[
iDevice
].
access_crst
));
/* delete the critical section */
}
}
TRACE
(
"closing all open wavein devices
\n
"
);
/* close all open input devices */
for
(
iDevice
=
0
;
iDevice
<
MAX_WAVEINDRV
;
iDevice
++
)
{
TRACE
(
"iDevice == %d
\n
"
,
iDevice
);
if
(
WInDev
[
iDevice
].
client
)
{
#if JACK_CLOSE_HACK
JACK_CloseWaveInDevice
(
&
WInDev
[
iDevice
],
TRUE
);
/* close the device, FORCE the client to close */
#else
JACK_CloseWaveInDevice
(
&
WInDev
[
iDevice
]);
/* close the device, FORCE the client to close */
#endif
DeleteCriticalSection
(
&
(
WInDev
[
iDevice
].
access_crst
));
/* delete the critical section */
}
}
TRACE
(
"returning 1
\n
"
);
return
1
;
...
...
@@ -745,6 +862,7 @@ LONG JACK_WaveInit(void)
LOAD_FUNCPTR
(
jack_port_get_buffer
);
LOAD_FUNCPTR
(
jack_get_ports
);
LOAD_FUNCPTR
(
jack_port_name
);
LOAD_FUNCPTR
(
jack_get_buffer_size
);
#undef LOAD_FUNCPTR
/* start with output device */
...
...
@@ -755,6 +873,7 @@ LONG JACK_WaveInit(void)
#if JACK_CLOSE_HACK
WOutDev
[
i
].
in_use
=
FALSE
;
WInDev
[
i
].
in_use
=
FALSE
;
#endif
memset
(
&
WOutDev
[
i
].
caps
,
0
,
sizeof
(
WOutDev
[
i
].
caps
));
...
...
@@ -800,6 +919,37 @@ LONG JACK_WaveInit(void)
{
/* TODO: we should initialize read stuff here */
memset
(
&
WInDev
[
0
].
caps
,
0
,
sizeof
(
WInDev
[
0
].
caps
));
/* FIXME: some programs compare this string against the content of the registry
* for MM drivers. The names have to match in order for the program to work
* (e.g. MS win9x mplayer.exe)
*/
#ifdef EMULATE_SB16
WInDev
[
i
].
caps
.
wMid
=
0x0002
;
WInDev
[
i
].
caps
.
wPid
=
0x0104
;
strcpy
(
WInDev
[
i
].
caps
.
szPname
,
"SB16 Wave In"
);
#else
WInDev
[
i
].
caps
.
wMid
=
0x00FF
;
WInDev
[
i
].
caps
.
wPid
=
0x0001
;
strcpy
(
WInDev
[
i
].
caps
.
szPname
,
"CS4236/37/38"
);
#endif
WInDev
[
i
].
caps
.
vDriverVersion
=
0x0100
;
WInDev
[
i
].
caps
.
wChannels
=
0x2
;
/* NOTE: we don't support any 8 bit modes so note that */
/* WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4S16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_4M16
;
/* WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2M16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_2S16
;
/* WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1M16
;
WInDev
[
i
].
caps
.
dwFormats
|=
WAVE_FORMAT_1S16
;
WInDev
[
i
].
caps
.
wReserved1
=
0
;
}
return
1
;
/* return success */
...
...
@@ -958,11 +1108,13 @@ static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
TRACE
(
"calling notify client
\n
"
);
TRACE
(
"notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) dwFlags=(%ld)
\n
"
,
lpWaveHdr
,
wwo
->
lpPlayPtr
,
lpWaveHdr
->
dwFlags
);
wodNotifyClient
(
wwo
,
WOM_DONE
,
(
DWORD
)
lpWaveHdr
,
0
);
}
TRACE
(
"Not notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) lpLoopPtr=(%p)
\n
"
,
lpWaveHdr
,
wwo
->
lpPlayPtr
,
wwo
->
lpLoopPtr
);
retval
=
(
lpWaveHdr
&&
lpWaveHdr
!=
wwo
->
lpPlayPtr
&&
lpWaveHdr
!=
wwo
->
lpLoopPtr
)
?
0
:
INFINITE
;
...
...
@@ -1042,12 +1194,16 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize)
return
MMSYSERR_BADDEVICEID
;
}
TRACE
(
"dwSupport=(0x%lx), dwFormats=(0x%lx)
\n
"
,
WOutDev
[
wDevID
].
caps
.
dwSupport
,
WOutDev
[
wDevID
].
caps
.
dwFormats
);
memcpy
(
lpCaps
,
&
WOutDev
[
wDevID
].
caps
,
min
(
dwSize
,
sizeof
(
*
lpCaps
)));
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* wodOpen [internal]
*
* NOTE: doesn't it seem like there is a race condition if you try to open
* the same device twice?
*/
static
DWORD
wodOpen
(
WORD
wDevID
,
LPWAVEOPENDESC
lpDesc
,
DWORD
dwFlags
)
{
...
...
@@ -1082,27 +1238,6 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
return
WAVERR_BADFORMAT
;
}
wwo
=
&
WOutDev
[
wDevID
];
wwo
->
wDevID
=
wDevID
;
/* Set things up before we call JACK_OpenDevice because */
/* we will start getting callbacks before JACK_OpenDevice */
/* even returns and we want to be initialized before then */
wwo
->
state
=
WINE_WS_STOPPED
;
/* start in a stopped state */
wwo
->
dwPlayedTotal
=
0
;
/* zero out these totals */
wwo
->
dwWrittenTotal
=
0
;
wwo
->
bytesInJack
=
0
;
wwo
->
tickCountMS
=
0
;
InitializeCriticalSection
(
&
wwo
->
access_crst
);
/* initialize the critical section */
/* open up jack ports for this device */
if
(
!
JACK_OpenDevice
(
&
WOutDev
[
wDevID
]))
{
ERR
(
"JACK_OpenDevice(%d) failed
\n
"
,
wDevID
);
return
MMSYSERR_ERROR
;
/* return unspecified error */
}
/* only PCM format is supported so far... */
if
(
lpDesc
->
lpFormat
->
wFormatTag
!=
WAVE_FORMAT_PCM
||
lpDesc
->
lpFormat
->
nChannels
==
0
||
...
...
@@ -1122,15 +1257,41 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
return
MMSYSERR_NOERROR
;
}
dwFlags
&=
~
WAVE_DIRECTSOUND
;
/* direct sound not supported, ignore the flag */
wwo
=
&
WOutDev
[
wDevID
];
wwo
->
wDevID
=
wDevID
;
/* Set things up before we call JACK_OpenWaveOutDevice because */
/* we will start getting callbacks before JACK_OpenWaveOutDevice */
/* even returns and we want to be initialized before then */
wwo
->
state
=
WINE_WS_STOPPED
;
/* start in a stopped state */
wwo
->
dwPlayedTotal
=
0
;
/* zero out these totals */
wwo
->
dwWrittenTotal
=
0
;
wwo
->
bytesInJack
=
0
;
wwo
->
tickCountMS
=
0
;
/* Initialize volume to full level */
wwo
->
volume_left
=
100
;
wwo
->
volume_right
=
100
;
InitializeCriticalSection
(
&
wwo
->
access_crst
);
/* initialize the critical section */
EnterCriticalSection
(
&
wwo
->
access_crst
);
dwFlags
&=
~
WAVE_DIRECTSOUND
;
/* direct sound not supported, ignore the flag */
wwo
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
memcpy
(
&
wwo
->
waveDesc
,
lpDesc
,
sizeof
(
WAVEOPENDESC
));
memcpy
(
&
wwo
->
format
,
lpDesc
->
lpFormat
,
sizeof
(
PCMWAVEFORMAT
));
/* open up jack ports for this device */
if
(
!
JACK_OpenWaveOutDevice
(
&
WOutDev
[
wDevID
]))
{
ERR
(
"JACK_OpenWaveOutDevice(%d) failed
\n
"
,
wDevID
);
LeaveCriticalSection
(
&
wwo
->
access_crst
);
DeleteCriticalSection
(
&
wwo
->
access_crst
);
/* delete the critical section so we can initialize it again from wodOpen() */
return
MMSYSERR_ERROR
;
/* return unspecified error */
}
LeaveCriticalSection
(
&
wwo
->
access_crst
);
/* display the current wave format */
...
...
@@ -1147,10 +1308,11 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
wwo
->
sample_rate
,
wwo
->
format
.
wf
.
nSamplesPerSec
);
#if JACK_CLOSE_HACK
JACK_CloseDevice
(
wwo
,
FALSE
);
/* close this device, don't force the client to close */
JACK_Close
WaveOut
Device
(
wwo
,
FALSE
);
/* close this device, don't force the client to close */
#else
JACK_CloseDevice
(
wwo
);
/* close this device */
JACK_Close
WaveOut
Device
(
wwo
);
/* close this device */
#endif
DeleteCriticalSection
(
&
wwo
->
access_crst
);
/* delete the critical section so we can initialize it again from wodOpen() */
return
WAVERR_BADFORMAT
;
}
...
...
@@ -1200,11 +1362,11 @@ static DWORD wodClose(WORD wDevID)
wwo
->
state
=
WINE_WS_CLOSED
;
/* mark the device as closed */
#if JACK_CLOSE_HACK
JACK_CloseDevice
(
wwo
,
FALSE
);
/* close the jack device, DO NOT force the client to close */
JACK_Close
WaveOut
Device
(
wwo
,
FALSE
);
/* close the jack device, DO NOT force the client to close */
#else
JACK_CloseDevice
(
wwo
);
/* close the jack device */
DeleteCriticalSection
(
&
wwo
->
access_crst
);
/* delete the critical section so we can initialize it again from wodOpen() */
JACK_CloseWaveOutDevice
(
wwo
);
/* close the jack device */
#endif
DeleteCriticalSection
(
&
wwo
->
access_crst
);
/* delete the critical section so we can initialize it again from wodOpen() */
ret
=
wodNotifyClient
(
wwo
,
WOM_CLOSE
,
0L
,
0L
);
}
...
...
@@ -1212,6 +1374,7 @@ static DWORD wodClose(WORD wDevID)
return
ret
;
}
/**************************************************************************
* wodWrite [internal]
*
...
...
@@ -1254,9 +1417,6 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
for
(
wh
=
&
(
wwo
->
lpQueuePtr
);
*
wh
;
wh
=
&
((
*
wh
)
->
lpNext
));
*
wh
=
lpWaveHdr
;
LeaveCriticalSection
(
&
wwo
->
access_crst
);
EnterCriticalSection
(
&
wwo
->
access_crst
);
if
(
!
wwo
->
lpPlayPtr
)
wodHelper_BeginWaveHdr
(
wwo
,
lpWaveHdr
);
if
(
wwo
->
state
==
WINE_WS_STOPPED
)
...
...
@@ -1626,6 +1786,619 @@ static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid)
*======================================================================*/
/**************************************************************************
* widNotifyClient [internal]
*/
static
DWORD
widNotifyClient
(
WINE_WAVEIN
*
wwi
,
WORD
wMsg
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
TRACE
(
"wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX
\n
"
,
wMsg
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
WIM_OPEN
:
case
WIM_CLOSE
:
case
WIM_DATA
:
if
(
wwi
->
wFlags
!=
DCB_NULL
&&
!
DriverCallback
(
wwi
->
waveDesc
.
dwCallback
,
wwi
->
wFlags
,
(
HDRVR
)
wwi
->
waveDesc
.
hWave
,
wMsg
,
wwi
->
waveDesc
.
dwInstance
,
dwParam1
,
dwParam2
))
{
WARN
(
"can't notify client !
\n
"
);
return
MMSYSERR_ERROR
;
}
break
;
default:
FIXME
(
"Unknown callback message %u
\n
"
,
wMsg
);
return
MMSYSERR_INVALPARAM
;
}
return
MMSYSERR_NOERROR
;
}
/******************************************************************
* JACK_callback_wwi
*/
/* everytime the jack server wants something from us it calls this
function */
int
JACK_callback_wwi
(
nframes_t
nframes
,
void
*
arg
)
{
sample_t
*
in_l
;
sample_t
*
in_r
=
0
;
WINE_WAVEIN
*
wwi
=
(
WINE_WAVEIN
*
)
arg
;
TRACE
(
"wDevID: %u, nframes %u
\n
"
,
wwi
->
wDevID
,
nframes
);
if
(
!
wwi
->
client
)
ERR
(
"client is closed, this is weird...
\n
"
);
in_l
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwi
->
in_port_l
,
nframes
);
if
(
wwi
->
in_port_r
)
in_r
=
(
sample_t
*
)
fp_jack_port_get_buffer
(
wwi
->
in_port_r
,
nframes
);
EnterCriticalSection
(
&
wwi
->
access_crst
);
if
((
wwi
->
lpQueuePtr
!=
NULL
)
&&
(
wwi
->
state
==
WINE_WS_PLAYING
))
{
LPWAVEHDR
lpWaveHdr
=
wwi
->
lpQueuePtr
;
nframes_t
jackFramesLeft
=
nframes
;
#if JACK_CLOSE_HACK
if
(
wwi
->
in_use
==
FALSE
)
{
/* do nothing if nothing is being recorded */
return
0
;
}
#endif
TRACE
(
"wwi.state == WINE_WS_PLAYING
\n
"
);
while
(
lpWaveHdr
&&
jackFramesLeft
)
{
DWORD
waveHdrFramesLeft
=
(
lpWaveHdr
->
dwBufferLength
-
lpWaveHdr
->
dwBytesRecorded
)
/
(
sizeof
(
short
)
*
wwi
->
format
.
wf
.
nChannels
);
DWORD
numFrames
=
min
(
jackFramesLeft
,
waveHdrFramesLeft
);
TRACE
(
"dwBufferLength=(%lu) dwBytesRecorded=(%ld)
\n
"
,
lpWaveHdr
->
dwBufferLength
,
lpWaveHdr
->
dwBytesRecorded
);
TRACE
(
"jackFramesLeft=(%u) waveHdrFramesLeft=(%lu)
\n
"
,
jackFramesLeft
,
waveHdrFramesLeft
);
if
(
!
in_r
)
{
/* mono */
sample_move_s16_d16
((
short
*
)((
char
*
)
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
),
in_l
+
(
nframes
-
jackFramesLeft
),
numFrames
,
1
);
}
else
{
/* stereo */
sample_move_s16_d16
((
short
*
)((
char
*
)
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
),
in_l
+
(
nframes
-
jackFramesLeft
),
numFrames
,
2
);
sample_move_s16_d16
((
short
*
)((
char
*
)
lpWaveHdr
->
lpData
+
lpWaveHdr
->
dwBytesRecorded
+
sizeof
(
short
)),
in_r
+
(
nframes
-
jackFramesLeft
),
numFrames
,
2
);
}
lpWaveHdr
->
dwBytesRecorded
+=
(
numFrames
*
sizeof
(
short
)
*
wwi
->
format
.
wf
.
nChannels
);
jackFramesLeft
-=
numFrames
;
if
(
lpWaveHdr
->
dwBytesRecorded
>=
lpWaveHdr
->
dwBufferLength
)
{
/* must copy the value of next waveHdr, because we have no idea of what
* will be done with the content of lpWaveHdr in callback
*/
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
TRACE
(
"WaveHdr full. dwBytesRecorded=(%lu) dwFlags=(0x%lx)
\n
"
,
lpWaveHdr
->
dwBytesRecorded
,
lpWaveHdr
->
dwFlags
);
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
lpWaveHdr
=
wwi
->
lpQueuePtr
=
lpNext
;
}
}
TRACE
(
"jackFramesLeft=(%u) lpWaveHdr=(%p)
\n
"
,
jackFramesLeft
,
lpWaveHdr
);
if
(
jackFramesLeft
>
0
)
{
WARN
(
"Record buffer ran out of WaveHdrs
\n
"
);
}
}
LeaveCriticalSection
(
&
wwi
->
access_crst
);
return
0
;
}
/******************************************************************
* JACK_OpenWaveInDevice
*/
static
int
JACK_OpenWaveInDevice
(
WINE_WAVEIN
*
wwi
,
WORD
nChannels
)
{
const
char
**
ports
;
int
i
;
char
client_name
[
64
];
jack_port_t
*
in_port_l
;
jack_port_t
*
in_port_r
=
0
;
jack_client_t
*
client
;
int
failed
=
0
;
TRACE
(
"creating jack client and setting up callbacks
\n
"
);
if
((
nChannels
==
0
)
||
(
nChannels
>
2
))
{
ERR
(
"nChannels = (%d), but we only support mono or stereo.
\n
"
,
nChannels
);
return
0
;
}
#if JACK_CLOSE_HACK
/* see if this device is already open */
if
(
wwi
->
client
)
{
/* if this device is already in use then it is bad for us to be in here */
if
(
wwi
->
in_use
)
return
0
;
TRACE
(
"using existing client
\n
"
);
wwi
->
in_use
=
TRUE
;
return
1
;
}
#endif
/* zero out the buffer pointer and the size of the buffer */
wwi
->
sound_buffer
=
0
;
wwi
->
buffer_size
=
0
;
/* try to become a client of the JACK server */
snprintf
(
client_name
,
sizeof
(
client_name
),
"wine_jack_in_%d"
,
wwi
->
wDevID
);
TRACE
(
"client name '%s'
\n
"
,
client_name
);
if
((
client
=
fp_jack_client_new
(
client_name
))
==
0
)
{
/* jack has problems with shutting down clients, so lets */
/* wait a short while and try once more before we give up */
Sleep
(
250
);
if
((
client
=
fp_jack_client_new
(
client_name
))
==
0
)
{
ERR
(
"jack server not running?
\n
"
);
return
0
;
}
}
wwi
->
client
=
client
;
/* tell the JACK server to call `JACK_wwi_callback()' whenever
there is work to be done. */
fp_jack_set_process_callback
(
client
,
JACK_callback_wwi
,
wwi
);
/* tell the JACK server to call `JACK_bufsize_wwi()' whenever
the maximum number of frames that will be passed
to `JACK_Callback()' changes */
fp_jack_set_buffer_size_callback
(
client
,
JACK_bufsize_wwi
,
wwi
);
/* tell the JACK server to call `srate()' whenever
the sample rate of the system changes. */
fp_jack_set_sample_rate_callback
(
client
,
JACK_srate
,
wwi
);
/* tell the JACK server to call `jack_shutdown()' if
it ever shuts down, either entirely, or if it
just decides to stop calling us. */
fp_jack_on_shutdown
(
client
,
JACK_shutdown_wwi
,
wwi
);
/* display the current sample rate. once the client is activated
(see below), you should rely on your own sample rate
callback (see above) for this value. */
wwi
->
sample_rate
=
fp_jack_get_sample_rate
(
client
);
TRACE
(
"engine sample rate: %lu
\n
"
,
wwi
->
sample_rate
);
/* create the left and right channel output ports */
/* jack's ports are all mono so for stereo you need two */
in_port_l
=
fp_jack_port_register
(
client
,
"in_l"
,
JACK_DEFAULT_AUDIO_TYPE
,
JackPortIsInput
,
0
);
wwi
->
in_port_l
=
in_port_l
;
TRACE
(
"Created port. (%p)
\n
"
,
in_port_l
);
if
(
nChannels
==
2
)
{
in_port_r
=
fp_jack_port_register
(
client
,
"in_r"
,
JACK_DEFAULT_AUDIO_TYPE
,
JackPortIsInput
,
0
);
TRACE
(
"Created port. (%p)
\n
"
,
in_port_r
);
}
wwi
->
in_port_r
=
in_port_r
;
#if JACK_CLOSE_HACK
wwi
->
in_use
=
TRUE
;
/* mark this device as in use since it now is ;-) */
#endif
TRACE
(
"activating client.
\n
"
);
/* tell the JACK server that we are ready to roll */
if
(
fp_jack_activate
(
client
))
{
ERR
(
"cannot activate client
\n
"
);
return
0
;
}
TRACE
(
"activated client.
\n
"
);
/* figure out what the ports that we want to output on are */
/* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
/* this way works if names are changed */
ports
=
fp_jack_get_ports
(
client
,
NULL
,
NULL
,
JackPortIsPhysical
|
JackPortIsOutput
);
/* display a trace of the output ports we found */
for
(
i
=
0
;
ports
[
i
];
i
++
)
{
TRACE
(
"ports[%d] = '%s'
\n
"
,
i
,
ports
[
i
]);
}
if
(
!
ports
)
{
ERR
(
"jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsOutput'
\n
"
);
}
/* connect the ports. Note: you can't do this before
the client is activated (this may change in the future).
*/
/* we want to connect to two ports so we have stereo input ;-) */
if
(
fp_jack_connect
(
client
,
ports
[
0
],
fp_jack_port_name
(
in_port_l
)))
{
ERR
(
"cannot connect to input port %d('%s')
\n
"
,
0
,
ports
[
0
]);
failed
=
1
;
}
TRACE
(
"Connected (%s)<->(%s)
\n
"
,
ports
[
0
],
fp_jack_port_name
(
in_port_l
));
if
((
nChannels
==
2
)
&&
in_port_r
)
{
if
(
fp_jack_connect
(
client
,
ports
[
1
],
fp_jack_port_name
(
in_port_r
)))
{
ERR
(
"cannot connect to input port %d('%s')
\n
"
,
1
,
ports
[
1
]);
failed
=
1
;
}
TRACE
(
"Connected (%s)<->(%s)
\n
"
,
ports
[
1
],
fp_jack_port_name
(
in_port_r
));
}
free
(
ports
);
/* free the returned array of ports */
/* if something failed we need to shut the client down and return 0 */
if
(
failed
)
{
#if JACK_CLOSE_HACK
JACK_CloseWaveInDevice
(
wwi
,
TRUE
);
#else
JACK_CloseWaveInDevice
(
wwi
);
#endif
return
0
;
}
TRACE
(
"return success.
\n
"
);
return
1
;
/* return success */
}
/**************************************************************************
* widGetDevCaps [internal]
*/
static
DWORD
widGetDevCaps
(
WORD
wDevID
,
LPWAVEINCAPSA
lpCaps
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %lu);
\n
"
,
wDevID
,
lpCaps
,
dwSize
);
if
(
lpCaps
==
NULL
)
return
MMSYSERR_NOTENABLED
;
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
TRACE
(
"MAX_WAVEINDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
memcpy
(
lpCaps
,
&
WInDev
[
wDevID
].
caps
,
min
(
dwSize
,
sizeof
(
*
lpCaps
)));
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widOpen [internal]
*/
static
DWORD
widOpen
(
WORD
wDevID
,
LPWAVEOPENDESC
lpDesc
,
DWORD
dwFlags
)
{
WINE_WAVEIN
*
wwi
;
DWORD
retval
;
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpDesc
,
dwFlags
);
if
(
lpDesc
==
NULL
)
{
WARN
(
"Invalid Parameter !
\n
"
);
return
MMSYSERR_INVALPARAM
;
}
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
TRACE
(
"MAX_WAVEINDRV reached !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
#if JACK_CLOSE_HACK
if
(
WInDev
[
wDevID
].
client
&&
WOutDev
[
wDevID
].
in_use
)
#else
if
(
WInDev
[
wDevID
].
client
)
#endif
{
TRACE
(
"device %d already allocated
\n
"
,
wDevID
);
return
MMSYSERR_ALLOCATED
;
}
/* make sure we aren't being opened in 8 bit mode */
if
(
lpDesc
->
lpFormat
->
wBitsPerSample
==
8
)
{
TRACE
(
"8bits per sample unsupported, returning WAVERR_BADFORMAT
\n
"
);
return
WAVERR_BADFORMAT
;
}
/* only PCM format is supported so far... */
if
(
lpDesc
->
lpFormat
->
wFormatTag
!=
WAVE_FORMAT_PCM
||
lpDesc
->
lpFormat
->
nChannels
==
0
||
lpDesc
->
lpFormat
->
nSamplesPerSec
==
0
)
{
WARN
(
"Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
WAVERR_BADFORMAT
;
}
if
(
dwFlags
&
WAVE_FORMAT_QUERY
)
{
TRACE
(
"Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !
\n
"
,
lpDesc
->
lpFormat
->
wFormatTag
,
lpDesc
->
lpFormat
->
nChannels
,
lpDesc
->
lpFormat
->
nSamplesPerSec
);
return
MMSYSERR_NOERROR
;
}
wwi
=
&
WInDev
[
wDevID
];
wwi
->
wDevID
=
wDevID
;
/* Set things up before we call JACK_OpenWaveOutDevice because */
/* we will start getting callbacks before JACK_OpenWaveOutDevice */
/* even returns and we want to be initialized before then */
wwi
->
state
=
WINE_WS_STOPPED
;
/* start in a stopped state */
InitializeCriticalSection
(
&
wwi
->
access_crst
);
/* initialize the critical section */
EnterCriticalSection
(
&
wwi
->
access_crst
);
/* open up jack ports for this device */
if
(
!
JACK_OpenWaveInDevice
(
&
WInDev
[
wDevID
],
lpDesc
->
lpFormat
->
nChannels
))
{
ERR
(
"JACK_OpenWaveInDevice(%d) failed
\n
"
,
wDevID
);
LeaveCriticalSection
(
&
wwi
->
access_crst
);
DeleteCriticalSection
(
&
wwi
->
access_crst
);
return
MMSYSERR_ERROR
;
/* return unspecified error */
}
dwFlags
&=
~
WAVE_DIRECTSOUND
;
/* direct sound not supported, ignore the flag */
wwi
->
wFlags
=
HIWORD
(
dwFlags
&
CALLBACK_TYPEMASK
);
memcpy
(
&
wwi
->
waveDesc
,
lpDesc
,
sizeof
(
WAVEOPENDESC
));
memcpy
(
&
wwi
->
format
,
lpDesc
->
lpFormat
,
sizeof
(
PCMWAVEFORMAT
));
LeaveCriticalSection
(
&
wwi
->
access_crst
);
/* display the current wave format */
TRACE
(
"wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!
\n
"
,
wwi
->
format
.
wBitsPerSample
,
wwi
->
format
.
wf
.
nAvgBytesPerSec
,
wwi
->
format
.
wf
.
nSamplesPerSec
,
wwi
->
format
.
wf
.
nChannels
,
wwi
->
format
.
wf
.
nBlockAlign
);
/* make sure that we have the same sample rate in our audio stream */
/* as we do in the jack server */
if
(
wwi
->
format
.
wf
.
nSamplesPerSec
!=
wwi
->
sample_rate
)
{
TRACE
(
"error: jack server sample rate is '%ld', wave sample rate is '%ld'
\n
"
,
wwi
->
sample_rate
,
wwi
->
format
.
wf
.
nSamplesPerSec
);
#if JACK_CLOSE_HACK
JACK_CloseWaveInDevice
(
wwi
,
FALSE
);
/* close this device, don't force the client to close */
#else
JACK_CloseWaveInDevice
(
wwi
);
/* close this device */
#endif
DeleteCriticalSection
(
&
wwi
->
access_crst
);
return
WAVERR_BADFORMAT
;
}
/* check for an invalid number of bits per sample */
if
(
wwi
->
format
.
wBitsPerSample
==
0
)
{
WARN
(
"Resetting zeroed wBitsPerSample to 16
\n
"
);
wwi
->
format
.
wBitsPerSample
=
16
*
(
wwi
->
format
.
wf
.
nAvgBytesPerSec
/
wwi
->
format
.
wf
.
nSamplesPerSec
)
/
wwi
->
format
.
wf
.
nChannels
;
}
TRACE
(
"notify client.
\n
"
);
EnterCriticalSection
(
&
wwi
->
access_crst
);
retval
=
widNotifyClient
(
wwi
,
WIM_OPEN
,
0L
,
0L
);
LeaveCriticalSection
(
&
wwi
->
access_crst
);
return
retval
;
}
/**************************************************************************
* widClose [internal]
*/
static
DWORD
widClose
(
WORD
wDevID
)
{
DWORD
ret
=
MMSYSERR_NOERROR
;
WINE_WAVEIN
*
wwi
;
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
!
WInDev
[
wDevID
].
client
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_BADDEVICEID
;
}
wwi
=
&
WInDev
[
wDevID
];
if
(
wwi
->
lpQueuePtr
)
{
WARN
(
"buffers still playing !
\n
"
);
ret
=
WAVERR_STILLPLAYING
;
}
else
{
/* sanity check: this should not happen since the device must have been reset before */
if
(
wwi
->
lpQueuePtr
)
ERR
(
"out of sync
\n
"
);
wwi
->
state
=
WINE_WS_CLOSED
;
/* mark the device as closed */
#if JACK_CLOSE_HACK
JACK_CloseWaveInDevice
(
wwi
,
FALSE
);
/* close the jack device, DO NOT force the client to close */
#else
JACK_CloseWaveInDevice
(
wwi
);
/* close the jack device */
#endif
DeleteCriticalSection
(
&
wwi
->
access_crst
);
/* delete the critical section so we can initialize it again from wodOpen() */
ret
=
widNotifyClient
(
wwi
,
WIM_CLOSE
,
0L
,
0L
);
}
return
ret
;
}
/**************************************************************************
* widAddBuffer [internal]
*/
static
DWORD
widAddBuffer
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
WINE_WAVEIN
*
wwi
=
&
WInDev
[
wDevID
];
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't do it !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
!
(
lpWaveHdr
->
dwFlags
&
WHDR_PREPARED
))
{
TRACE
(
"never been prepared !
\n
"
);
return
WAVERR_UNPREPARED
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
{
TRACE
(
"header already in use !
\n
"
);
return
WAVERR_STILLPLAYING
;
}
lpWaveHdr
->
dwFlags
|=
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwBytesRecorded
=
0
;
lpWaveHdr
->
lpNext
=
NULL
;
EnterCriticalSection
(
&
wwi
->
access_crst
);
/* insert buffer at end of queue */
{
LPWAVEHDR
*
wh
;
for
(
wh
=
&
(
wwi
->
lpQueuePtr
);
*
wh
;
wh
=
&
((
*
wh
)
->
lpNext
));
*
wh
=
lpWaveHdr
;
}
LeaveCriticalSection
(
&
wwi
->
access_crst
);
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widPrepare [internal]
*/
static
DWORD
widPrepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
return
MMSYSERR_INVALHANDLE
;
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
return
WAVERR_STILLPLAYING
;
lpWaveHdr
->
dwFlags
|=
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
&=
~
WHDR_DONE
;
lpWaveHdr
->
dwBytesRecorded
=
0
;
lpWaveHdr
->
lpNext
=
NULL
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widUnprepare [internal]
*/
static
DWORD
widUnprepare
(
WORD
wDevID
,
LPWAVEHDR
lpWaveHdr
,
DWORD
dwSize
)
{
TRACE
(
"(%u, %p, %08lX);
\n
"
,
wDevID
,
lpWaveHdr
,
dwSize
);
if
(
wDevID
>=
MAX_WAVEINDRV
)
{
WARN
(
"bad device ID !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
lpWaveHdr
->
dwFlags
&
WHDR_INQUEUE
)
{
TRACE
(
"Still playing...
\n
"
);
return
WAVERR_STILLPLAYING
;
}
lpWaveHdr
->
dwFlags
&=
~
WHDR_PREPARED
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStart [internal]
*/
static
DWORD
widStart
(
WORD
wDevID
)
{
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't start recording !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
WInDev
[
wDevID
].
state
=
WINE_WS_PLAYING
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widStop [internal]
*/
static
DWORD
widStop
(
WORD
wDevID
)
{
WINE_WAVEIN
*
wwi
=
&
WInDev
[
wDevID
];
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't stop !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
if
(
wwi
->
state
!=
WINE_WS_STOPPED
)
{
WAVEHDR
*
lpWaveHdr
;
/* do something here to stop recording ??? */
/* return current buffer to app */
lpWaveHdr
=
wwi
->
lpQueuePtr
;
if
(
lpWaveHdr
)
{
LPWAVEHDR
lpNext
=
lpWaveHdr
->
lpNext
;
TRACE
(
"stop %p %p
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
wwi
->
lpQueuePtr
=
lpNext
;
}
}
wwi
->
state
=
WINE_WS_STOPPED
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widReset [internal]
*/
static
DWORD
widReset
(
WORD
wDevID
)
{
WINE_WAVEIN
*
wwi
=
&
WInDev
[
wDevID
];
WAVEHDR
*
lpWaveHdr
;
TRACE
(
"(%u);
\n
"
,
wDevID
);
if
(
wDevID
>=
MAX_WAVEINDRV
||
WInDev
[
wDevID
].
state
==
WINE_WS_CLOSED
)
{
WARN
(
"can't reset !
\n
"
);
return
MMSYSERR_INVALHANDLE
;
}
wwi
->
state
=
WINE_WS_STOPPED
;
/* return all buffers to the app */
for
(
lpWaveHdr
=
wwi
->
lpQueuePtr
;
lpWaveHdr
;
lpWaveHdr
=
lpWaveHdr
->
lpNext
)
{
TRACE
(
"reset %p %p
\n
"
,
lpWaveHdr
,
lpWaveHdr
->
lpNext
);
lpWaveHdr
->
dwFlags
&=
~
WHDR_INQUEUE
;
lpWaveHdr
->
dwFlags
|=
WHDR_DONE
;
widNotifyClient
(
wwi
,
WIM_DATA
,
(
DWORD
)
lpWaveHdr
,
0
);
}
wwi
->
lpQueuePtr
=
NULL
;
return
MMSYSERR_NOERROR
;
}
/**************************************************************************
* widMessage (WINEJACK.6)
*/
DWORD
WINAPI
JACK_widMessage
(
WORD
wDevID
,
WORD
wMsg
,
DWORD
dwUser
,
...
...
@@ -1634,11 +2407,39 @@ DWORD WINAPI JACK_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
TRACE
(
"(%u, %04X, %08lX, %08lX, %08lX);
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
switch
(
wMsg
)
{
case
DRVM_INIT
:
case
DRVM_EXIT
:
case
DRVM_ENABLE
:
case
DRVM_DISABLE
:
/* FIXME: Pretend this is supported */
return
0
;
case
WIDM_OPEN
:
return
widOpen
(
wDevID
,
(
LPWAVEOPENDESC
)
dwParam1
,
dwParam2
);
case
WIDM_CLOSE
:
return
widClose
(
wDevID
);
case
WIDM_ADDBUFFER
:
return
widAddBuffer
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_PREPARE
:
return
widPrepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_UNPREPARE
:
return
widUnprepare
(
wDevID
,
(
LPWAVEHDR
)
dwParam1
,
dwParam2
);
case
WIDM_GETDEVCAPS
:
return
widGetDevCaps
(
wDevID
,
(
LPWAVEINCAPSA
)
dwParam1
,
dwParam2
);
case
WIDM_GETNUMDEVS
:
return
MAX_WAVEINDRV
;
case
WIDM_RESET
:
return
widReset
(
wDevID
);
case
WIDM_START
:
return
widStart
(
wDevID
);
case
WIDM_STOP
:
return
widStop
(
wDevID
);
default:
FIXME
(
"unknown message %d!
\n
"
,
wMsg
);
}
return
MMSYSERR_NOTSUPPORTED
;
}
#else
/* !HAVE_JACK_JACK_H */
DWORD
WINAPI
JACK_widMessage
(
WORD
wDevID
,
WORD
wMsg
,
DWORD
dwUser
,
DWORD
dwParam1
,
DWORD
dwParam2
)
{
FIXME
(
"(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine
\n
"
,
wDevID
,
wMsg
,
dwUser
,
dwParam1
,
dwParam2
);
return
MMSYSERR_NOTENABLED
;
}
/**************************************************************************
* wodMessage (WINEJACK.7)
*/
...
...
dlls/winmm/winejack/winejack.drv.spec
View file @
ed69f0bf
@ stdcall DriverProc(long long long long long) JACK_DriverProc
@ stdcall wodMessage(long long long long long) JACK_wodMessage
@ stdcall widMessage(long long long long long) JACK_widMessage
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment