#include #include #include #include "audio.h" #include "audio_internal.h" typedef struct _SinkLibaoContext { ao_device *device; ao_sample_format format; } SinkLibaoContext; AudioPipelineStatus sink_libao_push(AudioPipelineElement *self, AudioBuffer *buffer) { SinkLibaoContext *context = (SinkLibaoContext *)self->ctx; if (context->device == NULL) { int default_driver = ao_default_driver_id(); context->device = ao_open_live(default_driver, &context->format, NULL); if (context->device == NULL) { fprintf(stderr, "Error opening device.\n"); return PipelineError; } } int result = ao_play(context->device, (char *)buffer->data, buffer->buf_size); return (result == 0) ? PipelineError : PipelineRunning; } AudioPipelineStatus sink_libao_link(AudioPipelineElement *self, AudioPipelineElement *source) { SinkLibaoContext *context = (SinkLibaoContext *)self->ctx; if (context->device != NULL) { ao_close(context->device); context->device = NULL; } memset(&context->format, 0, sizeof(ao_sample_format)); context->format.bits = source->bits_per_sample; context->format.channels = source->channels; context->format.rate = source->sample_rate; context->format.byte_format = AO_FMT_LITTLE; source->next = self; return PipelineStopped; } char *sink_libao_describe(AudioPipelineElement *self) { return "libao sink"; } void sink_libao_destroy(AudioPipelineElement *self) { SinkLibaoContext *context = (SinkLibaoContext *)self->ctx; ao_close(context->device); ao_shutdown(); free(self->ctx); free(self); } AudioPipelineElement *audio_sink_libao(void) { AudioPipelineElement *self = calloc(1, sizeof(AudioPipelineElement)); SinkLibaoContext *context = calloc(1, sizeof(SinkLibaoContext)); ao_initialize(); self->ctx = context; self->describe = sink_libao_describe; self->start = sink_nop; self->reset = sink_nop; self->stop = sink_nop; self->push = sink_libao_push; self->link = sink_libao_link; self->destroy = sink_libao_destroy; self->type = AudioElementSink; return self; }