From ee099750079ed30326dd6e3be0df32f2d68d474c Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 1 Aug 2016 00:18:56 -0400 Subject: [PATCH] audio: Initial bits to enable audio capture support. --- .hgignore | 1 + src/audio/SDL_audio.c | 2 +- test/Makefile.in | 4 + test/testaudiocapture.c | 161 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 test/testaudiocapture.c diff --git a/.hgignore b/.hgignore index 84122f80f..fc65a7f0c 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 05674eb86..eb1dd5e92 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, ¤t_audio.inputDevices, ¤t_audio.inputDeviceCount); } diff --git a/test/Makefile.in b/test/Makefile.in index b5fbc737c..68f0d3dab 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 000000000..ce96c6100 --- /dev/null +++ b/test/testaudiocapture.c @@ -0,0 +1,161 @@ +/* + Copyright (C) 1997-2016 Sam Lantinga + + 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 +#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; +} +