Skip to content

Instantly share code, notes, and snippets.

@bnolan
Created April 26, 2017 07:08
Show Gist options
  • Save bnolan/bce24855f49b52a62fded8af483eec60 to your computer and use it in GitHub Desktop.
Save bnolan/bce24855f49b52a62fded8af483eec60 to your computer and use it in GitHub Desktop.
Using the SDL microphone with libopus in loopback
#include <SDL2/SDL.h>
#include <opus.h>
#include <opus_types.h>
#include <stdlib.h>
static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static SDL_AudioSpec spec;
static SDL_AudioDeviceID devid_in = 0;
static SDL_AudioDeviceID devid_out = 0;
int sampling_rate = 48000;
int channels = 1;
int frameSize = 480;
OpusEncoder* encoder;
OpusDecoder* decoder;
unsigned char encoded[1024 * 16];
static void loop()
{
SDL_bool please_quit = SDL_FALSE;
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) {
please_quit = SDL_TRUE;
} else if (e.type == SDL_KEYDOWN) {
if (e.key.keysym.sym == SDLK_ESCAPE) {
please_quit = SDL_TRUE;
}
} else if (e.type == SDL_MOUSEBUTTONDOWN) {
if (e.button.button == 1) {
SDL_PauseAudioDevice(devid_out, SDL_TRUE);
SDL_PauseAudioDevice(devid_in, SDL_FALSE);
}
} else if (e.type == SDL_MOUSEBUTTONUP) {
if (e.button.button == 1) {
SDL_PauseAudioDevice(devid_in, SDL_TRUE);
SDL_PauseAudioDevice(devid_out, SDL_FALSE);
}
}
}
if (SDL_GetAudioDeviceStatus(devid_in) == SDL_AUDIO_PLAYING) {
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
} else {
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
}
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
if (please_quit) {
/* stop playing back, quit. */
SDL_Log("Shutting down.\n");
SDL_PauseAudioDevice(devid_in, 1);
SDL_CloseAudioDevice(devid_in);
SDL_PauseAudioDevice(devid_out, 1);
SDL_CloseAudioDevice(devid_out);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
exit(0);
}
/* Note that it would be easier to just have a one-line function that
calls SDL_QueueAudio() as a capture device callback, but we're
trying to test the API, so we use SDL_DequeueAudio() here. */
while (SDL_TRUE) {
Uint8 buf[frameSize * sizeof(float) * channels];
float *samples = (float *)&buf;
const Uint32 br = SDL_DequeueAudio(devid_in, buf, sizeof (buf));
// Amplify!
for (int i = 0; i < frameSize * channels; i++) {
samples[i] *= 32;
}
int encodedSize = opus_encode_float(encoder, samples, frameSize, (unsigned char *) &encoded, sizeof(encoded));
printf("Encoded size: %d (%f%%)\n", encodedSize, 100.0 / sizeof(buf) * encodedSize);
Uint8 decodedBuf[1024 * 16];
float *decodedSamples = (float *)&decodedBuf;
int decodedSize = opus_decode_float(decoder, (unsigned char *) &encoded, encodedSize, decodedSamples, frameSize, 0);
// printf("Decoded size: %d %d\n", decodedSize, decodedBuf[8]);
SDL_QueueAudio(devid_out, decodedBuf, br);
if (br < sizeof (buf)) {
break;
}
}
}
int
main(int argc, char **argv)
{
int application = OPUS_APPLICATION_AUDIO;
int err;
// Create opus
encoder = opus_encoder_create(sampling_rate, channels, application, &err);
if (err) {
printf("Err creating encoder %d", err);
exit(-1);
}
decoder = opus_decoder_create(sampling_rate, channels, &err);
if (err) {
printf("Err creating decoder %d", err);
exit(-1);
}
//encoded = (unsigned char *)calloc(1024 * 16 * 4);
/* (argv[1] == NULL means "open default device.") */
const char *devname = argv[1];
SDL_AudioSpec wanted;
int devcount;
int i;
/* 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);
}
window = SDL_CreateWindow("testaudiocapture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0);
renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Log("Using audico driver: %s\n", SDL_GetCurrentAudioDriver());
devcount = SDL_GetNumAudioDevices(SDL_TRUE);
for (i = 0; i < devcount; i++) {
SDL_Log(" Capture device #%d: '%s'\n", i, SDL_GetAudioDeviceName(i, SDL_TRUE));
}
SDL_zero(wanted);
wanted.freq = sampling_rate;
wanted.format = AUDIO_F32SYS;
wanted.channels = channels;
wanted.samples = 4096;
wanted.callback = NULL;
SDL_zero(spec);
/* DirectSound can fail in some instances if you open the same hardware
for both capture and output and didn't open the output end first,
according to the docs, so if you're doing something like this, always
open your capture devices second in case you land in those bizarre
circumstances. */
SDL_Log("Opening default playback device...\n");
devid_out = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wanted, &spec, SDL_AUDIO_ALLOW_ANY_CHANGE);
if (!devid_out) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for playback: %s!\n", SDL_GetError());
SDL_Quit();
exit(1);
}
SDL_Log("Opening capture device %s%s%s...\n",
devname ? "'" : "",
devname ? devname : "[[default]]",
devname ? "'" : "");
devid_in = SDL_OpenAudioDevice(argv[1], SDL_TRUE, &spec, &spec, 0);
if (!devid_in) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open an audio device for capture: %s!\n", SDL_GetError());
SDL_Quit();
exit(1);
}
SDL_Log("Ready! Hold down mouse or finger to record!\n");
while (1) { loop(); SDL_Delay(16); }
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment