Commit ee099750079ed30326dd6e3be0df32f2d68d474c

Ryan C. Gordon 2016-08-01T00:18:56

audio: Initial bits to enable audio capture support.

diff --git a/.hgignore b/.hgignore
index 84122f8..fc65a7f 100644
--- a/.hgignore
+++ b/.hgignore
@@ -120,6 +120,7 @@ test/testbounds
 test/torturethread
 test/testdisplayinfo
 test/testqsort
+test/testaudiocapture
 test/*.exe
 test/*.dSYM
 buildbot
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 05674eb..eb1dd5e 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -317,7 +317,7 @@ add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, 
 static SDL_INLINE int
 add_capture_device(const char *name, void *handle)
 {
-    /* !!! FIXME: add this later. SDL_assert(current_audio.impl.HasCaptureSupport);*/
+    SDL_assert(current_audio.impl.HasCaptureSupport);
     return add_audio_device(name, handle, &current_audio.inputDevices, &current_audio.inputDeviceCount);
 }
 
diff --git a/test/Makefile.in b/test/Makefile.in
index b5fbc73..68f0d3d 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -13,6 +13,7 @@ TARGETS = \
 	loopwavequeue$(EXE) \
 	testatomic$(EXE) \
 	testaudioinfo$(EXE) \
+	testaudiocapture$(EXE) \
 	testautomation$(EXE) \
 	testbounds$(EXE) \
 	testcustomcursor$(EXE) \
@@ -113,6 +114,9 @@ testmultiaudio$(EXE): $(srcdir)/testmultiaudio.c
 testaudiohotplug$(EXE): $(srcdir)/testaudiohotplug.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
+testaudiocapture$(EXE): $(srcdir)/testaudiocapture.c
+	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
+
 testatomic$(EXE): $(srcdir)/testatomic.c
 	$(CC) -o $@ $^ $(CFLAGS) $(LIBS)
 
diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c
new file mode 100644
index 0000000..ce96c61
--- /dev/null
+++ b/test/testaudiocapture.c
@@ -0,0 +1,161 @@
+/*
+  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+#include "SDL.h"
+
+#ifdef __EMSCRIPTEN__
+#include <emscripten/emscripten.h>
+#endif
+
+#define CAPTURE_SECONDS 5
+
+static SDL_AudioSpec spec;
+static Uint8 *sound = NULL;     /* Pointer to wave data */
+static Uint32 soundlen = 0;     /* Length of wave data */
+static Uint32 processed = 0;
+static SDL_AudioDeviceID devid = 0;
+
+void SDLCALL
+capture_callback(void *arg, Uint8 * stream, int len)
+{
+    const int avail = (int) (soundlen - processed);
+    if (len > avail) {
+        len = avail;
+    }
+
+    /*SDL_Log("CAPTURE CALLBACK: %d more bytes\n", len);*/
+    SDL_memcpy(sound + processed, stream, len);
+    processed += len;
+}
+
+void SDLCALL
+play_callback(void *arg, Uint8 * stream, int len)
+{
+    const Uint8 *waveptr = sound + processed;
+    const int avail = soundlen - processed;
+    int cpy = len;
+    if (cpy > avail) {
+        cpy = avail;
+    }
+
+    /*SDL_Log("PLAY CALLBACK: %d more bytes\n", cpy);*/
+    SDL_memcpy(stream, waveptr, cpy);
+    processed += cpy;
+
+    len -= cpy;
+    if (len > 0) {
+        SDL_memset(stream + cpy, spec.silence, len);
+    }
+}
+
+static void
+loop()
+{
+    SDL_Event e;
+    SDL_bool please_quit = SDL_FALSE;
+
+    while (SDL_PollEvent(&e)) {
+        if (e.type == SDL_QUIT) {
+            please_quit = SDL_TRUE;
+        }
+    }
+
+    if ((!please_quit) && (processed >= soundlen)) {
+        processed = 0;
+        if (spec.callback == capture_callback) {
+            SDL_Log("Done recording, playing back...\n");
+            SDL_PauseAudioDevice(devid, 1);
+            SDL_CloseAudioDevice(devid);
+
+            spec.callback = play_callback;
+            devid = SDL_OpenAudioDevice(NULL, 0, &spec, &spec, 0);
+            if (!devid) {
+                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback!\n");
+                SDL_Quit();
+                exit(1);
+            }
+
+            SDL_PauseAudioDevice(devid, 0);
+        } else {
+            SDL_Log("Done playing back.\n");
+            please_quit = SDL_TRUE;
+        }
+    }
+
+    if (please_quit) {
+        /* stop playing back, quit. */
+        SDL_Log("Shutting down.\n");
+        SDL_PauseAudioDevice(devid, 1);
+        SDL_CloseAudioDevice(devid);
+        SDL_free(sound);
+        sound = NULL;
+        SDL_Quit();
+        #ifdef __EMSCRIPTEN__
+        emscripten_cancel_main_loop();
+        #endif
+        exit(0);
+    }
+}
+
+int
+main(int argc, char **argv)
+{
+    /* Enable standard application logging */
+    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
+
+    /* Load the SDL library */
+    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
+        return (1);
+    }
+
+    /* Android apparently needs a window...? */
+    #ifdef __ANDROID__  
+    SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0);
+    #endif
+
+    SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
+
+    SDL_zero(spec);
+    spec.freq = 44100;
+    spec.format = AUDIO_F32SYS;
+    spec.channels = 1;
+    spec.samples = 1024;
+    spec.callback = capture_callback;
+
+    soundlen = spec.freq * (SDL_AUDIO_BITSIZE(spec.format) / 8) * spec.channels * CAPTURE_SECONDS;
+    sound = (Uint8 *) SDL_malloc(soundlen);
+    if (!sound) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory\n");
+        SDL_Quit();
+        return 1;
+    }
+
+    devid = SDL_OpenAudioDevice(NULL, 1, &spec, &spec, 0);
+    if (!devid) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
+        SDL_free(sound);
+        SDL_Quit();
+        exit(1);
+    }
+
+    SDL_Log("Recording for %d seconds...\n", CAPTURE_SECONDS);
+    SDL_PauseAudioDevice(devid, 0);
+
+#ifdef __EMSCRIPTEN__
+    emscripten_set_main_loop(loop, 0, 1);
+#else
+    while (1) { loop(); SDL_Delay(16); }
+#endif
+
+    return 0;
+}
+