Skip to content
Permalink
Browse files

winmm: Implemented audio capture support.

  • Loading branch information
icculus committed Aug 6, 2016
1 parent 4499e5b commit 51d15233800eca1e4e0a818e8bdd173d3a473ce1
Showing with 120 additions and 26 deletions.
  1. +120 −26 src/audio/winmm/SDL_winmm.c
@@ -27,6 +27,7 @@
#include "../../core/windows/SDL_windows.h"
#include <mmsystem.h>

#include "SDL_assert.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "../SDL_audio_c.h"
@@ -152,30 +153,83 @@ WINMM_WaitDone(_THIS)
} while (left > 0);
}

static int
WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
const int nextbuf = this->hidden->next_buffer;
MMRESULT result;

SDL_assert(buflen == this->spec.size);

/* Wait for an audio chunk to finish */
WaitForSingleObject(this->hidden->audio_sem, INFINITE);

/* Copy it to caller's buffer... */
SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);

/* requeue the buffer that just finished. */
result = waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[nextbuf],
sizeof (this->hidden->wavebuf[nextbuf]));
if (result != MMSYSERR_NOERROR) {
return -1; /* uhoh! Disable the device. */
}

/* queue the next buffer in sequence, next time. */
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
return this->spec.size;
}

static void
WINMM_FlushCapture(_THIS)
{
/* Wait for an audio chunk to finish */
if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
const int nextbuf = this->hidden->next_buffer;
/* requeue the buffer that just finished without reading from it. */
waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[nextbuf],
sizeof (this->hidden->wavebuf[nextbuf]));
this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
}
}

static void
WINMM_CloseDevice(_THIS)
{
int i;

if (this->hidden->audio_sem) {
CloseHandle(this->hidden->audio_sem);
}
if (this->hidden->hout) {
waveOutReset(this->hidden->hout);

/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveOutUnprepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
}
}

waveOutClose(this->hidden->hout);
}

if (this->hidden->hin) {
waveInReset(this->hidden->hin);

/* Clean up mixing buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
waveInUnprepareHeader(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof (this->hidden->wavebuf[i]));
}
}
waveInClose(this->hidden->hin);
}

if (this->hidden->hout) {
waveOutClose(this->hidden->hout);
if (this->hidden->audio_sem) {
CloseHandle(this->hidden->audio_sem);
}

SDL_free(this->hidden->mixbuf);
@@ -269,32 +323,44 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
result = waveInOpen(&this->hidden->hin, devId, &waveformat,
(DWORD_PTR) CaptureSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInOpen()", result);
}
} else {
result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
(DWORD_PTR) FillSound, (DWORD_PTR) this,
CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutOpen()", result);
}
}

if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutOpen()", result);
}
#ifdef SOUND_DEBUG
/* Check the sound device we retrieved */
{
WAVEOUTCAPS caps;

result = waveOutGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutGetDevCaps()", result);
if (iscapture) {
WAVEINCAPS caps;
result = waveInGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof (caps));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInGetDevCaps()", result);
}
printf("Audio device: %s\n", caps.szPname);
} else {
WAVEOUTCAPS caps;
result = waveOutGetDevCaps((UINT) this->hidden->hout,
&caps, sizeof(caps));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutGetDevCaps()", result);
}
printf("Audio device: %s\n", caps.szPname);
}
printf("Audio device: %s\n", caps.szPname);
}
#endif

/* Create the audio buffer semaphore */
this->hidden->audio_sem =
CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
if (this->hidden->audio_sem == NULL) {
return SDL_SetError("Couldn't create semaphore");
}
@@ -312,11 +378,35 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
this->hidden->wavebuf[i].lpData =
(LPSTR) & this->hidden->mixbuf[i * this->spec.size];
result = waveOutPrepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));

if (iscapture) {
result = waveInPrepareHeader(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInPrepareHeader()", result);
}

result = waveInAddBuffer(this->hidden->hin,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveInAddBuffer()", result);
}
} else {
result = waveOutPrepareHeader(this->hidden->hout,
&this->hidden->wavebuf[i],
sizeof(this->hidden->wavebuf[i]));
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutPrepareHeader()", result);
}
}
}

if (iscapture) {
result = waveInStart(this->hidden->hin);
if (result != MMSYSERR_NOERROR) {
return SetMMerror("waveOutPrepareHeader()", result);
return SetMMerror("waveInStart()", result);
}
}

@@ -334,8 +424,12 @@ WINMM_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = WINMM_WaitDevice;
impl->WaitDone = WINMM_WaitDone;
impl->GetDeviceBuf = WINMM_GetDeviceBuf;
impl->CaptureFromDevice = WINMM_CaptureFromDevice;
impl->FlushCapture = WINMM_FlushCapture;
impl->CloseDevice = WINMM_CloseDevice;

impl->HasCaptureSupport = SDL_TRUE;

return 1; /* this audio target is available. */
}

0 comments on commit 51d1523

Please sign in to comment.