#include #include #include #include #include int xas_audio_format_eq(xas_audio_format a, xas_audio_format b) { return a.channels == b.channels && a.sample_size == b.sample_size && a.sample_rate == b.sample_rate; } void xas_audio_zero(xas_audio_format format, void *dest, size_t index, size_t count) { size_t stride = format.channels * format.sample_size; memset((uint8_t *)dest + stride * index, '\0', stride * count); } void xas_audio_copy(xas_audio_format format, void *dest, void *src, size_t index_dest, size_t index_src, size_t count) { size_t stride = format.channels * format.sample_size; memcpy(((uint8_t *)dest) + stride * index_dest, ((uint8_t *)src) + stride * index_src, stride * count); } static inline void apply_gain_mono(int16_t *samples, float gain, size_t index, size_t count) { size_t i; for (i=index; itype = type; stream->format.channels = format.channels; stream->format.sample_size = format.sample_size; stream->format.sample_rate = format.sample_rate; 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, xas_audio_format format, size_t buffer_size, void *ctx) { return stream_new(XAS_AUDIO_STREAM_SINK, drain, cleanup, format, buffer_size, ctx); } xas_audio_stream *xas_audio_stream_new_source(xas_audio_fill fill, xas_audio_cleanup cleanup, xas_audio_format format, size_t buffer_size, void *ctx) { return stream_new(XAS_AUDIO_STREAM_SOURCE, fill, cleanup, format, buffer_size, ctx); } void xas_audio_stream_destroy(xas_audio_stream *stream) { if (stream->cleanup) { stream->cleanup(stream->ctx, stream); } free(stream); } void *xas_audio_stream_buffer(xas_audio_stream *stream) { return stream + 1; } static inline int stream_flush(xas_audio_stream *sink) { if (sink->buffer_count == 0) { return 0; } if (sink->drain(sink->ctx, sink + 1, sink->buffer_count, sink) < 0) { goto error_sink_drain; } sink->buffer_count = 0; return 0; error_sink_drain: return -1; } static inline void *ptr(xas_audio_stream *stream, void *buf, size_t index) { return ((uint8_t *)buf) + stream->format.channels * stream->format.sample_size * index; } ssize_t xas_audio_stream_write(xas_audio_stream *sink, void *samples, size_t count) { size_t index_i = 0; if (sink->buffer_count + count > sink->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 = sink->buffer_size - sink->buffer_count; xas_audio_copy(sink->format, sink+ 1, samples, sink->buffer_count, index_i, remaining); if (sink->drain(sink->ctx, sink + 1, sink->buffer_size, sink) < 0) { goto error_sink_drain; } index_i += remaining; sink->buffer_count = 0; } /* * While there are still samples to buffer or flush... */ while (index_i < count) { size_t remaining = count - index_i; if (remaining >= sink->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 (sink->drain(sink->ctx, ptr(sink, samples, index_i), sink->buffer_size, sink) < 0) { goto error_sink_drain; } index_i += sink->buffer_size; } else { /* * Enough of the input has been drained that it can be copied to * the target buffer. */ xas_audio_copy(sink->format, sink + 1, samples, sink->buffer_count, index_i, remaining); index_i += remaining; sink->buffer_count += remaining; } } return index_i; error_sink_drain: return -1; } int xas_audio_stream_flush(xas_audio_stream *sink) { if (sink->type == XAS_AUDIO_STREAM_SINK) { return stream_flush(sink); } errno = EINVAL; return -1; } ssize_t xas_audio_stream_read(xas_audio_stream *source, void **samples, size_t count) { *samples = source + 1; if (count > source->buffer_size) { count = source->buffer_size; } return source->fill(source->ctx, *samples, count, source); }