disk audio: Implemented "capture" support, cleaned up some things.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 06 Aug 2016 03:39:15 -0400
changeset 10264db0b712b79dd
parent 10263 ec1844380edb
child 10265 886ab9de5f43
disk audio: Implemented "capture" support, cleaned up some things.
src/audio/SDL_audio.c
src/audio/SDL_sysaudio.h
src/audio/disk/SDL_diskaudio.c
src/audio/disk/SDL_diskaudio.h
     1.1 --- a/src/audio/SDL_audio.c	Sat Aug 06 02:48:00 2016 -0400
     1.2 +++ b/src/audio/SDL_audio.c	Sat Aug 06 03:39:15 2016 -0400
     1.3 @@ -33,11 +33,6 @@
     1.4  static SDL_AudioDriver current_audio;
     1.5  static SDL_AudioDevice *open_devices[16];
     1.6  
     1.7 -/* !!! FIXME: These are wordy and unlocalized... */
     1.8 -#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
     1.9 -#define DEFAULT_INPUT_DEVNAME "System audio capture device"
    1.10 -
    1.11 -
    1.12  /*
    1.13   * Not all of these will be compiled and linked in, but it's convenient
    1.14   *  to have a complete list here and saves yet-another block of #ifdefs...
     2.1 --- a/src/audio/SDL_sysaudio.h	Sat Aug 06 02:48:00 2016 -0400
     2.2 +++ b/src/audio/SDL_sysaudio.h	Sat Aug 06 03:39:15 2016 -0400
     2.3 @@ -26,6 +26,10 @@
     2.4  #include "SDL_mutex.h"
     2.5  #include "SDL_thread.h"
     2.6  
     2.7 +/* !!! FIXME: These are wordy and unlocalized... */
     2.8 +#define DEFAULT_OUTPUT_DEVNAME "System audio output device"
     2.9 +#define DEFAULT_INPUT_DEVNAME "System audio capture device"
    2.10 +
    2.11  /* The SDL audio driver */
    2.12  typedef struct SDL_AudioDevice SDL_AudioDevice;
    2.13  #define _THIS   SDL_AudioDevice *_this
     3.1 --- a/src/audio/disk/SDL_diskaudio.c	Sat Aug 06 02:48:00 2016 -0400
     3.2 +++ b/src/audio/disk/SDL_diskaudio.c	Sat Aug 06 03:39:15 2016 -0400
     3.3 @@ -34,42 +34,31 @@
     3.4  #include "../SDL_audio_c.h"
     3.5  #include "SDL_diskaudio.h"
     3.6  
     3.7 +/* !!! FIXME: these should be SDL hints, not environment variables. */
     3.8  /* environment variables and defaults. */
     3.9  #define DISKENVR_OUTFILE         "SDL_DISKAUDIOFILE"
    3.10  #define DISKDEFAULT_OUTFILE      "sdlaudio.raw"
    3.11 -#define DISKENVR_WRITEDELAY      "SDL_DISKAUDIODELAY"
    3.12 -#define DISKDEFAULT_WRITEDELAY   150
    3.13 -
    3.14 -static const char *
    3.15 -DISKAUD_GetOutputFilename(const char *devname)
    3.16 -{
    3.17 -    if (devname == NULL) {
    3.18 -        devname = SDL_getenv(DISKENVR_OUTFILE);
    3.19 -        if (devname == NULL) {
    3.20 -            devname = DISKDEFAULT_OUTFILE;
    3.21 -        }
    3.22 -    }
    3.23 -    return devname;
    3.24 -}
    3.25 +#define DISKENVR_INFILE         "SDL_DISKAUDIOFILEIN"
    3.26 +#define DISKDEFAULT_INFILE      "sdlaudio-in.raw"
    3.27 +#define DISKENVR_IODELAY      "SDL_DISKAUDIODELAY"
    3.28 +#define DISKDEFAULT_IODELAY   150
    3.29  
    3.30  /* This function waits until it is possible to write a full sound buffer */
    3.31  static void
    3.32  DISKAUD_WaitDevice(_THIS)
    3.33  {
    3.34 -    SDL_Delay(this->hidden->write_delay);
    3.35 +    SDL_Delay(this->hidden->io_delay);
    3.36  }
    3.37  
    3.38  static void
    3.39  DISKAUD_PlayDevice(_THIS)
    3.40  {
    3.41 -    size_t written;
    3.42 -
    3.43 -    /* Write the audio data */
    3.44 -    written = SDL_RWwrite(this->hidden->output,
    3.45 -                          this->hidden->mixbuf, 1, this->hidden->mixlen);
    3.46 +    const size_t written = SDL_RWwrite(this->hidden->io,
    3.47 +                                       this->hidden->mixbuf,
    3.48 +                                       1, this->spec.size);
    3.49  
    3.50      /* If we couldn't write, assume fatal error for now */
    3.51 -    if (written != this->hidden->mixlen) {
    3.52 +    if (written != this->spec.size) {
    3.53          SDL_OpenedAudioDeviceDisconnected(this);
    3.54      }
    3.55  #ifdef DEBUG_AUDIO
    3.56 @@ -83,22 +72,66 @@
    3.57      return (this->hidden->mixbuf);
    3.58  }
    3.59  
    3.60 +static int
    3.61 +DISKAUD_CaptureFromDevice(_THIS, void *buffer, int buflen)
    3.62 +{
    3.63 +    struct SDL_PrivateAudioData *h = this->hidden;
    3.64 +    const int origbuflen = buflen;
    3.65 +
    3.66 +    SDL_Delay(h->io_delay);
    3.67 +
    3.68 +    if (h->io) {
    3.69 +        const size_t br = SDL_RWread(h->io, buffer, 1, buflen);
    3.70 +        buflen -= (int) br;
    3.71 +        buffer = ((Uint8 *) buffer) + br;
    3.72 +        if (buflen > 0) {  /* EOF (or error, but whatever). */
    3.73 +            SDL_RWclose(h->io);
    3.74 +            h->io = NULL;
    3.75 +        }
    3.76 +    }
    3.77 +
    3.78 +    /* if we ran out of file, just write silence. */
    3.79 +    SDL_memset(buffer, this->spec.silence, buflen);
    3.80 +
    3.81 +    return origbuflen;
    3.82 +}
    3.83 +
    3.84 +static void
    3.85 +DISKAUD_FlushCapture(_THIS)
    3.86 +{
    3.87 +    /* no op...we don't advance the file pointer or anything. */
    3.88 +}
    3.89 +
    3.90 +
    3.91  static void
    3.92  DISKAUD_CloseDevice(_THIS)
    3.93  {
    3.94 -    if (this->hidden->output != NULL) {
    3.95 -        SDL_RWclose(this->hidden->output);
    3.96 +    if (this->hidden->io != NULL) {
    3.97 +        SDL_RWclose(this->hidden->io);
    3.98      }
    3.99      SDL_free(this->hidden->mixbuf);
   3.100      SDL_free(this->hidden);
   3.101  }
   3.102  
   3.103 +
   3.104 +static const char *
   3.105 +get_filename(const int iscapture, const char *devname)
   3.106 +{
   3.107 +    if (devname == NULL) {
   3.108 +        devname = SDL_getenv(iscapture ? DISKENVR_INFILE : DISKENVR_OUTFILE);
   3.109 +        if (devname == NULL) {
   3.110 +            devname = iscapture ? DISKDEFAULT_INFILE : DISKDEFAULT_OUTFILE;
   3.111 +        }
   3.112 +    }
   3.113 +    return devname;
   3.114 +}
   3.115 +
   3.116  static int
   3.117  DISKAUD_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
   3.118  {
   3.119      /* handle != NULL means "user specified the placeholder name on the fake detected device list" */
   3.120 -    const char *fname = DISKAUD_GetOutputFilename(handle ? NULL : devname);
   3.121 -    const char *envr = SDL_getenv(DISKENVR_WRITEDELAY);
   3.122 +    const char *fname = get_filename(iscapture, handle ? NULL : devname);
   3.123 +    const char *envr = SDL_getenv(DISKENVR_IODELAY);
   3.124  
   3.125      this->hidden = (struct SDL_PrivateAudioData *)
   3.126          SDL_malloc(sizeof(*this->hidden));
   3.127 @@ -107,27 +140,28 @@
   3.128      }
   3.129      SDL_zerop(this->hidden);
   3.130  
   3.131 -    this->hidden->mixlen = this->spec.size;
   3.132 -    this->hidden->write_delay =
   3.133 -        (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY;
   3.134 +    this->hidden->io_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_IODELAY;
   3.135  
   3.136      /* Open the audio device */
   3.137 -    this->hidden->output = SDL_RWFromFile(fname, "wb");
   3.138 -    if (this->hidden->output == NULL) {
   3.139 +    this->hidden->io = SDL_RWFromFile(fname, iscapture ? "rb" : "wb");
   3.140 +    if (this->hidden->io == NULL) {
   3.141          return -1;
   3.142      }
   3.143  
   3.144      /* Allocate mixing buffer */
   3.145 -    this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->hidden->mixlen);
   3.146 -    if (this->hidden->mixbuf == NULL) {
   3.147 -        return -1;
   3.148 +    if (!iscapture) {
   3.149 +        this->hidden->mixbuf = (Uint8 *) SDL_malloc(this->spec.size);
   3.150 +        if (this->hidden->mixbuf == NULL) {
   3.151 +            return SDL_OutOfMemory();
   3.152 +        }
   3.153 +        SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   3.154      }
   3.155 -    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
   3.156  
   3.157  #if HAVE_STDIO_H
   3.158      fprintf(stderr,
   3.159 -            "WARNING: You are using the SDL disk writer audio driver!\n"
   3.160 -            " Writing to file [%s].\n", fname);
   3.161 +            "WARNING: You are using the SDL disk i/o audio driver!\n"
   3.162 +            " %s file [%s].\n", iscapture ? "Reading from" : "Writing to",
   3.163 +            fname);
   3.164  #endif
   3.165  
   3.166      /* We're ready to rock and roll. :-) */
   3.167 @@ -137,8 +171,8 @@
   3.168  static void
   3.169  DISKAUD_DetectDevices(void)
   3.170  {
   3.171 -    /* !!! FIXME: stole this literal string from DEFAULT_OUTPUT_DEVNAME in SDL_audio.c */
   3.172 -    SDL_AddAudioDevice(SDL_FALSE, "System audio output device", (void *) 0x1);
   3.173 +    SDL_AddAudioDevice(SDL_FALSE, DEFAULT_OUTPUT_DEVNAME, (void *) 0x1);
   3.174 +    SDL_AddAudioDevice(SDL_TRUE, DEFAULT_INPUT_DEVNAME, (void *) 0x2);
   3.175  }
   3.176  
   3.177  static int
   3.178 @@ -149,10 +183,14 @@
   3.179      impl->WaitDevice = DISKAUD_WaitDevice;
   3.180      impl->PlayDevice = DISKAUD_PlayDevice;
   3.181      impl->GetDeviceBuf = DISKAUD_GetDeviceBuf;
   3.182 +    impl->CaptureFromDevice = DISKAUD_CaptureFromDevice;
   3.183 +    impl->FlushCapture = DISKAUD_FlushCapture;
   3.184 +
   3.185      impl->CloseDevice = DISKAUD_CloseDevice;
   3.186      impl->DetectDevices = DISKAUD_DetectDevices;
   3.187  
   3.188      impl->AllowsArbitraryDeviceNames = 1;
   3.189 +    impl->HasCaptureSupport = SDL_TRUE;
   3.190  
   3.191      return 1;   /* this audio target is available. */
   3.192  }
     4.1 --- a/src/audio/disk/SDL_diskaudio.h	Sat Aug 06 02:48:00 2016 -0400
     4.2 +++ b/src/audio/disk/SDL_diskaudio.h	Sat Aug 06 03:39:15 2016 -0400
     4.3 @@ -32,10 +32,9 @@
     4.4  struct SDL_PrivateAudioData
     4.5  {
     4.6      /* The file descriptor for the audio device */
     4.7 -    SDL_RWops *output;
     4.8 +    SDL_RWops *io;
     4.9 +    Uint32 io_delay;
    4.10      Uint8 *mixbuf;
    4.11 -    Uint32 mixlen;
    4.12 -    Uint32 write_delay;
    4.13  };
    4.14  
    4.15  #endif /* _SDL_diskaudio_h */