dsound: Use AudioClient buffer statistics.
Signed-off-by: Andrew Eikum <aeikum@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
77184106c8
commit
569ed159b0
|
@ -158,7 +158,6 @@ static HRESULT DirectSoundDevice_Create(DirectSoundDevice ** ppDevice)
|
||||||
device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
|
device->ds3dl.flRolloffFactor = DS3D_DEFAULTROLLOFFFACTOR;
|
||||||
device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
|
device->ds3dl.flDopplerFactor = DS3D_DEFAULTDOPPLERFACTOR;
|
||||||
|
|
||||||
device->prebuf = ds_snd_queue_max;
|
|
||||||
device->guid = GUID_NULL;
|
device->guid = GUID_NULL;
|
||||||
|
|
||||||
/* Set default wave format (may need it for waveOutOpen) */
|
/* Set default wave format (may need it for waveOutOpen) */
|
||||||
|
|
|
@ -93,7 +93,6 @@ WCHAR wine_vxd_drv[] = { 'w','i','n','e','m','m','.','v','x','d', 0 };
|
||||||
|
|
||||||
/* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */
|
/* All default settings, you most likely don't want to touch these, see wiki on UsefulRegistryKeys */
|
||||||
int ds_hel_buflen = 32768 * 2;
|
int ds_hel_buflen = 32768 * 2;
|
||||||
int ds_snd_queue_max = 10;
|
|
||||||
static HINSTANCE instance;
|
static HINSTANCE instance;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -146,15 +145,10 @@ void setup_dsound_options(void)
|
||||||
if (!get_config_key( hkey, appkey, "HelBuflen", buffer, MAX_PATH ))
|
if (!get_config_key( hkey, appkey, "HelBuflen", buffer, MAX_PATH ))
|
||||||
ds_hel_buflen = atoi(buffer);
|
ds_hel_buflen = atoi(buffer);
|
||||||
|
|
||||||
if (!get_config_key( hkey, appkey, "SndQueueMax", buffer, MAX_PATH ))
|
|
||||||
ds_snd_queue_max = atoi(buffer);
|
|
||||||
|
|
||||||
|
|
||||||
if (appkey) RegCloseKey( appkey );
|
if (appkey) RegCloseKey( appkey );
|
||||||
if (hkey) RegCloseKey( hkey );
|
if (hkey) RegCloseKey( hkey );
|
||||||
|
|
||||||
TRACE("ds_hel_buflen = %d\n", ds_hel_buflen);
|
TRACE("ds_hel_buflen = %d\n", ds_hel_buflen);
|
||||||
TRACE("ds_snd_queue_max = %d\n", ds_snd_queue_max);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * get_device_id(LPCGUID pGuid)
|
static const char * get_device_id(LPCGUID pGuid)
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
#define DS_MAX_CHANNELS 6
|
#define DS_MAX_CHANNELS 6
|
||||||
|
|
||||||
extern int ds_hel_buflen DECLSPEC_HIDDEN;
|
extern int ds_hel_buflen DECLSPEC_HIDDEN;
|
||||||
extern int ds_snd_queue_max DECLSPEC_HIDDEN;
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Predeclare the interface implementation structures
|
* Predeclare the interface implementation structures
|
||||||
|
@ -76,10 +75,9 @@ struct DirectSoundDevice
|
||||||
DSCAPS drvcaps;
|
DSCAPS drvcaps;
|
||||||
DWORD priolevel, sleeptime;
|
DWORD priolevel, sleeptime;
|
||||||
PWAVEFORMATEX pwfx, primary_pwfx;
|
PWAVEFORMATEX pwfx, primary_pwfx;
|
||||||
UINT playing_offs_bytes, in_mmdev_bytes, prebuf;
|
UINT playing_offs_bytes, in_mmdev_bytes;
|
||||||
DWORD fraglen;
|
|
||||||
LPBYTE buffer;
|
LPBYTE buffer;
|
||||||
DWORD writelead, buflen, state, playpos, mixpos;
|
DWORD writelead, buflen, aclen, fraglen, state, playpos, pad;
|
||||||
int nrofbuffers;
|
int nrofbuffers;
|
||||||
IDirectSoundBufferImpl** buffers;
|
IDirectSoundBufferImpl** buffers;
|
||||||
RTL_RWLOCK buffer_list_lock;
|
RTL_RWLOCK buffer_list_lock;
|
||||||
|
@ -211,7 +209,6 @@ HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
HRESULT DSOUND_PrimaryDestroy(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
HRESULT DSOUND_PrimaryPlay(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
HRESULT DSOUND_PrimaryStop(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_PrimaryGetPosition(DirectSoundDevice *device, LPDWORD playpos, LPDWORD writepos) DECLSPEC_HIDDEN;
|
|
||||||
LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex) DECLSPEC_HIDDEN;
|
LPWAVEFORMATEX DSOUND_CopyFormat(LPCWAVEFORMATEX wfex) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) DECLSPEC_HIDDEN;
|
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave) DECLSPEC_HIDDEN;
|
||||||
HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -613,86 +613,27 @@ static void DSOUND_MixToPrimary(const DirectSoundDevice *device, DWORD writepos,
|
||||||
* Returns: None
|
* Returns: None
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
static void DSOUND_WaveQueue(DirectSoundDevice *device, LPBYTE pos, DWORD bytes)
|
||||||
{
|
{
|
||||||
DWORD prebuf_frames, prebuf_bytes, read_offs_bytes;
|
|
||||||
BYTE *buffer;
|
BYTE *buffer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p)\n", device);
|
TRACE("(%p)\n", device);
|
||||||
|
|
||||||
read_offs_bytes = (device->playing_offs_bytes + device->in_mmdev_bytes) % device->buflen;
|
hr = IAudioRenderClient_GetBuffer(device->render, bytes / device->pwfx->nBlockAlign, &buffer);
|
||||||
|
|
||||||
TRACE("read_offs_bytes = %u, playing_offs_bytes = %u, in_mmdev_bytes: %u, prebuf = %u\n",
|
|
||||||
read_offs_bytes, device->playing_offs_bytes, device->in_mmdev_bytes, device->prebuf);
|
|
||||||
|
|
||||||
if (!force)
|
|
||||||
{
|
|
||||||
if(device->mixpos < device->playing_offs_bytes)
|
|
||||||
prebuf_bytes = device->mixpos + device->buflen - device->playing_offs_bytes;
|
|
||||||
else
|
|
||||||
prebuf_bytes = device->mixpos - device->playing_offs_bytes;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
/* buffer the maximum amount of frags */
|
|
||||||
prebuf_bytes = device->prebuf * device->fraglen;
|
|
||||||
|
|
||||||
/* limit to the queue we have left */
|
|
||||||
if(device->in_mmdev_bytes + prebuf_bytes > device->prebuf * device->fraglen)
|
|
||||||
prebuf_bytes = device->prebuf * device->fraglen - device->in_mmdev_bytes;
|
|
||||||
|
|
||||||
TRACE("prebuf_bytes = %u\n", prebuf_bytes);
|
|
||||||
|
|
||||||
if(!prebuf_bytes)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(prebuf_bytes + read_offs_bytes > device->buflen){
|
|
||||||
DWORD chunk_bytes = device->buflen - read_offs_bytes;
|
|
||||||
prebuf_frames = chunk_bytes / device->pwfx->nBlockAlign;
|
|
||||||
prebuf_bytes -= chunk_bytes;
|
|
||||||
}else{
|
|
||||||
prebuf_frames = prebuf_bytes / device->pwfx->nBlockAlign;
|
|
||||||
prebuf_bytes = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr = IAudioRenderClient_GetBuffer(device->render, prebuf_frames, &buffer);
|
|
||||||
if(FAILED(hr)){
|
if(FAILED(hr)){
|
||||||
WARN("GetBuffer failed: %08x\n", hr);
|
WARN("GetBuffer failed: %08x\n", hr);
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer, device->buffer + read_offs_bytes,
|
memcpy(buffer, pos, bytes);
|
||||||
prebuf_frames * device->pwfx->nBlockAlign);
|
|
||||||
|
|
||||||
hr = IAudioRenderClient_ReleaseBuffer(device->render, prebuf_frames, 0);
|
hr = IAudioRenderClient_ReleaseBuffer(device->render, bytes / device->pwfx->nBlockAlign, 0);
|
||||||
if(FAILED(hr)){
|
if(FAILED(hr))
|
||||||
WARN("ReleaseBuffer failed: %08x\n", hr);
|
WARN("ReleaseBuffer failed: %08x\n", hr);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
device->in_mmdev_bytes += prebuf_frames * device->pwfx->nBlockAlign;
|
done:
|
||||||
|
device->pad += bytes;
|
||||||
/* check if anything wrapped */
|
|
||||||
if(prebuf_bytes > 0){
|
|
||||||
prebuf_frames = prebuf_bytes / device->pwfx->nBlockAlign;
|
|
||||||
|
|
||||||
hr = IAudioRenderClient_GetBuffer(device->render, prebuf_frames, &buffer);
|
|
||||||
if(FAILED(hr)){
|
|
||||||
WARN("GetBuffer failed: %08x\n", hr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(buffer, device->buffer, prebuf_frames * device->pwfx->nBlockAlign);
|
|
||||||
|
|
||||||
hr = IAudioRenderClient_ReleaseBuffer(device->render, prebuf_frames, 0);
|
|
||||||
if(FAILED(hr)){
|
|
||||||
WARN("ReleaseBuffer failed: %08x\n", hr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
device->in_mmdev_bytes += prebuf_frames * device->pwfx->nBlockAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("in_mmdev_bytes now = %i\n", device->in_mmdev_bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -710,7 +651,8 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, BOOL force)
|
||||||
*/
|
*/
|
||||||
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
static void DSOUND_PerformMix(DirectSoundDevice *device)
|
||||||
{
|
{
|
||||||
UINT32 pad, to_mix_frags, to_mix_bytes;
|
UINT32 pad, maxq, writepos;
|
||||||
|
DWORD block;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
TRACE("(%p)\n", device);
|
TRACE("(%p)\n", device);
|
||||||
|
@ -724,147 +666,81 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
|
||||||
LeaveCriticalSection(&device->mixlock);
|
LeaveCriticalSection(&device->mixlock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
block = device->pwfx->nBlockAlign;
|
||||||
|
pad *= block;
|
||||||
|
device->playpos += device->pad - pad;
|
||||||
|
device->playpos %= device->buflen;
|
||||||
|
device->pad = pad;
|
||||||
|
|
||||||
to_mix_frags = device->prebuf - (pad * device->pwfx->nBlockAlign + device->fraglen - 1) / device->fraglen;
|
maxq = device->aclen - pad;
|
||||||
|
if(!maxq){
|
||||||
to_mix_bytes = to_mix_frags * device->fraglen;
|
/* nothing to do! */
|
||||||
|
LeaveCriticalSection(&device->mixlock);
|
||||||
if(device->in_mmdev_bytes > 0){
|
return;
|
||||||
DWORD delta_bytes = min(to_mix_bytes, device->in_mmdev_bytes);
|
|
||||||
device->in_mmdev_bytes -= delta_bytes;
|
|
||||||
device->playing_offs_bytes += delta_bytes;
|
|
||||||
device->playing_offs_bytes %= device->buflen;
|
|
||||||
}
|
}
|
||||||
|
if (maxq > device->fraglen * 3)
|
||||||
|
maxq = device->fraglen * 3;
|
||||||
|
|
||||||
|
writepos = (device->playpos + pad) % device->buflen;
|
||||||
|
|
||||||
if (device->priolevel != DSSCL_WRITEPRIMARY) {
|
if (device->priolevel != DSSCL_WRITEPRIMARY) {
|
||||||
BOOL recover = FALSE, all_stopped = FALSE;
|
BOOL all_stopped = FALSE;
|
||||||
DWORD playpos, writepos, writelead, maxq, prebuff_max, prebuff_left, size1, size2;
|
|
||||||
LPVOID buf1, buf2;
|
|
||||||
int nfiller;
|
int nfiller;
|
||||||
|
DWORD bpp = device->pwfx->wBitsPerSample>>3;
|
||||||
|
|
||||||
/* the sound of silence */
|
/* the sound of silence */
|
||||||
nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
|
nfiller = device->pwfx->wBitsPerSample == 8 ? 128 : 0;
|
||||||
|
|
||||||
/* get the position in the primary buffer */
|
|
||||||
if (DSOUND_PrimaryGetPosition(device, &playpos, &writepos) != 0){
|
|
||||||
LeaveCriticalSection(&(device->mixlock));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("primary playpos=%d, writepos=%d, clrpos=%d, mixpos=%d, buflen=%d\n",
|
|
||||||
playpos,writepos,device->playpos,device->mixpos,device->buflen);
|
|
||||||
assert(device->playpos < device->buflen);
|
|
||||||
|
|
||||||
/* calc maximum prebuff */
|
|
||||||
prebuff_max = (device->prebuf * device->fraglen);
|
|
||||||
|
|
||||||
/* check how close we are to an underrun. It occurs when the writepos overtakes the mixpos */
|
|
||||||
prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
|
|
||||||
writelead = DSOUND_BufPtrDiff(device->buflen, writepos, playpos);
|
|
||||||
|
|
||||||
/* check for underrun. underrun occurs when the write position passes the mix position
|
/* check for underrun. underrun occurs when the write position passes the mix position
|
||||||
* also wipe out just-played sound data */
|
* also wipe out just-played sound data */
|
||||||
if((prebuff_left > prebuff_max) || (device->state == STATE_STOPPED) || (device->state == STATE_STARTING)){
|
if (!pad)
|
||||||
if (device->state == STATE_STOPPING || device->state == STATE_PLAYING)
|
WARN("Probable buffer underrun\n");
|
||||||
WARN("Probable buffer underrun\n");
|
else if (device->state == STATE_STOPPED ||
|
||||||
else TRACE("Buffer starting or buffer underrun\n");
|
device->state == STATE_STARTING) {
|
||||||
|
TRACE("Buffer restarting\n");
|
||||||
/* recover mixing for all buffers */
|
|
||||||
recover = TRUE;
|
|
||||||
|
|
||||||
/* reset mix position to write position */
|
|
||||||
device->mixpos = writepos;
|
|
||||||
|
|
||||||
ZeroMemory(device->buffer, device->buflen);
|
|
||||||
} else if (playpos < device->playpos) {
|
|
||||||
buf1 = device->buffer + device->playpos;
|
|
||||||
buf2 = device->buffer;
|
|
||||||
size1 = device->buflen - device->playpos;
|
|
||||||
size2 = playpos;
|
|
||||||
FillMemory(buf1, size1, nfiller);
|
|
||||||
if (playpos && (!buf2 || !size2))
|
|
||||||
FIXME("%d: (%d, %d)=>(%d, %d) There should be an additional buffer here!!\n", __LINE__, device->playpos, device->mixpos, playpos, writepos);
|
|
||||||
FillMemory(buf2, size2, nfiller);
|
|
||||||
} else {
|
|
||||||
buf1 = device->buffer + device->playpos;
|
|
||||||
buf2 = NULL;
|
|
||||||
size1 = playpos - device->playpos;
|
|
||||||
size2 = 0;
|
|
||||||
FillMemory(buf1, size1, nfiller);
|
|
||||||
}
|
}
|
||||||
device->playpos = playpos;
|
|
||||||
|
|
||||||
/* find the maximum we can prebuffer from current write position */
|
memset(device->mix_buffer, nfiller, maxq);
|
||||||
maxq = (writelead < prebuff_max) ? (prebuff_max - writelead) : 0;
|
|
||||||
|
|
||||||
TRACE("prebuff_left = %d, prebuff_max = %dx%d=%d, writelead=%d\n",
|
|
||||||
prebuff_left, device->prebuf, device->fraglen, prebuff_max, writelead);
|
|
||||||
|
|
||||||
ZeroMemory(device->mix_buffer, device->mix_buffer_len);
|
|
||||||
|
|
||||||
/* do the mixing */
|
/* do the mixing */
|
||||||
DSOUND_MixToPrimary(device, writepos, maxq, recover, &all_stopped);
|
DSOUND_MixToPrimary(device, writepos, maxq, TRUE, &all_stopped);
|
||||||
|
|
||||||
if (maxq + writepos > device->buflen)
|
if (maxq + writepos > device->buflen) {
|
||||||
{
|
|
||||||
DWORD todo = device->buflen - writepos;
|
DWORD todo = device->buflen - writepos;
|
||||||
DWORD offs_float = (todo / device->pwfx->nBlockAlign) * device->pwfx->nChannels;
|
|
||||||
device->normfunction(device->mix_buffer, device->buffer + writepos, todo);
|
device->normfunction(device->mix_buffer, device->buffer + writepos, todo);
|
||||||
device->normfunction(device->mix_buffer + offs_float, device->buffer, maxq - todo);
|
DSOUND_WaveQueue(device, device->buffer + writepos, todo);
|
||||||
}
|
|
||||||
else
|
device->normfunction(device->mix_buffer + todo / bpp, device->buffer, (maxq - todo));
|
||||||
|
DSOUND_WaveQueue(device, device->buffer, maxq - todo);
|
||||||
|
} else {
|
||||||
device->normfunction(device->mix_buffer, device->buffer + writepos, maxq);
|
device->normfunction(device->mix_buffer, device->buffer + writepos, maxq);
|
||||||
|
DSOUND_WaveQueue(device, device->buffer + writepos, maxq);
|
||||||
/* update the mix position, taking wrap-around into account */
|
|
||||||
device->mixpos = writepos + maxq;
|
|
||||||
device->mixpos %= device->buflen;
|
|
||||||
|
|
||||||
/* update prebuff left */
|
|
||||||
prebuff_left = DSOUND_BufPtrDiff(device->buflen, device->mixpos, playpos);
|
|
||||||
|
|
||||||
/* check if have a whole fragment */
|
|
||||||
if (prebuff_left >= device->fraglen){
|
|
||||||
|
|
||||||
/* update the wave queue */
|
|
||||||
DSOUND_WaveQueue(device, FALSE);
|
|
||||||
|
|
||||||
/* buffers are full. start playing if applicable */
|
|
||||||
if(device->state == STATE_STARTING){
|
|
||||||
TRACE("started primary buffer\n");
|
|
||||||
if(DSOUND_PrimaryPlay(device) != DS_OK){
|
|
||||||
WARN("DSOUND_PrimaryPlay failed\n");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
/* we are playing now */
|
|
||||||
device->state = STATE_PLAYING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* buffers are full. start stopping if applicable */
|
|
||||||
if(device->state == STATE_STOPPED){
|
|
||||||
TRACE("restarting primary buffer\n");
|
|
||||||
if(DSOUND_PrimaryPlay(device) != DS_OK){
|
|
||||||
WARN("DSOUND_PrimaryPlay failed\n");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
/* start stopping again. as soon as there is no more data, it will stop */
|
|
||||||
device->state = STATE_STOPPING;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if device was stopping, its for sure stopped when all buffers have stopped */
|
if (maxq) {
|
||||||
else if (all_stopped && (device->state == STATE_STOPPING)) {
|
if (device->state == STATE_STARTING ||
|
||||||
TRACE("All buffers have stopped. Stopping primary buffer\n");
|
device->state == STATE_STOPPED) {
|
||||||
|
if(DSOUND_PrimaryPlay(device) != DS_OK)
|
||||||
|
WARN("DSOUND_PrimaryPlay failed\n");
|
||||||
|
else if (device->state == STATE_STARTING)
|
||||||
|
device->state = STATE_PLAYING;
|
||||||
|
else
|
||||||
|
device->state = STATE_STOPPING;
|
||||||
|
}
|
||||||
|
} else if (!pad && !maxq && (all_stopped == TRUE) &&
|
||||||
|
(device->state == STATE_STOPPING)) {
|
||||||
device->state = STATE_STOPPED;
|
device->state = STATE_STOPPED;
|
||||||
|
|
||||||
/* stop the primary buffer now */
|
|
||||||
DSOUND_PrimaryStop(device);
|
DSOUND_PrimaryStop(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (device->state != STATE_STOPPED) {
|
} else if (device->state != STATE_STOPPED) {
|
||||||
|
if (maxq > device->buflen)
|
||||||
DSOUND_WaveQueue(device, TRUE);
|
maxq = device->buflen;
|
||||||
|
if (writepos + maxq > device->buflen) {
|
||||||
|
DSOUND_WaveQueue(device, device->buffer + writepos, device->buflen - writepos);
|
||||||
|
DSOUND_WaveQueue(device, device->buffer, writepos + maxq - device->buflen);
|
||||||
|
} else
|
||||||
|
DSOUND_WaveQueue(device, device->buffer + writepos, maxq);
|
||||||
|
|
||||||
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
|
/* in the DSSCL_WRITEPRIMARY mode, the app is totally in charge... */
|
||||||
if (device->state == STATE_STARTING) {
|
if (device->state == STATE_STARTING) {
|
||||||
|
|
|
@ -40,24 +40,6 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(dsound);
|
WINE_DEFAULT_DEBUG_CHANNEL(dsound);
|
||||||
|
|
||||||
static DWORD DSOUND_fraglen(DirectSoundDevice *device)
|
|
||||||
{
|
|
||||||
REFERENCE_TIME period;
|
|
||||||
HRESULT hr;
|
|
||||||
DWORD ret;
|
|
||||||
|
|
||||||
hr = IAudioClient_GetDevicePeriod(device->client, &period, NULL);
|
|
||||||
if(FAILED(hr)){
|
|
||||||
/* just guess at 10ms */
|
|
||||||
WARN("GetDevicePeriod failed: %08x\n", hr);
|
|
||||||
ret = MulDiv(device->pwfx->nBlockAlign, device->pwfx->nSamplesPerSec, 100);
|
|
||||||
}else
|
|
||||||
ret = MulDiv(device->pwfx->nSamplesPerSec * device->pwfx->nBlockAlign, period, 10000000);
|
|
||||||
|
|
||||||
ret -= ret % device->pwfx->nBlockAlign;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DWORD speaker_config_to_channel_mask(DWORD speaker_config)
|
static DWORD speaker_config_to_channel_mask(DWORD speaker_config)
|
||||||
{
|
{
|
||||||
switch (DSSPEAKER_CONFIG(speaker_config)) {
|
switch (DSSPEAKER_CONFIG(speaker_config)) {
|
||||||
|
@ -217,11 +199,10 @@ static HRESULT DSOUND_WaveFormat(DirectSoundDevice *device, IAudioClient *client
|
||||||
|
|
||||||
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
||||||
{
|
{
|
||||||
UINT prebuf_frames;
|
|
||||||
REFERENCE_TIME prebuf_rt;
|
|
||||||
WAVEFORMATEX *wfx = NULL;
|
WAVEFORMATEX *wfx = NULL;
|
||||||
HRESULT hres;
|
HRESULT hres;
|
||||||
REFERENCE_TIME period;
|
REFERENCE_TIME period, buflen = 800000;
|
||||||
|
UINT32 frames;
|
||||||
DWORD period_ms;
|
DWORD period_ms;
|
||||||
|
|
||||||
TRACE("(%p, %d)\n", device, forcewave);
|
TRACE("(%p, %d)\n", device, forcewave);
|
||||||
|
@ -243,6 +224,12 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
||||||
device->volume = NULL;
|
device->volume = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device->pad) {
|
||||||
|
device->playpos += device->pad;
|
||||||
|
device->playpos %= device->buflen;
|
||||||
|
device->pad = 0;
|
||||||
|
}
|
||||||
|
|
||||||
hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
|
hres = IMMDevice_Activate(device->mmdevice, &IID_IAudioClient,
|
||||||
CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
|
CLSCTX_INPROC_SERVER, NULL, (void **)&device->client);
|
||||||
if(FAILED(hres)) {
|
if(FAILED(hres)) {
|
||||||
|
@ -263,12 +250,9 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
||||||
HeapFree(GetProcessHeap(), 0, device->pwfx);
|
HeapFree(GetProcessHeap(), 0, device->pwfx);
|
||||||
device->pwfx = wfx;
|
device->pwfx = wfx;
|
||||||
|
|
||||||
prebuf_frames = device->prebuf * DSOUND_fraglen(device) / device->pwfx->nBlockAlign;
|
|
||||||
prebuf_rt = (10000000 * (UINT64)prebuf_frames) / device->pwfx->nSamplesPerSec;
|
|
||||||
|
|
||||||
hres = IAudioClient_Initialize(device->client,
|
hres = IAudioClient_Initialize(device->client,
|
||||||
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
|
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_NOPERSIST |
|
||||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK, prebuf_rt, 0, device->pwfx, NULL);
|
AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buflen, 0, device->pwfx, NULL);
|
||||||
if(FAILED(hres)){
|
if(FAILED(hres)){
|
||||||
IAudioClient_Release(device->client);
|
IAudioClient_Release(device->client);
|
||||||
device->client = NULL;
|
device->client = NULL;
|
||||||
|
@ -318,10 +302,19 @@ HRESULT DSOUND_ReopenDevice(DirectSoundDevice *device, BOOL forcewave)
|
||||||
hres = IAudioClient_GetStreamLatency(device->client, &period);
|
hres = IAudioClient_GetStreamLatency(device->client, &period);
|
||||||
if (FAILED(hres)) {
|
if (FAILED(hres)) {
|
||||||
WARN("GetStreamLatency failed with %08x\n", hres);
|
WARN("GetStreamLatency failed with %08x\n", hres);
|
||||||
period_ms = 10;
|
period = 100000;
|
||||||
} else
|
}
|
||||||
period_ms = (period + 9999) / 10000;
|
period_ms = (period + 9999) / 10000;
|
||||||
TRACE("period %u ms fraglen %u prebuf %u\n", period_ms, device->fraglen, device->prebuf);
|
|
||||||
|
hres = IAudioClient_GetBufferSize(device->client, &frames);
|
||||||
|
if (FAILED(hres)) {
|
||||||
|
WARN("GetBufferSize failed with %08x\n", hres);
|
||||||
|
frames = (UINT64)device->pwfx->nSamplesPerSec * buflen / 10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
device->fraglen = MulDiv(device->pwfx->nSamplesPerSec, period, 10000000) * device->pwfx->nBlockAlign;
|
||||||
|
device->aclen = frames * device->pwfx->nBlockAlign;
|
||||||
|
TRACE("period %u ms fraglen %u buflen %u\n", period_ms, device->fraglen, device->aclen);
|
||||||
|
|
||||||
if (period_ms < 3)
|
if (period_ms < 3)
|
||||||
device->sleeptime = 5;
|
device->sleeptime = 5;
|
||||||
|
@ -339,17 +332,11 @@ HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device)
|
||||||
|
|
||||||
TRACE("(%p)\n", device);
|
TRACE("(%p)\n", device);
|
||||||
|
|
||||||
device->fraglen = DSOUND_fraglen(device);
|
|
||||||
|
|
||||||
/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
|
/* on original windows, the buffer it set to a fixed size, no matter what the settings are.
|
||||||
on windows this size is always fixed (tested on win-xp) */
|
on windows this size is always fixed (tested on win-xp) */
|
||||||
if (!device->buflen)
|
if (!device->buflen)
|
||||||
device->buflen = ds_hel_buflen;
|
device->buflen = ds_hel_buflen;
|
||||||
device->buflen -= device->buflen % device->pwfx->nBlockAlign;
|
device->buflen -= device->buflen % device->pwfx->nBlockAlign;
|
||||||
while(device->buflen < device->fraglen * device->prebuf){
|
|
||||||
device->buflen += ds_hel_buflen;
|
|
||||||
device->buflen -= device->buflen % device->pwfx->nBlockAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, device->mix_buffer);
|
HeapFree(GetProcessHeap(), 0, device->mix_buffer);
|
||||||
device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
|
device->mix_buffer_len = (device->buflen / (device->pwfx->wBitsPerSample / 8)) * sizeof(float);
|
||||||
|
@ -419,9 +406,6 @@ static void DSOUND_PrimaryClose(DirectSoundDevice *device)
|
||||||
if(FAILED(hr))
|
if(FAILED(hr))
|
||||||
WARN("Stop failed: %08x\n", hr);
|
WARN("Stop failed: %08x\n", hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear the queue */
|
|
||||||
device->in_mmdev_bytes = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
|
HRESULT DSOUND_PrimaryCreate(DirectSoundDevice *device)
|
||||||
|
|
Loading…
Reference in New Issue