#include #include #include #include static xas_audio_stream *stream_new(enum xas_audio_stream_type type, void *callback, xas_audio_cleanup cleanup, void *ctx, size_t sample_size, size_t sample_rate, size_t channels, size_t buffer_size) { xas_audio_stream *stream; size_t total = sizeof(xas_audio_stream) + sample_size * channels * buffer_size; if ((stream = malloc(total)) == NULL) { goto error_malloc_stream; } stream->type = type; stream->sample_size = sample_size; stream->sample_rate = sample_rate; stream->channels = channels; stream->buffer_size = buffer_size; stream->buffer_count = 0; stream->callback = callback; stream->cleanup = cleanup; stream->ctx = ctx; return stream; error_malloc_stream: return NULL; } xas_audio_stream *xas_audio_stream_new_sink(xas_audio_drain drain, xas_audio_cleanup cleanup, void *ctx, size_t sample_size, size_t sample_rate, size_t channels, size_t buffer_size) { return stream_new(XAS_AUDIO_STREAM_SINK, drain, cleanup, ctx, sample_size, sample_rate, channels, buffer_size); } xas_audio_stream *xas_audio_stream_new_source(xas_audio_fill fill, xas_audio_cleanup cleanup, void *ctx, size_t sample_size, size_t sample_rate, size_t channels, size_t buffer_size) { return stream_new(XAS_AUDIO_STREAM_SOURCE, fill, cleanup, ctx, sample_size, sample_rate, channels, buffer_size); } void xas_audio_stream_destroy(xas_audio_stream *stream) { if (stream->cleanup) { stream->cleanup(stream->ctx, stream); } free(stream); } static inline int stream_flush(xas_audio_stream *stream) { if (stream->buffer_count == 0) { return 0; } if (stream->drain(stream->ctx, stream + 1, stream->buffer_count, stream) < 0) { goto error_stream_drain; } stream->buffer_count = 0; return 0; error_stream_drain: return -1; } static inline void *ptr(xas_audio_stream *stream, void *buf, size_t index) { return ((uint8_t *)buf) + stream->sample_size * stream->channels * index; } ssize_t xas_audio_stream_write(xas_audio_stream *stream, void *samples, size_t count) { size_t left = count, index = 0; if (stream->buffer_count > 0) { size_t remainder = stream->buffer_size - stream->buffer_count; memcpy(ptr(stream, stream + 1, stream->buffer_count), ptr(stream, samples, 0), stream->sample_size * stream->channels * remainder); 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), stream->buffer_size, stream) < 0) { goto error_stream_drain; } left -= stream->buffer_size; index += stream->buffer_size; } memcpy(ptr(stream, stream + 1, 0), ptr(stream, samples, index), stream->sample_size * stream->channels * left); stream->buffer_count = left; index += left; return index; error_stream_drain: error_stream_flush: return -1; } ssize_t xas_audio_stream_read(xas_audio_stream *stream, void **samples, size_t count) { *samples = stream + 1; return stream->fill(stream->ctx, *samples, count, stream); } int xas_audio_stream_flush(xas_audio_stream *stream) { if (stream->type == XAS_AUDIO_STREAM_SINK) { return stream_flush(stream); } errno = EINVAL; return -1; }