Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
audio: Added SDL_AudioStreamFlush().
  • Loading branch information
icculus committed Oct 19, 2017
1 parent 9d9be45 commit 7293290
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 4 deletions.
22 changes: 21 additions & 1 deletion include/SDL_audio.h
Expand Up @@ -545,16 +545,36 @@ extern DECLSPEC int SDLCALL SDL_AudioStreamPut(SDL_AudioStream *stream, const vo
extern DECLSPEC int SDLCALL SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len);

/**
* Get the number of converted/resampled bytes available
* Get the number of converted/resampled bytes available. The stream may be
* buffering data behind the scenes until it has enough to resample
* correctly, so this number might be lower than what you expect, or even
* be zero. Add more data or flush the stream if you need the data now.
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamClear
* \sa SDL_AudioStreamFlush
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamAvailable(SDL_AudioStream *stream);

/**
* Tell the stream that you're done sending data, and anything being buffered
* should be converted/resampled and made available immediately.
*
* It is legal to add more data to a stream after flushing, but there will
* be audio gaps in the output. Generally this is intended to signal the
* end of input, so the complete output becomes available.
*
* \sa SDL_NewAudioStream
* \sa SDL_AudioStreamPut
* \sa SDL_AudioStreamGet
* \sa SDL_AudioStreamClear
* \sa SDL_FreeAudioStream
*/
extern DECLSPEC int SDLCALL SDL_AudioStreamFlush(SDL_AudioStream *stream);

/**
* Clear any pending data in the stream without converting it
*
Expand Down
66 changes: 63 additions & 3 deletions src/audio/SDL_audiocvt.c
Expand Up @@ -1362,7 +1362,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
}

static int
SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len)
SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
{
int buflen = len;
int workbuflen;
Expand Down Expand Up @@ -1479,6 +1479,13 @@ SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len)
printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
#endif

if (maxputbytes) {
const int maxbytes = *maxputbytes;
if (buflen > maxbytes)
buflen = maxbytes;
*maxputbytes -= buflen;
}

/* resamplebuf holds the final output, even if we didn't resample. */
return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
}
Expand Down Expand Up @@ -1524,7 +1531,7 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
we don't need to store it for later, skip the staging process.
*/
if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
return SDL_AudioStreamPutInternal(stream, buf, len);
return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
}

/* If there's not enough data to fill the staging buffer, just save it */
Expand All @@ -1539,7 +1546,7 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
SDL_assert(amount > 0);
SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
stream->staging_buffer_filled = 0;
if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size) < 0) {
if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
return -1;
}
buf = (void *)((Uint8 *)buf + amount);
Expand All @@ -1548,6 +1555,58 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
return 0;
}

int SDL_AudioStreamFlush(SDL_AudioStream *stream)
{
if (!stream) {
return SDL_InvalidParamError("stream");
}

#if DEBUG_AUDIOSTREAM
printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
#endif

/* shouldn't use a staging buffer if we're not resampling. */
SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));

if (stream->staging_buffer_filled > 0) {
/* push the staging buffer + silence. We need to flush out not just
the staging buffer, but the piece that the stream was saving off
for right-side resampler padding. */
const SDL_bool first_run = stream->first_run;
const int filled = stream->staging_buffer_filled;
int actual_input_frames = filled / stream->src_sample_frame_size;
if (!first_run)
actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;

if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
/* This is how many bytes we're expecting without silence appended. */
int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;

#if DEBUG_AUDIOSTREAM
printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
#endif

SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
return -1;
}

/* we have flushed out (or initially filled) the pending right-side
resampler padding, but we need to push more silence to guarantee
the staging buffer is fully flushed out, too. */
SDL_memset(stream->staging_buffer, '\0', filled);
if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
return -1;
}
}
}

stream->staging_buffer_filled = 0;
stream->first_run = SDL_TRUE;

return 0;
}

/* get converted/resampled data from the stream */
int
SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
Expand Down Expand Up @@ -1587,6 +1646,7 @@ SDL_AudioStreamClear(SDL_AudioStream *stream)
stream->reset_resampler_func(stream);
}
stream->first_run = SDL_TRUE;
stream->staging_buffer_filled = 0;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_overrides.h
Expand Up @@ -646,3 +646,4 @@
#define SDL_AudioStreamClear SDL_AudioStreamClear_REAL
#define SDL_AudioStreamAvailable SDL_AudioStreamAvailable_REAL
#define SDL_FreeAudioStream SDL_FreeAudioStream_REAL
#define SDL_AudioStreamFlush SDL_AudioStreamFlush_REAL
1 change: 1 addition & 0 deletions src/dynapi/SDL_dynapi_procs.h
Expand Up @@ -680,3 +680,4 @@ SDL_DYNAPI_PROC(int,SDL_AudioStreamGet,(SDL_AudioStream *a, void *b, int c),(a,b
SDL_DYNAPI_PROC(void,SDL_AudioStreamClear,(SDL_AudioStream *a),(a),)
SDL_DYNAPI_PROC(int,SDL_AudioStreamAvailable,(SDL_AudioStream *a),(a),return)
SDL_DYNAPI_PROC(void,SDL_FreeAudioStream,(SDL_AudioStream *a),(a),)
SDL_DYNAPI_PROC(int,SDL_AudioStreamFlush,(SDL_AudioStream *a),(a),return)

0 comments on commit 7293290

Please sign in to comment.