--- a/src/audio/directsound/SDL_directsound.c Wed Aug 10 15:34:24 2016 -0400
+++ b/src/audio/directsound/SDL_directsound.c Wed Aug 10 16:00:16 2016 -0400
@@ -24,6 +24,7 @@
/* Allow access to a raw mixing buffer */
+#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_loadso.h"
#include "SDL_audio.h"
@@ -36,11 +37,13 @@
/* DirectX function pointers for audio */
static void* DSoundDLL = NULL;
-typedef HRESULT(WINAPI*fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
-typedef HRESULT(WINAPI*fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
-typedef HRESULT(WINAPI*fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
+typedef HRESULT (WINAPI *fnDirectSoundCreate8)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
+typedef HRESULT (WINAPI *fnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+typedef HRESULT (WINAPI *fnDirectSoundCaptureCreate8)(LPCGUID,LPDIRECTSOUNDCAPTURE8 *,LPUNKNOWN);
+typedef HRESULT (WINAPI *fnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW,LPVOID);
static fnDirectSoundCreate8 pDirectSoundCreate8 = NULL;
static fnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL;
+static fnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL;
static fnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL;
static void
@@ -48,6 +51,7 @@
{
pDirectSoundCreate8 = NULL;
pDirectSoundEnumerateW = NULL;
+ pDirectSoundCaptureCreate8 = NULL;
pDirectSoundCaptureEnumerateW = NULL;
if (DSoundDLL != NULL) {
@@ -76,6 +80,7 @@
loaded = 1; /* will reset if necessary. */
DSOUNDLOAD(DirectSoundCreate8);
DSOUNDLOAD(DirectSoundEnumerateW);
+ DSOUNDLOAD(DirectSoundCaptureCreate8);
DSOUNDLOAD(DirectSoundCaptureEnumerateW);
#undef DSOUNDLOAD
@@ -197,7 +202,7 @@
return;
}
- while ((cursor / this->hidden->mixlen) == this->hidden->lastchunk) {
+ while ((cursor / this->spec.size) == this->hidden->lastchunk) {
/* FIXME: find out how much time is left and sleep that long */
SDL_Delay(1);
@@ -239,9 +244,8 @@
if (this->hidden->locked_buf) {
IDirectSoundBuffer_Unlock(this->hidden->mixbuf,
this->hidden->locked_buf,
- this->hidden->mixlen, NULL, 0);
+ this->spec.size, NULL, 0);
}
-
}
static Uint8 *
@@ -265,7 +269,7 @@
SetDSerror("DirectSound GetCurrentPosition", result);
return (NULL);
}
- cursor /= this->hidden->mixlen;
+ cursor /= this->spec.size;
#ifdef DEBUG_SOUND
/* Detect audio dropouts */
{
@@ -281,17 +285,17 @@
#endif
this->hidden->lastchunk = cursor;
cursor = (cursor + 1) % this->hidden->num_buffers;
- cursor *= this->hidden->mixlen;
+ cursor *= this->spec.size;
/* Lock the audio buffer */
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
- this->hidden->mixlen,
+ this->spec.size,
(LPVOID *) & this->hidden->locked_buf,
&rawlen, NULL, &junk, 0);
if (result == DSERR_BUFFERLOST) {
IDirectSoundBuffer_Restore(this->hidden->mixbuf);
result = IDirectSoundBuffer_Lock(this->hidden->mixbuf, cursor,
- this->hidden->mixlen,
+ this->spec.size,
(LPVOID *) & this->
hidden->locked_buf, &rawlen, NULL,
&junk, 0);
@@ -310,7 +314,7 @@
/* Wait for the playing chunk to finish */
if (stream != NULL) {
- SDL_memset(stream, this->spec.silence, this->hidden->mixlen);
+ SDL_memset(stream, this->spec.silence, this->spec.size);
DSOUND_PlayDevice(this);
}
DSOUND_WaitDevice(this);
@@ -319,83 +323,106 @@
IDirectSoundBuffer_Stop(this->hidden->mixbuf);
}
+static int
+DSOUND_CaptureFromDevice(_THIS, void *buffer, int buflen)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ DWORD junk, cursor, ptr1len, ptr2len;
+ VOID *ptr1, *ptr2;
+
+ SDL_assert(buflen == this->spec.size);
+
+ while (SDL_TRUE) {
+ if (SDL_AtomicGet(&this->shutdown)) { /* in case the buffer froze... */
+ SDL_memset(buffer, this->spec.silence, buflen);
+ return buflen;
+ }
+
+ if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) {
+ return -1;
+ }
+ if ((cursor / this->spec.size) == h->lastchunk) {
+ SDL_Delay(1); /* FIXME: find out how much time is left and sleep that long */
+ } else {
+ break;
+ }
+ }
+
+ if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * this->spec.size, this->spec.size, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) {
+ return -1;
+ }
+
+ SDL_assert(ptr1len == this->spec.size);
+ SDL_assert(ptr2 == NULL);
+ SDL_assert(ptr2len == 0);
+
+ SDL_memcpy(buffer, ptr1, ptr1len);
+
+ if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) {
+ return -1;
+ }
+
+ h->lastchunk = (h->lastchunk + 1) % h->num_buffers;
+
+ return ptr1len;
+}
+
+static void
+DSOUND_FlushCapture(_THIS)
+{
+ struct SDL_PrivateAudioData *h = this->hidden;
+ DWORD junk, cursor;
+ if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) {
+ h->lastchunk = cursor / this->spec.size;
+ }
+}
+
static void
DSOUND_CloseDevice(_THIS)
{
if (this->hidden->mixbuf != NULL) {
+ IDirectSoundBuffer_Stop(this->hidden->mixbuf);
IDirectSoundBuffer_Release(this->hidden->mixbuf);
}
if (this->hidden->sound != NULL) {
IDirectSound_Release(this->hidden->sound);
}
+ if (this->hidden->capturebuf != NULL) {
+ IDirectSoundCaptureBuffer_Stop(this->hidden->capturebuf);
+ IDirectSoundCaptureBuffer_Release(this->hidden->capturebuf);
+ }
+ if (this->hidden->capture != NULL) {
+ IDirectSoundCapture_Release(this->hidden->capture);
+ }
SDL_free(this->hidden);
}
/* This function tries to create a secondary audio buffer, and returns the
- number of audio chunks available in the created buffer.
+ number of audio chunks available in the created buffer. This is for
+ playback devices, not capture.
*/
static int
-CreateSecondary(_THIS, HWND focus)
+CreateSecondary(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
{
LPDIRECTSOUND sndObj = this->hidden->sound;
LPDIRECTSOUNDBUFFER *sndbuf = &this->hidden->mixbuf;
- Uint32 chunksize = this->spec.size;
- const int numchunks = 8;
HRESULT result = DS_OK;
DSBUFFERDESC format;
LPVOID pvAudioPtr1, pvAudioPtr2;
DWORD dwAudioBytes1, dwAudioBytes2;
- WAVEFORMATEX wfmt;
-
- SDL_zero(wfmt);
-
- if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
- wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- } else {
- wfmt.wFormatTag = WAVE_FORMAT_PCM;
- }
-
- wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
- wfmt.nChannels = this->spec.channels;
- wfmt.nSamplesPerSec = this->spec.freq;
- wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
- wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
-
- /* Try to set primary mixing privileges */
- if (focus) {
- result = IDirectSound_SetCooperativeLevel(sndObj,
- focus, DSSCL_PRIORITY);
- } else {
- result = IDirectSound_SetCooperativeLevel(sndObj,
- GetDesktopWindow(),
- DSSCL_NORMAL);
- }
- if (result != DS_OK) {
- return SetDSerror("DirectSound SetCooperativeLevel", result);
- }
/* Try to create the secondary buffer */
SDL_zero(format);
format.dwSize = sizeof(format);
format.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
- if (!focus) {
- format.dwFlags |= DSBCAPS_GLOBALFOCUS;
- } else {
- format.dwFlags |= DSBCAPS_STICKYFOCUS;
- }
- format.dwBufferBytes = numchunks * chunksize;
- if ((format.dwBufferBytes < DSBSIZE_MIN) ||
- (format.dwBufferBytes > DSBSIZE_MAX)) {
- return SDL_SetError("Sound buffer size must be between %d and %d",
- DSBSIZE_MIN / numchunks, DSBSIZE_MAX / numchunks);
- }
- format.dwReserved = 0;
- format.lpwfxFormat = &wfmt;
+ format.dwFlags |= DSBCAPS_GLOBALFOCUS;
+ format.dwBufferBytes = bufsize;
+ format.lpwfxFormat = wfmt;
result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL);
if (result != DS_OK) {
return SetDSerror("DirectSound CreateSoundBuffer", result);
}
- IDirectSoundBuffer_SetFormat(*sndbuf, &wfmt);
+ IDirectSoundBuffer_SetFormat(*sndbuf, wfmt);
/* Silence the initial audio buffer */
result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes,
@@ -410,18 +437,65 @@
}
/* We're ready to go */
- return (numchunks);
+ return 0;
+}
+
+/* This function tries to create a capture buffer, and returns the
+ number of audio chunks available in the created buffer. This is for
+ capture devices, not playback.
+*/
+static int
+CreateCaptureBuffer(_THIS, const DWORD bufsize, WAVEFORMATEX *wfmt)
+{
+ LPDIRECTSOUNDCAPTURE capture = this->hidden->capture;
+ LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &this->hidden->capturebuf;
+ DSCBUFFERDESC format;
+// DWORD junk, cursor;
+ HRESULT result;
+
+ SDL_zero(format);
+ format.dwSize = sizeof (format);
+ format.dwFlags = DSCBCAPS_WAVEMAPPED;
+ format.dwBufferBytes = bufsize;
+ format.lpwfxFormat = wfmt;
+
+ result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSound CreateCaptureBuffer", result);
+ }
+
+ result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING);
+ if (result != DS_OK) {
+ IDirectSoundCaptureBuffer_Release(*capturebuf);
+ return SetDSerror("DirectSound Start", result);
+ }
+
+#if 0
+ /* presumably this starts at zero, but just in case... */
+ result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor);
+ if (result != DS_OK) {
+ IDirectSoundCaptureBuffer_Stop(*capturebuf);
+ IDirectSoundCaptureBuffer_Release(*capturebuf);
+ return SetDSerror("DirectSound GetCurrentPosition", result);
+ }
+
+ this->hidden->lastchunk = cursor / this->spec.size;
+#endif
+
+ return 0;
}
static int
DSOUND_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
+ const DWORD numchunks = 8;
HRESULT result;
SDL_bool valid_format = SDL_FALSE;
SDL_bool tried_format = SDL_FALSE;
SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
LPGUID guid = (LPGUID) handle;
-
+ DWORD bufsize;
+
/* Initialize all variables that we clean on shutdown */
this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc((sizeof *this->hidden));
@@ -431,9 +505,22 @@
SDL_zerop(this->hidden);
/* Open the audio device */
- result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
- if (result != DS_OK) {
- return SetDSerror("DirectSoundCreate", result);
+ if (iscapture) {
+ result = pDirectSoundCaptureCreate8(guid, &this->hidden->capture, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSoundCaptureCreate8", result);
+ }
+ } else {
+ result = pDirectSoundCreate8(guid, &this->hidden->sound, NULL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSoundCreate8", result);
+ }
+ result = IDirectSound_SetCooperativeLevel(this->hidden->sound,
+ GetDesktopWindow(),
+ DSSCL_NORMAL);
+ if (result != DS_OK) {
+ return SetDSerror("DirectSound SetCooperativeLevel", result);
+ }
}
while ((!valid_format) && (test_format)) {
@@ -443,12 +530,38 @@
case AUDIO_S32:
case AUDIO_F32:
tried_format = SDL_TRUE;
+
this->spec.format = test_format;
+
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(&this->spec);
- this->hidden->num_buffers = CreateSecondary(this, NULL);
- if (this->hidden->num_buffers > 0) {
- valid_format = SDL_TRUE;
+
+ bufsize = numchunks * this->spec.size;
+ if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) {
+ SDL_SetError("Sound buffer size must be between %d and %d",
+ (DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks,
+ DSBSIZE_MAX / numchunks);
+ } else {
+ int rc;
+ WAVEFORMATEX wfmt;
+ SDL_zero(wfmt);
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ wfmt.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ wfmt.wFormatTag = WAVE_FORMAT_PCM;
+ }
+
+ wfmt.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+ wfmt.nChannels = this->spec.channels;
+ wfmt.nSamplesPerSec = this->spec.freq;
+ wfmt.nBlockAlign = wfmt.nChannels * (wfmt.wBitsPerSample / 8);
+ wfmt.nAvgBytesPerSec = wfmt.nSamplesPerSec * wfmt.nBlockAlign;
+
+ rc = iscapture ? CreateCaptureBuffer(this, bufsize, &wfmt) : CreateSecondary(this, bufsize, &wfmt);
+ if (rc == 0) {
+ this->hidden->num_buffers = numchunks;
+ valid_format = SDL_TRUE;
+ }
}
break;
}
@@ -462,8 +575,7 @@
return SDL_SetError("DirectSound: Unsupported audio format");
}
- /* The buffer will auto-start playing in DSOUND_WaitDevice() */
- this->hidden->mixlen = this->spec.size;
+ /* Playback buffers will auto-start playing in DSOUND_WaitDevice() */
return 0; /* good to go. */
}
@@ -490,10 +602,13 @@
impl->WaitDevice = DSOUND_WaitDevice;
impl->WaitDone = DSOUND_WaitDone;
impl->GetDeviceBuf = DSOUND_GetDeviceBuf;
+ impl->CaptureFromDevice = DSOUND_CaptureFromDevice;
+ impl->FlushCapture = DSOUND_FlushCapture;
impl->CloseDevice = DSOUND_CloseDevice;
impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle;
+ impl->Deinitialize = DSOUND_Deinitialize;
- impl->Deinitialize = DSOUND_Deinitialize;
+ impl->HasCaptureSupport = SDL_TRUE;
return 1; /* this audio target is available. */
}