diff options
-rw-r--r-- | src/audio.c | 78 |
1 files changed, 49 insertions, 29 deletions
diff --git a/src/audio.c b/src/audio.c index 8853164..10f7a34 100644 --- a/src/audio.c +++ b/src/audio.c @@ -106,50 +106,70 @@ static inline void *ptr(xas_audio_stream *stream, void *buf, size_t index) { ssize_t xas_audio_stream_write(xas_audio_stream *stream, void *samples, size_t count) { - size_t left = count, - index = 0; + size_t index_i = 0; - if (stream->buffer_count > 0) { - size_t remainder = stream->buffer_size - stream->buffer_count; + if (stream->buffer_count + count > stream->buffer_size) { + /* + * If the number of samples offered, plus the number of items currently + * in the buffer exceeds the buffer size, fill the buffer to capacity + * and flush it. + */ + size_t remaining = stream->buffer_size - stream->buffer_count; memcpy(ptr(stream, stream + 1, stream->buffer_count), - ptr(stream, samples, 0), - stream->sample_size * stream->channels * remainder); + ptr(stream, samples, index_i), + remaining * stream->sample_size * stream->channels); - stream->buffer_count += remainder; - - if (stream_flush(stream) < 0) { - goto error_stream_flush; - } - - left -= remainder; - index += remainder; - } - - while (left > stream->buffer_size) { if (stream->drain(stream->ctx, - ptr(stream, samples, index), + ptr(stream, stream + 1, 0), stream->buffer_size, stream) < 0) { goto error_stream_drain; } - left -= stream->buffer_size; - index += stream->buffer_size; - } + index_i += remaining; - memcpy(ptr(stream, stream + 1, 0), - ptr(stream, samples, index), - stream->sample_size * stream->channels * left); - - stream->buffer_count = left; + stream->buffer_count = 0; + } - index += left; + /* + * While there are still samples to buffer or flush... + */ + while (index_i < count) { + size_t remaining = count - index_i; + + if (remaining >= stream->buffer_size) { + /* + * If the number of samples remaining is greater than the target + * buffer size, then drain directly from the source buffer to the + * output an amount equal to the buffer size. + */ + if (stream->drain(stream->ctx, + ptr(stream, samples, index_i), + stream->buffer_size, + stream) < 0) { + goto error_stream_drain; + } + + index_i += stream->buffer_size; + } else { + /* + * Enough of the input has been drained that it can be copied to + * the target buffer. + */ + memcpy(ptr(stream, stream + 1, stream->buffer_count), + ptr(stream, samples, index_i), + remaining * stream->sample_size * stream->channels); + + index_i += remaining; + + stream->buffer_count += remaining; + } + } - return index; + return 0; error_stream_drain: -error_stream_flush: return -1; } |