More general code cleanup for readability.
A few more parameter validation checks. Return DS_OK rather than 0 in a number of functions. Fixed primary buffer ref count bug in CreateSoundBuffer(). Handle 1-3 byte sound fragments that would cause buffer overruns. Clear primary buffer with a neutral value instead of always 0 (because 128 is neutral for 8-bit sound). Fix bug with mixing 8-bit sound into the primary buffer. Broke out the main block in DSOUND_thread() to another function for readability. Handle "no audio" and "audio busy" cases properly when initializing dsound. Rename DllCanUnloadNow() to DSOUND_DllCanUnloadNow().
This commit is contained in:
parent
eee1ddc809
commit
f0fa956384
|
@ -59,7 +59,7 @@
|
||||||
|
|
||||||
/* #define USE_DSOUND3D 1 */
|
/* #define USE_DSOUND3D 1 */
|
||||||
|
|
||||||
#define DSOUND_BUFLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
|
#define DSOUND_FRAGLEN (primarybuf->wfx.nAvgBytesPerSec >> 4)
|
||||||
#define DSOUND_FREQSHIFT (14)
|
#define DSOUND_FREQSHIFT (14)
|
||||||
|
|
||||||
static int audiofd = -1;
|
static int audiofd = -1;
|
||||||
|
@ -645,6 +645,17 @@ static HRESULT WINAPI IDirectSoundBuffer_SetFormat(
|
||||||
LPDIRECTSOUNDBUFFER *dsb;
|
LPDIRECTSOUNDBUFFER *dsb;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// Let's be pedantic!
|
||||||
|
if ((wfex == NULL) ||
|
||||||
|
(wfex->wFormatTag != WAVE_FORMAT_PCM) ||
|
||||||
|
(wfex->nChannels < 1) || (wfex->nChannels > 2) ||
|
||||||
|
(wfex->nSamplesPerSec < 1) ||
|
||||||
|
(wfex->nBlockAlign < 1) || (wfex->nChannels > 4) ||
|
||||||
|
((wfex->wBitsPerSample != 8) && (wfex->wBitsPerSample != 16))) {
|
||||||
|
TRACE(dsound, "failed pedantic check!\n");
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
}
|
||||||
|
|
||||||
// ****
|
// ****
|
||||||
EnterCriticalSection(&(primarybuf->lock));
|
EnterCriticalSection(&(primarybuf->lock));
|
||||||
|
|
||||||
|
@ -725,8 +736,12 @@ static HRESULT WINAPI IDirectSoundBuffer_GetVolume(
|
||||||
LPDIRECTSOUNDBUFFER this,LPLONG vol
|
LPDIRECTSOUNDBUFFER this,LPLONG vol
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p)\n",this,vol);
|
TRACE(dsound,"(%p,%p)\n",this,vol);
|
||||||
|
|
||||||
|
if (vol == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
*vol = this->volume;
|
*vol = this->volume;
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_SetFrequency(
|
static HRESULT WINAPI IDirectSoundBuffer_SetFrequency(
|
||||||
|
@ -763,7 +778,7 @@ static HRESULT WINAPI IDirectSoundBuffer_Play(
|
||||||
);
|
);
|
||||||
this->playflags = flags;
|
this->playflags = flags;
|
||||||
this->playing = 1;
|
this->playing = 1;
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this)
|
static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this)
|
||||||
|
@ -779,7 +794,7 @@ static HRESULT WINAPI IDirectSoundBuffer_Stop(LPDIRECTSOUNDBUFFER this)
|
||||||
LeaveCriticalSection(&(this->lock));
|
LeaveCriticalSection(&(this->lock));
|
||||||
// ****
|
// ****
|
||||||
|
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER this) {
|
static DWORD WINAPI IDirectSoundBuffer_AddRef(LPDIRECTSOUNDBUFFER this) {
|
||||||
|
@ -817,7 +832,7 @@ static DWORD WINAPI IDirectSoundBuffer_Release(LPDIRECTSOUNDBUFFER this) {
|
||||||
if (this == primarybuf)
|
if (this == primarybuf)
|
||||||
primarybuf = NULL;
|
primarybuf = NULL;
|
||||||
|
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_GetCurrentPosition(
|
static HRESULT WINAPI IDirectSoundBuffer_GetCurrentPosition(
|
||||||
|
@ -826,19 +841,24 @@ static HRESULT WINAPI IDirectSoundBuffer_GetCurrentPosition(
|
||||||
TRACE(dsound,"(%p,%p,%p)\n",this,playpos,writepos);
|
TRACE(dsound,"(%p,%p,%p)\n",this,playpos,writepos);
|
||||||
if (playpos) *playpos = this->playpos;
|
if (playpos) *playpos = this->playpos;
|
||||||
if (writepos) *writepos = this->writepos;
|
if (writepos) *writepos = this->writepos;
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_GetStatus(
|
static HRESULT WINAPI IDirectSoundBuffer_GetStatus(
|
||||||
LPDIRECTSOUNDBUFFER this,LPDWORD status
|
LPDIRECTSOUNDBUFFER this,LPDWORD status
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p)\n",this,status);
|
TRACE(dsound,"(%p,%p)\n",this,status);
|
||||||
|
|
||||||
|
if (status == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
*status = 0;
|
*status = 0;
|
||||||
if (this->playing)
|
if (this->playing)
|
||||||
*status |= DSBSTATUS_PLAYING;
|
*status |= DSBSTATUS_PLAYING;
|
||||||
if (this->playflags & DSBPLAY_LOOPING)
|
if (this->playflags & DSBPLAY_LOOPING)
|
||||||
*status |= DSBSTATUS_LOOPING;
|
*status |= DSBSTATUS_LOOPING;
|
||||||
return 0;
|
|
||||||
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -846,6 +866,7 @@ static HRESULT WINAPI IDirectSoundBuffer_GetFormat(
|
||||||
LPDIRECTSOUNDBUFFER this,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
|
LPDIRECTSOUNDBUFFER this,LPWAVEFORMATEX lpwf,DWORD wfsize,LPDWORD wfwritten
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p,%ld,%p)\n",this,lpwf,wfsize,wfwritten);
|
TRACE(dsound,"(%p,%p,%ld,%p)\n",this,lpwf,wfsize,wfwritten);
|
||||||
|
|
||||||
if (wfsize>sizeof(this->wfx))
|
if (wfsize>sizeof(this->wfx))
|
||||||
wfsize = sizeof(this->wfx);
|
wfsize = sizeof(this->wfx);
|
||||||
if (lpwf) { // NULL is valid
|
if (lpwf) { // NULL is valid
|
||||||
|
@ -858,7 +879,7 @@ static HRESULT WINAPI IDirectSoundBuffer_GetFormat(
|
||||||
else
|
else
|
||||||
return DSERR_INVALIDPARAM;
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_Lock(
|
static HRESULT WINAPI IDirectSoundBuffer_Lock(
|
||||||
|
@ -903,7 +924,7 @@ static HRESULT WINAPI IDirectSoundBuffer_Lock(
|
||||||
}
|
}
|
||||||
// No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21
|
// No. See file:///cdrom/sdk52/docs/worddoc/dsound.doc page 21
|
||||||
// this->writepos=(writecursor+writebytes)%this->buflen;
|
// this->writepos=(writecursor+writebytes)%this->buflen;
|
||||||
return 0;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_SetCurrentPosition(
|
static HRESULT WINAPI IDirectSoundBuffer_SetCurrentPosition(
|
||||||
|
@ -929,7 +950,7 @@ static HRESULT WINAPI IDirectSoundBuffer_SetPan(
|
||||||
|
|
||||||
TRACE(dsound,"(%p,%ld)\n",this,pan);
|
TRACE(dsound,"(%p,%ld)\n",this,pan);
|
||||||
|
|
||||||
if (!(this) || (pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
|
if ((pan > DSBPAN_RIGHT) || (pan < DSBPAN_LEFT))
|
||||||
return DSERR_INVALIDPARAM;
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
// You cannot set the pan of the primary buffer
|
// You cannot set the pan of the primary buffer
|
||||||
|
@ -959,28 +980,48 @@ static HRESULT WINAPI IDirectSoundBuffer_GetPan(
|
||||||
LPDIRECTSOUNDBUFFER this,LPLONG pan
|
LPDIRECTSOUNDBUFFER this,LPLONG pan
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p)\n",this,pan);
|
TRACE(dsound,"(%p,%p)\n",this,pan);
|
||||||
|
|
||||||
|
if (pan == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
*pan = this->pan;
|
*pan = this->pan;
|
||||||
return 0;
|
|
||||||
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_Unlock(
|
static HRESULT WINAPI IDirectSoundBuffer_Unlock(
|
||||||
LPDIRECTSOUNDBUFFER this,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
|
LPDIRECTSOUNDBUFFER this,LPVOID p1,DWORD x1,LPVOID p2,DWORD x2
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p,%ld,%p,%ld):stub\n", this,p1,x1,p2,x2);
|
TRACE(dsound,"(%p,%p,%ld,%p,%ld):stub\n", this,p1,x1,p2,x2);
|
||||||
|
|
||||||
|
// There is really nothing to do here. Should someone
|
||||||
|
// choose to implement static buffers in hardware (by
|
||||||
|
// using a wave table synth, for example) this is where
|
||||||
|
// you'd want to do the loading. For software buffers,
|
||||||
|
// which is what we currently use, we need do nothing.
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
// It's also the place to pre-process 3D buffers...
|
||||||
|
|
||||||
// This is highly experimental and liable to break things
|
// This is highly experimental and liable to break things
|
||||||
if (this->dsbd.dwFlags & DSBCAPS_CTRL3D)
|
if (this->dsbd.dwFlags & DSBCAPS_CTRL3D)
|
||||||
DSOUND_Create3DBuffer(this);
|
DSOUND_Create3DBuffer(this);
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
|
||||||
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_GetFrequency(
|
static HRESULT WINAPI IDirectSoundBuffer_GetFrequency(
|
||||||
LPDIRECTSOUNDBUFFER this,LPDWORD freq
|
LPDIRECTSOUNDBUFFER this,LPDWORD freq
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p,%p)\n",this,freq);
|
TRACE(dsound,"(%p,%p)\n",this,freq);
|
||||||
|
|
||||||
|
if (freq == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
*freq = this->freq;
|
*freq = this->freq;
|
||||||
return 0;
|
|
||||||
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSoundBuffer_Initialize(
|
static HRESULT WINAPI IDirectSoundBuffer_Initialize(
|
||||||
|
@ -996,7 +1037,13 @@ static HRESULT WINAPI IDirectSoundBuffer_GetCaps(
|
||||||
) {
|
) {
|
||||||
TRACE(dsound,"(%p)->(%p)\n",this,caps);
|
TRACE(dsound,"(%p)->(%p)\n",this,caps);
|
||||||
|
|
||||||
|
if (caps == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
|
// I think we should check this value, not set it. See
|
||||||
|
// Inside DirectX, p215. That should apply here, too.
|
||||||
caps->dwSize = sizeof(*caps);
|
caps->dwSize = sizeof(*caps);
|
||||||
|
|
||||||
caps->dwFlags = this->dsbd.dwFlags | DSBCAPS_LOCSOFTWARE;
|
caps->dwFlags = this->dsbd.dwFlags | DSBCAPS_LOCSOFTWARE;
|
||||||
caps->dwBufferBytes = this->dsbd.dwBufferBytes;
|
caps->dwBufferBytes = this->dsbd.dwBufferBytes;
|
||||||
/* This value represents the speed of the "unlock" command.
|
/* This value represents the speed of the "unlock" command.
|
||||||
|
@ -1071,7 +1118,6 @@ static HRESULT WINAPI IDirectSound_SetCooperativeLevel(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
|
static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
|
||||||
LPDIRECTSOUND this,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
|
LPDIRECTSOUND this,LPDSBUFFERDESC dsbd,LPLPDIRECTSOUNDBUFFER ppdsb,LPUNKNOWN lpunk
|
||||||
) {
|
) {
|
||||||
|
@ -1127,6 +1173,8 @@ static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
|
||||||
*ppdsb = NULL;
|
*ppdsb = NULL;
|
||||||
return DSERR_OUTOFMEMORY;
|
return DSERR_OUTOFMEMORY;
|
||||||
}
|
}
|
||||||
|
// It's not necessary to initialize values to zero since
|
||||||
|
// we allocated this structure with HEAP_ZERO_MEMORY...
|
||||||
(*ppdsb)->playpos = 0;
|
(*ppdsb)->playpos = 0;
|
||||||
(*ppdsb)->writepos = 0;
|
(*ppdsb)->writepos = 0;
|
||||||
(*ppdsb)->lpvtbl = &dsbvt;
|
(*ppdsb)->lpvtbl = &dsbvt;
|
||||||
|
@ -1149,8 +1197,8 @@ static HRESULT WINAPI IDirectSound_CreateSoundBuffer(
|
||||||
this->buffers = (LPDIRECTSOUNDBUFFER*)HeapReAlloc(GetProcessHeap(),0,this->buffers,sizeof(LPDIRECTSOUNDBUFFER)*(this->nrofbuffers+1));
|
this->buffers = (LPDIRECTSOUNDBUFFER*)HeapReAlloc(GetProcessHeap(),0,this->buffers,sizeof(LPDIRECTSOUNDBUFFER)*(this->nrofbuffers+1));
|
||||||
this->buffers[this->nrofbuffers] = *ppdsb;
|
this->buffers[this->nrofbuffers] = *ppdsb;
|
||||||
this->nrofbuffers++;
|
this->nrofbuffers++;
|
||||||
this->lpvtbl->fnAddRef(this);
|
|
||||||
}
|
}
|
||||||
|
this->lpvtbl->fnAddRef(this);
|
||||||
|
|
||||||
if (dsbd->lpwfxFormat)
|
if (dsbd->lpwfxFormat)
|
||||||
memcpy(&((*ppdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ppdsb)->wfx));
|
memcpy(&((*ppdsb)->wfx), dsbd->lpwfxFormat, sizeof((*ppdsb)->wfx));
|
||||||
|
@ -1224,7 +1272,12 @@ static HRESULT WINAPI IDirectSound_GetCaps(LPDIRECTSOUND this,LPDSCAPS caps) {
|
||||||
TRACE(dsound,"(%p,%p)\n",this,caps);
|
TRACE(dsound,"(%p,%p)\n",this,caps);
|
||||||
TRACE(dsound,"(flags=0x%08lx)\n",caps->dwFlags);
|
TRACE(dsound,"(flags=0x%08lx)\n",caps->dwFlags);
|
||||||
|
|
||||||
|
if (caps == NULL)
|
||||||
|
return DSERR_INVALIDPARAM;
|
||||||
|
|
||||||
|
// We should check this value, not set it. See Inside DirectX, p215.
|
||||||
caps->dwSize = sizeof(*caps);
|
caps->dwSize = sizeof(*caps);
|
||||||
|
|
||||||
caps->dwFlags =
|
caps->dwFlags =
|
||||||
DSCAPS_PRIMARYSTEREO |
|
DSCAPS_PRIMARYSTEREO |
|
||||||
DSCAPS_PRIMARY16BIT |
|
DSCAPS_PRIMARY16BIT |
|
||||||
|
@ -1343,7 +1396,7 @@ static HRESULT WINAPI IDirectSound_GetSpeakerConfig(
|
||||||
LPDWORD lpdwSpeakerConfig)
|
LPDWORD lpdwSpeakerConfig)
|
||||||
{
|
{
|
||||||
TRACE(dsound, "(%p, %p)\n", this, lpdwSpeakerConfig);
|
TRACE(dsound, "(%p, %p)\n", this, lpdwSpeakerConfig);
|
||||||
*lpdwSpeakerConfig = DSSPEAKER_STEREO | DSSPEAKER_GEOMETRY_NARROW;
|
*lpdwSpeakerConfig = DSSPEAKER_STEREO | (DSSPEAKER_GEOMETRY_NARROW << 16);
|
||||||
return DS_OK;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1363,17 +1416,16 @@ static struct tagLPDIRECTSOUND_VTABLE dsvt = {
|
||||||
IDirectSound_GetCaps,
|
IDirectSound_GetCaps,
|
||||||
IDirectSound_DuplicateSoundBuffer,
|
IDirectSound_DuplicateSoundBuffer,
|
||||||
IDirectSound_SetCooperativeLevel,
|
IDirectSound_SetCooperativeLevel,
|
||||||
IDirectSound_Compact,
|
IDirectSound_Compact,
|
||||||
IDirectSound_GetSpeakerConfig,
|
IDirectSound_GetSpeakerConfig,
|
||||||
IDirectSound_SetSpeakerConfig,
|
IDirectSound_SetSpeakerConfig,
|
||||||
IDirectSound_Initialize
|
IDirectSound_Initialize
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
DSOUND_setformat(LPWAVEFORMATEX wfex) {
|
DSOUND_setformat(LPWAVEFORMATEX wfex) {
|
||||||
int xx,channels,speed,format,nformat;
|
int xx,channels,speed,format,nformat;
|
||||||
|
|
||||||
// Race condition here... called by DSOUND_thread() and SetFormat()
|
|
||||||
if (!audioOK) {
|
if (!audioOK) {
|
||||||
TRACE(dsound, "(%p) deferred\n", wfex);
|
TRACE(dsound, "(%p) deferred\n", wfex);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1706,8 +1758,7 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBuffer *dsb)
|
||||||
BYTE *buf, *ibuf, *obuf;
|
BYTE *buf, *ibuf, *obuf;
|
||||||
INT16 *ibufs, *obufs;
|
INT16 *ibufs, *obufs;
|
||||||
|
|
||||||
len = DSOUND_BUFLEN; // The most we will use
|
len = DSOUND_FRAGLEN; // The most we will use
|
||||||
len &= ~3; // 4 byte alignment
|
|
||||||
if (!(dsb->playflags & DSBPLAY_LOOPING)) {
|
if (!(dsb->playflags & DSBPLAY_LOOPING)) {
|
||||||
temp = ((primarybuf->wfx.nAvgBytesPerSec * dsb->buflen) /
|
temp = ((primarybuf->wfx.nAvgBytesPerSec * dsb->buflen) /
|
||||||
dsb->nAvgBytesPerSec) -
|
dsb->nAvgBytesPerSec) -
|
||||||
|
@ -1715,7 +1766,24 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBuffer *dsb)
|
||||||
dsb->nAvgBytesPerSec);
|
dsb->nAvgBytesPerSec);
|
||||||
len = (len > temp) ? temp : len;
|
len = (len > temp) ? temp : len;
|
||||||
}
|
}
|
||||||
|
len &= ~3; // 4 byte alignment
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
// This should only happen if we aren't looping and temp < 4
|
||||||
|
|
||||||
|
// We skip the remainder, so check for possible events
|
||||||
|
DSOUND_CheckEvent(dsb, dsb->buflen - dsb->playpos);
|
||||||
|
// Stop
|
||||||
|
dsb->playing = 0;
|
||||||
|
dsb->writepos = 0;
|
||||||
|
dsb->playpos = 0;
|
||||||
|
// Check for DSBPN_OFFSETSTOP
|
||||||
|
DSOUND_CheckEvent(dsb, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Been seeing segfaults in malloc() for some reason...
|
||||||
|
TRACE(dsound, "allocating buffer (size = %d)\n", len);
|
||||||
if ((buf = ibuf = (BYTE *) malloc(len)) == NULL)
|
if ((buf = ibuf = (BYTE *) malloc(len)) == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1726,21 +1794,21 @@ static DWORD DSOUND_MixInBuffer(IDirectSoundBuffer *dsb)
|
||||||
(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
|
(dsb->dsbd.dwFlags & DSBCAPS_CTRLVOLUME))
|
||||||
DSOUND_MixerVol(dsb, ibuf, len);
|
DSOUND_MixerVol(dsb, ibuf, len);
|
||||||
|
|
||||||
TRACE(dsound, "Mixing buffer - advance = %d\n", advance);
|
|
||||||
obuf = primarybuf->buffer + primarybuf->playpos;
|
obuf = primarybuf->buffer + primarybuf->playpos;
|
||||||
for (i = 0; i < len; i += advance) {
|
for (i = 0; i < len; i += advance) {
|
||||||
obufs = (INT16 *) obuf;
|
obufs = (INT16 *) obuf;
|
||||||
ibufs = (INT16 *) ibuf;
|
ibufs = (INT16 *) ibuf;
|
||||||
if (primarybuf->wfx.wBitsPerSample == 8) {
|
if (primarybuf->wfx.wBitsPerSample == 8) {
|
||||||
field = *ibuf;
|
|
||||||
field += *obuf;
|
|
||||||
// 8-bit WAV is unsigned
|
// 8-bit WAV is unsigned
|
||||||
field = field > 255 ? 255 : field;
|
field = (*ibuf - 128);
|
||||||
*obuf = field;
|
field += (*obuf - 128);
|
||||||
|
field = field > 127 ? 127 : field;
|
||||||
|
field = field < -128 ? -128 : field;
|
||||||
|
*obuf = field + 128;
|
||||||
} else {
|
} else {
|
||||||
|
// 16-bit WAV is signed
|
||||||
field = *ibufs;
|
field = *ibufs;
|
||||||
field += *obufs;
|
field += *obufs;
|
||||||
// 16-bit WAV is signed
|
|
||||||
field = field > 32767 ? 32767 : field;
|
field = field > 32767 ? 32767 : field;
|
||||||
field = field < -32768 ? -32768 : field;
|
field = field < -32768 ? -32768 : field;
|
||||||
*obufs = field;
|
*obufs = field;
|
||||||
|
@ -1808,11 +1876,13 @@ static int DSOUND_OpenAudio(void)
|
||||||
sleep(5);
|
sleep(5);
|
||||||
audiofd = open("/dev/audio",O_WRONLY);
|
audiofd = open("/dev/audio",O_WRONLY);
|
||||||
if (audiofd==-1) {
|
if (audiofd==-1) {
|
||||||
perror("open /dev/audio");
|
// Don't worry if sound is busy at the moment
|
||||||
audiofd = -1;
|
if (errno != EBUSY)
|
||||||
return DSERR_NODRIVER;
|
perror("open /dev/audio");
|
||||||
|
return audiofd; // -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We should probably do something here if SETFRAGMENT fails...
|
||||||
audioFragment=0x0002000c;
|
audioFragment=0x0002000c;
|
||||||
if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&audioFragment))
|
if (-1==ioctl(audiofd,SNDCTL_DSP_SETFRAGMENT,&audioFragment))
|
||||||
perror("ioctl SETFRAGMENT");
|
perror("ioctl SETFRAGMENT");
|
||||||
|
@ -1825,12 +1895,19 @@ static int DSOUND_OpenAudio(void)
|
||||||
|
|
||||||
static void DSOUND_CloseAudio(void)
|
static void DSOUND_CloseAudio(void)
|
||||||
{
|
{
|
||||||
|
int neutral;
|
||||||
|
|
||||||
|
neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
|
||||||
audioOK = 0; // race condition
|
audioOK = 0; // race condition
|
||||||
Sleep(5);
|
Sleep(5);
|
||||||
close(audiofd);
|
// It's possible we've been called with audio closed
|
||||||
|
// from SetFormat()... this is just to force a call
|
||||||
|
// to OpenAudio() to reset the hardware properly
|
||||||
|
if (audiofd != -1)
|
||||||
|
close(audiofd);
|
||||||
primarybuf->playpos = 0;
|
primarybuf->playpos = 0;
|
||||||
primarybuf->writepos = DSOUND_BUFLEN;
|
primarybuf->writepos = DSOUND_FRAGLEN;
|
||||||
memset(primarybuf->buffer, 0, primarybuf->buflen);
|
memset(primarybuf->buffer, neutral, primarybuf->buflen);
|
||||||
audiofd = -1;
|
audiofd = -1;
|
||||||
TRACE(dsound, "Audio stopped\n");
|
TRACE(dsound, "Audio stopped\n");
|
||||||
}
|
}
|
||||||
|
@ -1851,9 +1928,67 @@ static int DSOUND_WriteAudio(char *buf, int len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DSOUND_OutputPrimary(int len)
|
||||||
|
{
|
||||||
|
int neutral, flen1, flen2;
|
||||||
|
char *frag1, *frag2;
|
||||||
|
|
||||||
|
// This is a bad place for this. We need to clear the
|
||||||
|
// buffer with a neutral value, for unsigned 8-bit WAVE
|
||||||
|
// that's 128, for signed 16-bit it's 0
|
||||||
|
neutral = primarybuf->wfx.wBitsPerSample == 8 ? 128 : 0;
|
||||||
|
|
||||||
|
// ****
|
||||||
|
EnterCriticalSection(&(primarybuf->lock));
|
||||||
|
|
||||||
|
// Write out the
|
||||||
|
if ((audioOK == 1) || (DSOUND_OpenAudio() == 0)) {
|
||||||
|
if (primarybuf->playpos + len >= primarybuf->buflen) {
|
||||||
|
frag1 = primarybuf->buffer + primarybuf->playpos;
|
||||||
|
flen1 = primarybuf->buflen - primarybuf->playpos;
|
||||||
|
frag2 = primarybuf->buffer;
|
||||||
|
flen2 = len - (primarybuf->buflen - primarybuf->playpos);
|
||||||
|
if (DSOUND_WriteAudio(frag1, flen1) != 0) {
|
||||||
|
perror("DSOUND_WriteAudio");
|
||||||
|
LeaveCriticalSection(&(primarybuf->lock));
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
memset(frag1, neutral, flen1);
|
||||||
|
if (DSOUND_WriteAudio(frag2, flen2) != 0) {
|
||||||
|
perror("DSOUND_WriteAudio");
|
||||||
|
LeaveCriticalSection(&(primarybuf->lock));
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
memset(frag2, neutral, flen2);
|
||||||
|
} else {
|
||||||
|
frag1 = primarybuf->buffer + primarybuf->playpos;
|
||||||
|
flen1 = len;
|
||||||
|
if (DSOUND_WriteAudio(frag1, flen1) != 0) {
|
||||||
|
perror("DSOUND_WriteAudio");
|
||||||
|
LeaveCriticalSection(&(primarybuf->lock));
|
||||||
|
ExitThread(0);
|
||||||
|
}
|
||||||
|
memset(frag1, neutral, flen1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Can't play audio at the moment -- we need to sleep
|
||||||
|
// to make up for the time we'd be blocked in write()
|
||||||
|
// to /dev/audio
|
||||||
|
Sleep(60);
|
||||||
|
}
|
||||||
|
primarybuf->playpos += len;
|
||||||
|
if (primarybuf->playpos >= primarybuf->buflen)
|
||||||
|
primarybuf->playpos %= primarybuf->buflen;
|
||||||
|
primarybuf->writepos = primarybuf->playpos + DSOUND_FRAGLEN;
|
||||||
|
if (primarybuf->writepos >= primarybuf->buflen)
|
||||||
|
primarybuf->writepos %= primarybuf->buflen;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&(primarybuf->lock));
|
||||||
|
// ****
|
||||||
|
}
|
||||||
|
|
||||||
static DWORD WINAPI DSOUND_thread(LPVOID arg)
|
static DWORD WINAPI DSOUND_thread(LPVOID arg)
|
||||||
{
|
{
|
||||||
int maxlen = DSOUND_BUFLEN;
|
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
TRACE(dsound,"dsound is at pid %d\n",getpid());
|
TRACE(dsound,"dsound is at pid %d\n",getpid());
|
||||||
|
@ -1868,11 +2003,11 @@ static DWORD WINAPI DSOUND_thread(LPVOID arg)
|
||||||
}
|
}
|
||||||
/* RACE: dsound could be deleted */
|
/* RACE: dsound could be deleted */
|
||||||
dsound->lpvtbl->fnAddRef(dsound);
|
dsound->lpvtbl->fnAddRef(dsound);
|
||||||
if (primarybuf == NULL) { // Should never happen
|
if (primarybuf == NULL) {
|
||||||
/* no soundbuffer yet... wait. */
|
// Should never happen
|
||||||
Sleep(100);
|
WARN(dsound, "Lost the primary buffer!\n");
|
||||||
dsound->lpvtbl->fnRelease(dsound);
|
dsound->lpvtbl->fnRelease(dsound);
|
||||||
continue;
|
ExitThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ****
|
// ****
|
||||||
|
@ -1882,50 +2017,12 @@ static DWORD WINAPI DSOUND_thread(LPVOID arg)
|
||||||
// ****
|
// ****
|
||||||
|
|
||||||
if (primarybuf->playing)
|
if (primarybuf->playing)
|
||||||
len = maxlen > len ? maxlen : len;
|
len = DSOUND_FRAGLEN > len ? DSOUND_FRAGLEN : len;
|
||||||
if (len) {
|
if (len) {
|
||||||
// ****
|
// This does all the work
|
||||||
EnterCriticalSection(&(primarybuf->lock));
|
DSOUND_OutputPrimary(len);
|
||||||
|
|
||||||
if (audioOK == 0)
|
|
||||||
DSOUND_OpenAudio();
|
|
||||||
if (primarybuf->playpos + len >= primarybuf->buflen) {
|
|
||||||
if (DSOUND_WriteAudio(
|
|
||||||
primarybuf->buffer + primarybuf->playpos,
|
|
||||||
primarybuf->buflen - primarybuf->playpos)
|
|
||||||
!= 0) {
|
|
||||||
perror("DSOUND_WriteAudio");
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
memset(primarybuf->buffer + primarybuf->playpos, 0,
|
|
||||||
primarybuf->buflen - primarybuf->playpos);
|
|
||||||
if (DSOUND_WriteAudio(primarybuf->buffer,
|
|
||||||
len - (primarybuf->buflen - primarybuf->playpos)) != 0) {
|
|
||||||
perror("DSOUND_WriteAudio");
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
memset(primarybuf->buffer, 0,
|
|
||||||
len - (primarybuf->buflen - primarybuf->playpos));
|
|
||||||
} else {
|
|
||||||
if (DSOUND_WriteAudio(
|
|
||||||
primarybuf->buffer + primarybuf->playpos,
|
|
||||||
len) != 0) {
|
|
||||||
perror("DSOUND_WriteAudio");
|
|
||||||
ExitThread(0);
|
|
||||||
}
|
|
||||||
memset(primarybuf->buffer + primarybuf->playpos, 0, len);
|
|
||||||
}
|
|
||||||
primarybuf->playpos += len;
|
|
||||||
if (primarybuf->playpos >= primarybuf->buflen)
|
|
||||||
primarybuf->playpos %= primarybuf->buflen;
|
|
||||||
primarybuf->writepos = primarybuf->playpos + maxlen;
|
|
||||||
if (primarybuf->writepos >= primarybuf->buflen)
|
|
||||||
primarybuf->writepos %= primarybuf->buflen;
|
|
||||||
|
|
||||||
LeaveCriticalSection(&(primarybuf->lock));
|
|
||||||
// ****
|
|
||||||
} else {
|
} else {
|
||||||
/* no soundbuffer. close and wait. */
|
// no buffers playing -- close and wait
|
||||||
if (audioOK)
|
if (audioOK)
|
||||||
DSOUND_CloseAudio();
|
DSOUND_CloseAudio();
|
||||||
Sleep(100);
|
Sleep(100);
|
||||||
|
@ -1955,6 +2052,26 @@ HRESULT WINAPI DirectSoundCreate(LPGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUn
|
||||||
return DS_OK;
|
return DS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that we actually have audio capabilities
|
||||||
|
// If we do, whether it's busy or not, we continue
|
||||||
|
// otherwise we return with DSERR_NODRIVER
|
||||||
|
|
||||||
|
audiofd = open("/dev/audio",O_WRONLY);
|
||||||
|
if (audiofd == -1) {
|
||||||
|
if (errno == ENODEV) {
|
||||||
|
TRACE(dsound, "No sound hardware\n");
|
||||||
|
return DSERR_NODRIVER;
|
||||||
|
} else if (errno == EBUSY) {
|
||||||
|
TRACE(dsound, "Sound device busy, will keep trying\n");
|
||||||
|
} else {
|
||||||
|
TRACE(dsound, "Unexpected error while checking for sound support\n");
|
||||||
|
return DSERR_GENERIC;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
close(audiofd);
|
||||||
|
audiofd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
*ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
|
*ppDS = (LPDIRECTSOUND)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectSound));
|
||||||
if (*ppDS == NULL)
|
if (*ppDS == NULL)
|
||||||
return DSERR_OUTOFMEMORY;
|
return DSERR_OUTOFMEMORY;
|
||||||
|
@ -1985,10 +2102,11 @@ HRESULT WINAPI DirectSoundCreate(LPGUID lpGUID,LPDIRECTSOUND *ppDS,IUnknown *pUn
|
||||||
dsbd.dwBufferBytes = 0;
|
dsbd.dwBufferBytes = 0;
|
||||||
dsbd.lpwfxFormat = &(dsound->wfx);
|
dsbd.lpwfxFormat = &(dsound->wfx);
|
||||||
hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, &primarybuf, NULL);
|
hr = IDirectSound_CreateSoundBuffer(*ppDS, &dsbd, &primarybuf, NULL);
|
||||||
if (hr != DS_OK) return hr;
|
if (hr != DS_OK)
|
||||||
dsound->primary = primarybuf;
|
return hr;
|
||||||
|
dsound->primary = primarybuf;
|
||||||
}
|
}
|
||||||
|
memset(primarybuf->buffer, 128, primarybuf->buflen);
|
||||||
hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
|
hnd = CreateThread(NULL,0,DSOUND_thread,0,0,&xid);
|
||||||
}
|
}
|
||||||
return DS_OK;
|
return DS_OK;
|
||||||
|
@ -2099,7 +2217,7 @@ DWORD WINAPI DSOUND_DllGetClassObject(REFCLSID rclsid,REFIID riid,LPVOID *ppv)
|
||||||
* Success: S_OK
|
* Success: S_OK
|
||||||
* Failure: S_FALSE
|
* Failure: S_FALSE
|
||||||
*/
|
*/
|
||||||
DWORD WINAPI DllCanUnloadNow(void)
|
DWORD WINAPI DSOUND_DllCanUnloadNow(void)
|
||||||
{
|
{
|
||||||
FIXME(dsound, "(void): stub\n");
|
FIXME(dsound, "(void): stub\n");
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
|
@ -4,7 +4,7 @@ type win32
|
||||||
0 stdcall DirectSoundCreate(ptr ptr ptr) DirectSoundCreate
|
0 stdcall DirectSoundCreate(ptr ptr ptr) DirectSoundCreate
|
||||||
1 stdcall DirectSoundEnumerateA(ptr ptr) DirectSoundEnumerate32A
|
1 stdcall DirectSoundEnumerateA(ptr ptr) DirectSoundEnumerate32A
|
||||||
2 stub DirectSoundEnumerateW
|
2 stub DirectSoundEnumerateW
|
||||||
3 stdcall DllCanUnloadNow() DllCanUnloadNow
|
3 stdcall DllCanUnloadNow() DSOUND_DllCanUnloadNow
|
||||||
4 stdcall DllGetClassObject(ptr ptr ptr) DSOUND_DllGetClassObject
|
4 stdcall DllGetClassObject(ptr ptr ptr) DSOUND_DllGetClassObject
|
||||||
5 stub DirectSoundCaptureCreate
|
5 stub DirectSoundCaptureCreate
|
||||||
6 stub DirectSoundCaptureEnumerateA
|
6 stub DirectSoundCaptureEnumerateA
|
||||||
|
|
Loading…
Reference in New Issue