michael@0: /* michael@0: * Copyright © 2013 Mozilla Foundation michael@0: * michael@0: * This program is made available under an ISC-style license. See the michael@0: * accompanying file LICENSE for details. michael@0: */ michael@0: #include michael@0: #if defined(HAVE_CONFIG_H) michael@0: #include "config.h" michael@0: #endif michael@0: #include "cubeb/cubeb.h" michael@0: #include "cubeb-internal.h" michael@0: michael@0: #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0]))) michael@0: michael@0: struct cubeb { michael@0: struct cubeb_ops * ops; michael@0: }; michael@0: michael@0: struct cubeb_stream { michael@0: struct cubeb * context; michael@0: }; michael@0: michael@0: #if defined(USE_PULSE) michael@0: int pulse_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_JACK) michael@0: int jack_init (cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_ALSA) michael@0: int alsa_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_AUDIOQUEUE) michael@0: int audioqueue_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_AUDIOUNIT) michael@0: int audiounit_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_DIRECTSOUND) michael@0: int directsound_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_WINMM) michael@0: int winmm_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_WASAPI) michael@0: int wasapi_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_SNDIO) michael@0: int sndio_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_OPENSL) michael@0: int opensl_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: #if defined(USE_AUDIOTRACK) michael@0: int audiotrack_init(cubeb ** context, char const * context_name); michael@0: #endif michael@0: michael@0: int michael@0: validate_stream_params(cubeb_stream_params stream_params) michael@0: { michael@0: if (stream_params.rate < 1000 || stream_params.rate > 192000 || michael@0: stream_params.channels < 1 || stream_params.channels > 8) { michael@0: return CUBEB_ERROR_INVALID_FORMAT; michael@0: } michael@0: michael@0: switch (stream_params.format) { michael@0: case CUBEB_SAMPLE_S16LE: michael@0: case CUBEB_SAMPLE_S16BE: michael@0: case CUBEB_SAMPLE_FLOAT32LE: michael@0: case CUBEB_SAMPLE_FLOAT32BE: michael@0: return CUBEB_OK; michael@0: } michael@0: michael@0: return CUBEB_ERROR_INVALID_FORMAT; michael@0: } michael@0: michael@0: int michael@0: validate_latency(int latency) michael@0: { michael@0: if (latency < 1 || latency > 2000) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: return CUBEB_OK; michael@0: } michael@0: michael@0: int michael@0: cubeb_init(cubeb ** context, char const * context_name) michael@0: { michael@0: int (* init[])(cubeb **, char const *) = { michael@0: #if defined(USE_PULSE) michael@0: pulse_init, michael@0: #endif michael@0: #if defined(USE_JACK) michael@0: jack_init, michael@0: #endif michael@0: #if defined(USE_ALSA) michael@0: alsa_init, michael@0: #endif michael@0: #if defined(USE_AUDIOUNIT) michael@0: audiounit_init, michael@0: #endif michael@0: #if defined(USE_AUDIOQUEUE) michael@0: audioqueue_init, michael@0: #endif michael@0: #if defined(USE_WASAPI) michael@0: wasapi_init, michael@0: #endif michael@0: #if defined(USE_WINMM) michael@0: winmm_init, michael@0: #endif michael@0: #if defined(USE_DIRECTSOUND) michael@0: directsound_init, michael@0: #endif michael@0: #if defined(USE_SNDIO) michael@0: sndio_init, michael@0: #endif michael@0: #if defined(USE_OPENSL) michael@0: opensl_init, michael@0: #endif michael@0: #if defined(USE_AUDIOTRACK) michael@0: audiotrack_init, michael@0: #endif michael@0: }; michael@0: int i; michael@0: michael@0: if (!context) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: for (i = 0; i < NELEMS(init); ++i) { michael@0: if (init[i](context, context_name) == CUBEB_OK) { michael@0: return CUBEB_OK; michael@0: } michael@0: } michael@0: michael@0: return CUBEB_ERROR; michael@0: } michael@0: michael@0: char const * michael@0: cubeb_get_backend_id(cubeb * context) michael@0: { michael@0: if (!context) { michael@0: return NULL; michael@0: } michael@0: michael@0: return context->ops->get_backend_id(context); michael@0: } michael@0: michael@0: int michael@0: cubeb_get_max_channel_count(cubeb * context, uint32_t * max_channels) michael@0: { michael@0: if (!context || !max_channels) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: return context->ops->get_max_channel_count(context, max_channels); michael@0: } michael@0: michael@0: int michael@0: cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, uint32_t * latency_ms) michael@0: { michael@0: if (!context || !latency_ms) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: return context->ops->get_min_latency(context, params, latency_ms); michael@0: } michael@0: michael@0: int michael@0: cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate) michael@0: { michael@0: if (!context || !rate) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: return context->ops->get_preferred_sample_rate(context, rate); michael@0: } michael@0: michael@0: void michael@0: cubeb_destroy(cubeb * context) michael@0: { michael@0: if (!context) { michael@0: return; michael@0: } michael@0: michael@0: context->ops->destroy(context); michael@0: } michael@0: michael@0: int michael@0: cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name, michael@0: cubeb_stream_params stream_params, unsigned int latency, michael@0: cubeb_data_callback data_callback, michael@0: cubeb_state_callback state_callback, michael@0: void * user_ptr) michael@0: { michael@0: int r; michael@0: michael@0: if (!context || !stream) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: if ((r = validate_stream_params(stream_params)) != CUBEB_OK || michael@0: (r = validate_latency(latency)) != CUBEB_OK) { michael@0: return r; michael@0: } michael@0: michael@0: return context->ops->stream_init(context, stream, stream_name, michael@0: stream_params, latency, michael@0: data_callback, michael@0: state_callback, michael@0: user_ptr); michael@0: } michael@0: michael@0: void michael@0: cubeb_stream_destroy(cubeb_stream * stream) michael@0: { michael@0: if (!stream) { michael@0: return; michael@0: } michael@0: michael@0: stream->context->ops->stream_destroy(stream); michael@0: } michael@0: michael@0: int michael@0: cubeb_stream_start(cubeb_stream * stream) michael@0: { michael@0: if (!stream) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: return stream->context->ops->stream_start(stream); michael@0: } michael@0: michael@0: int michael@0: cubeb_stream_stop(cubeb_stream * stream) michael@0: { michael@0: if (!stream) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: return stream->context->ops->stream_stop(stream); michael@0: } michael@0: michael@0: int michael@0: cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position) michael@0: { michael@0: if (!stream || !position) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: return stream->context->ops->stream_get_position(stream, position); michael@0: } michael@0: michael@0: int michael@0: cubeb_stream_get_latency(cubeb_stream * stream, uint32_t * latency) michael@0: { michael@0: if (!stream || !latency) { michael@0: return CUBEB_ERROR_INVALID_PARAMETER; michael@0: } michael@0: michael@0: return stream->context->ops->stream_get_latency(stream, latency); michael@0: }