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:
Robert Riggs 1998-12-07 12:13:01 +00:00 committed by Alexandre Julliard
parent eee1ddc809
commit f0fa956384
2 changed files with 205 additions and 87 deletions

View File

@ -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;

View File

@ -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