audio: Added SDL_AudioStreamFlush().
authorRyan C. Gordon <icculus@icculus.org>
Thu, 19 Oct 2017 18:05:42 -0400
changeset 11636ec1c9bded2d0
parent 11635 4a94743e31fe
child 11637 a970b2ae1bd7
audio: Added SDL_AudioStreamFlush().
include/SDL_audio.h
src/audio/SDL_audiocvt.c
src/dynapi/SDL_dynapi_overrides.h
src/dynapi/SDL_dynapi_procs.h
     1.1 --- a/include/SDL_audio.h	Thu Oct 19 13:54:56 2017 -0700
     1.2 +++ b/include/SDL_audio.h	Thu Oct 19 18:05:42 2017 -0400
     1.3 @@ -545,7 +545,27 @@
     1.4  extern DECLSPEC int SDLCALL SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len);
     1.5  
     1.6  /**
     1.7 - * Get the number of converted/resampled bytes available
     1.8 + * Get the number of converted/resampled bytes available. The stream may be
     1.9 + *  buffering data behind the scenes until it has enough to resample
    1.10 + *  correctly, so this number might be lower than what you expect, or even
    1.11 + *  be zero. Add more data or flush the stream if you need the data now.
    1.12 + *
    1.13 + *  \sa SDL_NewAudioStream
    1.14 + *  \sa SDL_AudioStreamPut
    1.15 + *  \sa SDL_AudioStreamGet
    1.16 + *  \sa SDL_AudioStreamClear
    1.17 + *  \sa SDL_AudioStreamFlush
    1.18 + *  \sa SDL_FreeAudioStream
    1.19 + */
    1.20 +extern DECLSPEC int SDLCALL SDL_AudioStreamAvailable(SDL_AudioStream *stream);
    1.21 +
    1.22 +/**
    1.23 + * Tell the stream that you're done sending data, and anything being buffered
    1.24 + *  should be converted/resampled and made available immediately.
    1.25 + *
    1.26 + * It is legal to add more data to a stream after flushing, but there will
    1.27 + *  be audio gaps in the output. Generally this is intended to signal the
    1.28 + *  end of input, so the complete output becomes available.
    1.29   *
    1.30   *  \sa SDL_NewAudioStream
    1.31   *  \sa SDL_AudioStreamPut
    1.32 @@ -553,7 +573,7 @@
    1.33   *  \sa SDL_AudioStreamClear
    1.34   *  \sa SDL_FreeAudioStream
    1.35   */
    1.36 -extern DECLSPEC int SDLCALL SDL_AudioStreamAvailable(SDL_AudioStream *stream);
    1.37 +extern DECLSPEC int SDLCALL SDL_AudioStreamFlush(SDL_AudioStream *stream);
    1.38  
    1.39  /**
    1.40   *  Clear any pending data in the stream without converting it
     2.1 --- a/src/audio/SDL_audiocvt.c	Thu Oct 19 13:54:56 2017 -0700
     2.2 +++ b/src/audio/SDL_audiocvt.c	Thu Oct 19 18:05:42 2017 -0400
     2.3 @@ -1362,7 +1362,7 @@
     2.4  }
     2.5  
     2.6  static int
     2.7 -SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len)
     2.8 +SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
     2.9  {
    2.10      int buflen = len;
    2.11      int workbuflen;
    2.12 @@ -1479,6 +1479,13 @@
    2.13      printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
    2.14      #endif
    2.15  
    2.16 +    if (maxputbytes) {
    2.17 +        const int maxbytes = *maxputbytes;
    2.18 +        if (buflen > maxbytes)
    2.19 +            buflen = maxbytes;
    2.20 +        *maxputbytes -= buflen;
    2.21 +    }
    2.22 +
    2.23      /* resamplebuf holds the final output, even if we didn't resample. */
    2.24      return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
    2.25  }
    2.26 @@ -1524,7 +1531,7 @@
    2.27             we don't need to store it for later, skip the staging process.
    2.28           */
    2.29          if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
    2.30 -            return SDL_AudioStreamPutInternal(stream, buf, len);
    2.31 +            return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
    2.32          }
    2.33  
    2.34          /* If there's not enough data to fill the staging buffer, just save it */
    2.35 @@ -1539,7 +1546,7 @@
    2.36          SDL_assert(amount > 0);
    2.37          SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
    2.38          stream->staging_buffer_filled = 0;
    2.39 -        if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size) < 0) {
    2.40 +        if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
    2.41              return -1;
    2.42          }
    2.43          buf = (void *)((Uint8 *)buf + amount);
    2.44 @@ -1548,6 +1555,58 @@
    2.45      return 0;
    2.46  }
    2.47  
    2.48 +int SDL_AudioStreamFlush(SDL_AudioStream *stream)
    2.49 +{
    2.50 +    if (!stream) {
    2.51 +        return SDL_InvalidParamError("stream");
    2.52 +    }
    2.53 +
    2.54 +    #if DEBUG_AUDIOSTREAM
    2.55 +    printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
    2.56 +    #endif
    2.57 +
    2.58 +    /* shouldn't use a staging buffer if we're not resampling. */
    2.59 +    SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
    2.60 +
    2.61 +    if (stream->staging_buffer_filled > 0) {
    2.62 +        /* push the staging buffer + silence. We need to flush out not just
    2.63 +           the staging buffer, but the piece that the stream was saving off
    2.64 +           for right-side resampler padding. */
    2.65 +        const SDL_bool first_run = stream->first_run;
    2.66 +        const int filled = stream->staging_buffer_filled;
    2.67 +        int actual_input_frames = filled / stream->src_sample_frame_size;
    2.68 +        if (!first_run)
    2.69 +            actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
    2.70 +
    2.71 +        if (actual_input_frames > 0) {  /* don't bother if nothing to flush. */
    2.72 +            /* This is how many bytes we're expecting without silence appended. */
    2.73 +            int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
    2.74 +
    2.75 +            #if DEBUG_AUDIOSTREAM
    2.76 +            printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
    2.77 +            #endif
    2.78 +
    2.79 +            SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
    2.80 +            if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
    2.81 +                return -1;
    2.82 +            }
    2.83 +
    2.84 +            /* we have flushed out (or initially filled) the pending right-side
    2.85 +               resampler padding, but we need to push more silence to guarantee
    2.86 +               the staging buffer is fully flushed out, too. */
    2.87 +            SDL_memset(stream->staging_buffer, '\0', filled);
    2.88 +            if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
    2.89 +                return -1;
    2.90 +            }
    2.91 +        }
    2.92 +    }
    2.93 +
    2.94 +    stream->staging_buffer_filled = 0;
    2.95 +    stream->first_run = SDL_TRUE;
    2.96 +
    2.97 +    return 0;
    2.98 +}
    2.99 +
   2.100  /* get converted/resampled data from the stream */
   2.101  int
   2.102  SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
   2.103 @@ -1587,6 +1646,7 @@
   2.104              stream->reset_resampler_func(stream);
   2.105          }
   2.106          stream->first_run = SDL_TRUE;
   2.107 +        stream->staging_buffer_filled = 0;
   2.108      }
   2.109  }
   2.110  
     3.1 --- a/src/dynapi/SDL_dynapi_overrides.h	Thu Oct 19 13:54:56 2017 -0700
     3.2 +++ b/src/dynapi/SDL_dynapi_overrides.h	Thu Oct 19 18:05:42 2017 -0400
     3.3 @@ -646,3 +646,4 @@
     3.4  #define SDL_AudioStreamClear SDL_AudioStreamClear_REAL
     3.5  #define SDL_AudioStreamAvailable SDL_AudioStreamAvailable_REAL
     3.6  #define SDL_FreeAudioStream SDL_FreeAudioStream_REAL
     3.7 +#define SDL_AudioStreamFlush SDL_AudioStreamFlush_REAL
     4.1 --- a/src/dynapi/SDL_dynapi_procs.h	Thu Oct 19 13:54:56 2017 -0700
     4.2 +++ b/src/dynapi/SDL_dynapi_procs.h	Thu Oct 19 18:05:42 2017 -0400
     4.3 @@ -680,3 +680,4 @@
     4.4  SDL_DYNAPI_PROC(void,SDL_AudioStreamClear,(SDL_AudioStream *a),(a),)
     4.5  SDL_DYNAPI_PROC(int,SDL_AudioStreamAvailable,(SDL_AudioStream *a),(a),return)
     4.6  SDL_DYNAPI_PROC(void,SDL_FreeAudioStream,(SDL_AudioStream *a),(a),)
     4.7 +SDL_DYNAPI_PROC(int,SDL_AudioStreamFlush,(SDL_AudioStream *a),(a),return)