Skip to content
Permalink
Browse files

disk audio: Implemented "capture" support, cleaned up some things.

  • Loading branch information
icculus committed Aug 6, 2016
1 parent a15b974 commit 978df1ad746dca3bc4cfbe29ade83e93c1304d7c
Showing with 82 additions and 46 deletions.
  1. +0 −5 src/audio/SDL_audio.c
  2. +4 −0 src/audio/SDL_sysaudio.h
  3. +76 −38 src/audio/disk/SDL_diskaudio.c
  4. +2 −3 src/audio/disk/SDL_diskaudio.h
@@ -33,11 +33,6 @@
static SDL_AudioDriver current_audio;
static SDL_AudioDevice *open_devices[16];

/* !!! FIXME: These are wordy and unlocalized... */
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"


/*
* Not all of these will be compiled and linked in, but it's convenient
* to have a complete list here and saves yet-another block of #ifdefs...
@@ -26,6 +26,10 @@
#include "SDL_mutex.h"
#include "SDL_thread.h"

/* !!! FIXME: These are wordy and unlocalized... */
#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
#define DEFAULT_INPUT_DEVNAME "System audio capture device"

/* The SDL audio driver */
typedef struct SDL_AudioDevice SDL_AudioDevice;
#define _THIS SDL_AudioDevice *_this
@@ -34,42 +34,31 @@
#include "../SDL_audio_c.h"
#include "SDL_diskaudio.h"

/* !!! FIXME: these should be SDL hints, not environment variables. */
/* environment variables and defaults. */
#define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE"
#define DISKDEFAULT_OUTFILE "sdlaudio.raw"
#define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_WRITEDELAY 150

static const char *
DISKAUD_GetOutputFilename(const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(DISKENVR_OUTFILE);
if (devname == NULL) {
devname = DISKDEFAULT_OUTFILE;
}
}
return devname;
}
#define DISKENVR_INFILE "SDL_DISKAUDIOFILEIN"
#define DISKDEFAULT_INFILE "sdlaudio-in.raw"
#define DISKENVR_IODELAY "SDL_DISKAUDIODELAY"
#define DISKDEFAULT_IODELAY 150

/* This function waits until it is possible to write a full sound buffer */
static void
DISKAUD_WaitDevice(_THIS)
{
SDL_Delay(this->hidden->write_delay);
SDL_Delay(this->hidden->io_delay);
}

static void
DISKAUD_PlayDevice(_THIS)
{
size_t written;

/* Write the audio data */
written = SDL_RWwrite(this->hidden->output,
this->hidden->mixbuf, 1, this->hidden->mixlen);
const size_t written = SDL_RWwrite(this->hidden->io,
this->hidden->mixbuf,
1, this->spec.size);

/* If we couldn't write, assume fatal error for now */
if (written != this->hidden->mixlen) {
if (written != this->spec.size) {
SDL_OpenedAudioDeviceDisconnected(this);
}
#ifdef DEBUG_AUDIO
@@ -83,22 +72,66 @@ DISKAUD_GetDeviceBuf(_THIS)
return (this->hidden->mixbuf);
}

static int
DISKAUD_CaptureFromDevice(_THIS, void *buffer, int buflen)
{
struct SDL_PrivateAudioData *h = this->hidden;
const int origbuflen = buflen;

SDL_Delay(h->io_delay);

if (h->io) {
const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
buflen -= (int) br;
buffer = ((Uint8 *) buffer) + br;
if (buflen > 0) { /* EOF (or error, but whatever). */
SDL_RWclose(h->io);
h->io = NULL;
}
}

/* if we ran out of file, just write silence. */
SDL_memset(buffer, this->spec.silence, buflen);

return origbuflen;
}

static void
DISKAUD_FlushCapture(_THIS)
{
/* no op...we don't advance the file pointer or anything. */
}


static void
DISKAUD_CloseDevice(_THIS)
{
if (this->hidden->output != NULL) {
SDL_RWclose(this->hidden->output);
if (this->hidden->io != NULL) {
SDL_RWclose(this->hidden->io);
}
SDL_free(this->hidden->mixbuf);
SDL_free(this->hidden);
}


static const char *
get_filename(const int iscapture, const char *devname)
{
if (devname == NULL) {
devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
if (devname == NULL) {
devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
}
}
return devname;
}

static int
DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
{
/* handle != NULL means "user specified the placeholder name on the fake detected device list" */
const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname);
const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
const char *fname = get_filename(iscapture, handle ? NULL : devname);
const char *envr = SDL_getenv(DISKENVR_IODELAY);

this->hidden = (struct SDL_PrivateAudioData *)
SDL_malloc(sizeof(*this->hidden));
@@ -107,27 +140,28 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
}
SDL_zerop(this->hidden);

this->hidden->mixlen = this->spec.size;
this->hidden->write_delay =
(envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
this->hidden->io_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_IODELAY;

/* Open the audio device */
this->hidden->output = SDL_RWFromFile(fname, "wb");
if (this->hidden->output == NULL) {
this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
if (this->hidden->io == NULL) {
return -1;
}

/* Allocate mixing buffer */
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
if (this->hidden->mixbuf == NULL) {
return -1;
if (!iscapture) {
this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
if (this->hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
}
SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);

#if HAVE_STDIO_H
fprintf(stderr,
"WARNING: You are using the SDL disk writer audio driver!\n"
" Writing to file [%s].\n", fname);
"WARNING: You are using the SDL disk i/o audio driver!\n"
" %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
fname);
#endif

/* We're ready to rock and roll. :-) */
@@ -137,8 +171,8 @@ DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
static void
DISKAUD_DetectDevices(void)
{
/* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */
SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1);
SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
}

static int
@@ -149,10 +183,14 @@ DISKAUD_Init(SDL_AudioDriverImpl * impl)
impl->WaitDevice = DISKAUD_WaitDevice;
impl->PlayDevice = DISKAUD_PlayDevice;
impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
impl->CaptureFromDevice = DISKAUD_CaptureFromDevice;
impl->FlushCapture = DISKAUD_FlushCapture;

impl->CloseDevice = DISKAUD_CloseDevice;
impl->DetectDevices = DISKAUD_DetectDevices;

impl->AllowsArbitraryDeviceNames = 1;
impl->HasCaptureSupport = SDL_TRUE;

return 1; /* this audio target is available. */
}
@@ -32,10 +32,9 @@
struct SDL_PrivateAudioData
{
/* The file descriptor for the audio device */
SDL_RWops *output;
SDL_RWops *io;
Uint32 io_delay;
Uint8 *mixbuf;
Uint32 mixlen;
Uint32 write_delay;
};

#endif /* _SDL_diskaudio_h */

0 comments on commit 978df1a

Please sign in to comment.