diff --git a/configure.in b/configure.in index e13437fd574f..21c264afee11 100644 --- a/configure.in +++ b/configure.in @@ -5657,10 +5657,7 @@ fi if test -n "$MOZ_CUBEB"; then case "$target" in *-android*|*-linuxandroid*) - if test -n "$gonkdir"; then - AC_DEFINE(MOZ_CUBEB) - fi - dnl No Android implementation of libcubeb yet. + AC_DEFINE(MOZ_CUBEB) ;; *-linux*) AC_DEFINE(MOZ_CUBEB) diff --git a/media/libcubeb/AUTHORS b/media/libcubeb/AUTHORS index 74d9c7d8127a..d98205cb4d97 100644 --- a/media/libcubeb/AUTHORS +++ b/media/libcubeb/AUTHORS @@ -1,3 +1,4 @@ Matthew Gregan Alexandre Ratchov Michael Wu +Paul Adenot diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA index 7232df158623..bed89182d1d8 100644 --- a/media/libcubeb/README_MOZILLA +++ b/media/libcubeb/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The cubeb git repository is: git://github.com/kinetiknz/cubeb.git -The git commit ID used was f2d524c34b6f75d85053034c3075c2ff08383769. +The git commit ID used was 0c7d97523096a7d4ae363974393d06f77c4592c9. diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h index 4494a6eb304b..bc398e0d1b98 100644 --- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -4,12 +4,12 @@ * This program is made available under an ISC-style license. See the * accompanying file LICENSE for details. */ -#ifndef CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 -#define CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 +#if !defined(CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382) +#define CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 #include -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif @@ -226,7 +226,7 @@ int cubeb_stream_stop(cubeb_stream * stream); @retval CUBEB_ERROR */ int cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position); -#ifdef __cplusplus +#if defined(__cplusplus) } #endif diff --git a/media/libcubeb/src/Makefile.in b/media/libcubeb/src/Makefile.in index 5b06a460026c..9d6d2366220e 100644 --- a/media/libcubeb/src/Makefile.in +++ b/media/libcubeb/src/Makefile.in @@ -28,14 +28,17 @@ DEFINES += -DUSE_WINMM endif ifeq ($(OS_TARGET),Android) -ifeq ($(MOZ_WIDGET_TOOLKIT),gonk) +ifneq ($(MOZ_WIDGET_TOOLKIT),gonk) +CSRCS += \ + cubeb_audiotrack.c \ + $(NULL) +DEFINES += -DUSE_AUDIOTRACK +endif CSRCS += \ cubeb_opensl.c \ $(NULL) DEFINES += -DUSE_OPENSL endif -# No Android implementation of libcubeb yet. -endif ifeq ($(OS_TARGET),Darwin) CSRCS += \ diff --git a/media/libcubeb/src/android/audiotrack_definitions.h b/media/libcubeb/src/android/audiotrack_definitions.h new file mode 100644 index 000000000000..da3032d4084c --- /dev/null +++ b/media/libcubeb/src/android/audiotrack_definitions.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +/* + * The following definitions are copied from the android sources. Only the + * relevant enum member and values needed are copied. + */ + +/* + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/utils/Errors.h + */ +typedef int32_t status_t; + +/* + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/media/AudioTrack.h + */ +struct Buffer { + uint32_t flags; + int channelCount; + int format; + size_t frameCount; + size_t size; + union { + void* raw; + short* i16; + int8_t* i8; + }; +}; + +enum event_type { + EVENT_MORE_DATA = 0, + EVENT_UNDERRUN = 1, + EVENT_LOOP_END = 2, + EVENT_MARKER = 3, + EVENT_NEW_POS = 4, + EVENT_BUFFER_END = 5 +}; + +/** + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/media/AudioSystem.h + * and + * https://android.googlesource.com/platform/system/core/+/android-4.2.2_r1/include/system/audio.h + */ + +#define AUDIO_STREAM_TYPE_MUSIC 3 + +enum { + AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS = 0x1, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_ICS = 0x2, + AUDIO_CHANNEL_OUT_MONO_ICS = AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS, + AUDIO_CHANNEL_OUT_STEREO_ICS = (AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS | AUDIO_CHANNEL_OUT_FRONT_RIGHT_ICS) +} AudioTrack_ChannelMapping_ICS; + +enum { + AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo = 0x4, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_Froyo = 0x8, + AUDIO_CHANNEL_OUT_MONO_Froyo = AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo, + AUDIO_CHANNEL_OUT_STEREO_Froyo = (AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo | AUDIO_CHANNEL_OUT_FRONT_RIGHT_Froyo) +} AudioTrack_ChannelMapping_Froyo; + +typedef enum { + AUDIO_FORMAT_PCM = 0x00000000, + AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, + AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_16_BIT), +} AudioTrack_SampleType; + diff --git a/media/libcubeb/src/android/sles_definitions.h b/media/libcubeb/src/android/sles_definitions.h new file mode 100644 index 000000000000..f5670c131c2e --- /dev/null +++ b/media/libcubeb/src/android/sles_definitions.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This file is similar to the file "OpenSLES_AndroidConfiguration.h" found in + * the Android NDK, but removes the #ifdef __cplusplus defines, so we can keep + * using a C compiler in cubeb. + */ + +#ifndef OPENSL_ES_ANDROIDCONFIGURATION_H_ +#define OPENSL_ES_ANDROIDCONFIGURATION_H_ + +/*---------------------------------------------------------------------------*/ +/* Android AudioRecorder configuration */ +/*---------------------------------------------------------------------------*/ + +/** Audio recording preset */ +/** Audio recording preset key */ +#define SL_ANDROID_KEY_RECORDING_PRESET ((const SLchar*) "androidRecordingPreset") +/** Audio recording preset values */ +/** preset "none" cannot be set, it is used to indicate the current settings + * do not match any of the presets. */ +#define SL_ANDROID_RECORDING_PRESET_NONE ((SLuint32) 0x00000000) +/** generic recording configuration on the platform */ +#define SL_ANDROID_RECORDING_PRESET_GENERIC ((SLuint32) 0x00000001) +/** uses the microphone audio source with the same orientation as the camera + * if available, the main device microphone otherwise */ +#define SL_ANDROID_RECORDING_PRESET_CAMCORDER ((SLuint32) 0x00000002) +/** uses the main microphone tuned for voice recognition */ +#define SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION ((SLuint32) 0x00000003) + +/*---------------------------------------------------------------------------*/ +/* Android AudioPlayer configuration */ +/*---------------------------------------------------------------------------*/ + +/** Audio playback stream type */ +/** Audio playback stream type key */ +#define SL_ANDROID_KEY_STREAM_TYPE ((const SLchar*) "androidPlaybackStreamType") + +/** Audio playback stream type values */ +/* same as android.media.AudioManager.STREAM_VOICE_CALL */ +#define SL_ANDROID_STREAM_VOICE ((SLint32) 0x00000000) +/* same as android.media.AudioManager.STREAM_SYSTEM */ +#define SL_ANDROID_STREAM_SYSTEM ((SLint32) 0x00000001) +/* same as android.media.AudioManager.STREAM_RING */ +#define SL_ANDROID_STREAM_RING ((SLint32) 0x00000002) +/* same as android.media.AudioManager.STREAM_MUSIC */ +#define SL_ANDROID_STREAM_MEDIA ((SLint32) 0x00000003) +/* same as android.media.AudioManager.STREAM_ALARM */ +#define SL_ANDROID_STREAM_ALARM ((SLint32) 0x00000004) +/* same as android.media.AudioManager.STREAM_NOTIFICATION */ +#define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005) + +#endif /* OPENSL_ES_ANDROIDCONFIGURATION_H_ */ diff --git a/media/libcubeb/src/audiotrack_definitions.h b/media/libcubeb/src/audiotrack_definitions.h new file mode 100644 index 000000000000..da3032d4084c --- /dev/null +++ b/media/libcubeb/src/audiotrack_definitions.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +/* + * The following definitions are copied from the android sources. Only the + * relevant enum member and values needed are copied. + */ + +/* + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/utils/Errors.h + */ +typedef int32_t status_t; + +/* + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/media/AudioTrack.h + */ +struct Buffer { + uint32_t flags; + int channelCount; + int format; + size_t frameCount; + size_t size; + union { + void* raw; + short* i16; + int8_t* i8; + }; +}; + +enum event_type { + EVENT_MORE_DATA = 0, + EVENT_UNDERRUN = 1, + EVENT_LOOP_END = 2, + EVENT_MARKER = 3, + EVENT_NEW_POS = 4, + EVENT_BUFFER_END = 5 +}; + +/** + * From https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/include/media/AudioSystem.h + * and + * https://android.googlesource.com/platform/system/core/+/android-4.2.2_r1/include/system/audio.h + */ + +#define AUDIO_STREAM_TYPE_MUSIC 3 + +enum { + AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS = 0x1, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_ICS = 0x2, + AUDIO_CHANNEL_OUT_MONO_ICS = AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS, + AUDIO_CHANNEL_OUT_STEREO_ICS = (AUDIO_CHANNEL_OUT_FRONT_LEFT_ICS | AUDIO_CHANNEL_OUT_FRONT_RIGHT_ICS) +} AudioTrack_ChannelMapping_ICS; + +enum { + AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo = 0x4, + AUDIO_CHANNEL_OUT_FRONT_RIGHT_Froyo = 0x8, + AUDIO_CHANNEL_OUT_MONO_Froyo = AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo, + AUDIO_CHANNEL_OUT_STEREO_Froyo = (AUDIO_CHANNEL_OUT_FRONT_LEFT_Froyo | AUDIO_CHANNEL_OUT_FRONT_RIGHT_Froyo) +} AudioTrack_ChannelMapping_Froyo; + +typedef enum { + AUDIO_FORMAT_PCM = 0x00000000, + AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, + AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_16_BIT), +} AudioTrack_SampleType; + diff --git a/media/libcubeb/src/cubeb-internal.h b/media/libcubeb/src/cubeb-internal.h index ec2ddfaf977b..f617a56adf05 100644 --- a/media/libcubeb/src/cubeb-internal.h +++ b/media/libcubeb/src/cubeb-internal.h @@ -4,8 +4,8 @@ * This program is made available under an ISC-style license. See the * accompanying file LICENSE for details. */ -#ifndef CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5 -#define CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5 +#if !defined(CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5) +#define CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5 #include "cubeb/cubeb.h" diff --git a/media/libcubeb/src/cubeb.c b/media/libcubeb/src/cubeb.c index fface813247a..a4b6a5329a18 100644 --- a/media/libcubeb/src/cubeb.c +++ b/media/libcubeb/src/cubeb.c @@ -5,7 +5,7 @@ * accompanying file LICENSE for details. */ #include -#ifdef HAVE_CONFIG_H +#if defined(HAVE_CONFIG_H) #include "config.h" #endif #include "cubeb/cubeb.h" @@ -21,30 +21,33 @@ struct cubeb_stream { struct cubeb * context; }; -#ifdef USE_PULSE +#if defined(USE_PULSE) int pulse_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_ALSA +#if defined(USE_ALSA) int alsa_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_AUDIOQUEUE +#if defined(USE_AUDIOQUEUE) int audioqueue_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_AUDIOUNIT +#if defined(USE_AUDIOUNIT) int audiounit_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_DIRECTSOUND +#if defined(USE_DIRECTSOUND) int directsound_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_WINMM +#if defined(USE_WINMM) int winmm_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_SNDIO +#if defined(USE_SNDIO) int sndio_init(cubeb ** context, char const * context_name); #endif -#ifdef USE_OPENSL +#if defined(USE_OPENSL) int opensl_init(cubeb ** context, char const * context_name); #endif +#if defined(USE_AUDIOTRACK) +int audiotrack_init(cubeb ** context, char const * context_name); +#endif int validate_stream_params(cubeb_stream_params stream_params) @@ -78,29 +81,32 @@ int cubeb_init(cubeb ** context, char const * context_name) { int (* init[])(cubeb **, char const *) = { -#ifdef USE_PULSE +#if defined(USE_PULSE) pulse_init, #endif -#ifdef USE_ALSA +#if defined(USE_ALSA) alsa_init, #endif -#ifdef USE_AUDIOUNIT +#if defined(USE_AUDIOUNIT) audiounit_init, #endif -#ifdef USE_AUDIOQUEUE +#if defined(USE_AUDIOQUEUE) audioqueue_init, #endif -#ifdef USE_WINMM +#if defined(USE_WINMM) winmm_init, #endif -#ifdef USE_DIRECTSOUND +#if defined(USE_DIRECTSOUND) directsound_init, #endif -#ifdef USE_SNDIO +#if defined(USE_SNDIO) sndio_init, #endif -#ifdef USE_OPENSL +#if defined(USE_OPENSL) opensl_init, +#endif +#if defined(USE_AUDIOTRACK) + audiotrack_init, #endif }; int i; diff --git a/media/libcubeb/src/cubeb_audiotrack.c b/media/libcubeb/src/cubeb_audiotrack.c new file mode 100644 index 000000000000..723dc947e37e --- /dev/null +++ b/media/libcubeb/src/cubeb_audiotrack.c @@ -0,0 +1,402 @@ +/* + * Copyright © 2013 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ + +#define NDEBUG +#include +#include +#include +#include +#include +#include "android/log.h" + +#include "cubeb/cubeb.h" +#include "cubeb-internal.h" +#include "android/audiotrack_definitions.h" + +#ifndef ALOG +#if defined(DEBUG) || defined(FORCE_ALOG) +#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko - Cubeb" , ## args) +#else +#define ALOG(args...) +#endif +#endif + +/** + * A lot of bytes for safety. It should be possible to bring this down a bit. */ +#define SIZE_AUDIOTRACK_INSTANCE 256 + +/** + * call dlsym to get the symbol |mangled_name|, handle the error and store the + * pointer in |pointer|. Because depending on Android version, we want different + * symbols, not finding a symbol is not an error. */ +#define DLSYM_DLERROR(mangled_name, pointer, lib) \ + do { \ + pointer = dlsym(lib, mangled_name); \ + if (!pointer) { \ + ALOG("error while loading %stm: %stm\n", mangled_name, dlerror()); \ + } else { \ + ALOG("%stm: OK", mangled_name); \ + } \ + } while(0); + +static struct cubeb_ops const audiotrack_ops; +void audiotrack_destroy(cubeb * context); +void audiotrack_stream_destroy(cubeb_stream * stream); + +struct AudioTrack { + /* only available on ICS and later. */ + /* static */ status_t (*get_min_frame_count)(int* frame_count, int stream_type, uint32_t rate); + /* if this symbol is not availble, and the next one is, we know + * we are on a Froyo (Android 2.2) device. */ + void* (*ctor)(void* instance, int, unsigned int, int, int, int, unsigned int, void (*)(int, void*, void*), void*, int, int); + void* (*ctor_froyo)(void* instance, int, unsigned int, int, int, int, unsigned int, void (*)(int, void*, void*), void*, int); + void* (*dtor)(void* instance); + void (*start)(void* instance); + void (*pause)(void* instance); + uint32_t (*latency)(void* instance); + status_t (*check)(void* instance); + status_t (*get_position)(void* instance, uint32_t* position); + /* only used on froyo. */ + /* static */ int (*get_output_frame_count)(int* frame_count, int stream); + /* static */ int (*get_output_latency)(uint32_t* frame_count, int stream); + /* static */ int (*get_output_samplingrate)(int* frame_count, int stream); + status_t (*set_marker_position)(void* instance, unsigned int); + +}; + +struct cubeb { + struct cubeb_ops const * ops; + void * library; + struct AudioTrack klass; +}; + +struct cubeb_stream { + cubeb * context; + cubeb_stream_params params; + cubeb_data_callback data_callback; + cubeb_state_callback state_callback; + void * instance; + void * user_ptr; + /* Number of frames that have been passed to the AudioTrack callback */ + long unsigned written; + int draining; +}; + +static void +audiotrack_refill(int event, void* user, void* info) +{ + cubeb_stream * stream = user; + switch (event) { + case EVENT_MORE_DATA: { + long got = 0; + struct Buffer * b = (struct Buffer*)info; + + if (stream->draining) { + return; + } + + got = stream->data_callback(stream, stream->user_ptr, b->raw, b->frameCount); + + stream->written += got; + + if (got != (long)b->frameCount) { + uint32_t p; + stream->draining = 1; + /* set a marker so we are notified when the are done draining, that is, + * when every frame has been played by android. */ + stream->context->klass.set_marker_position(stream->instance, stream->written); + } + + break; + } + case EVENT_UNDERRUN: + ALOG("underrun in cubeb backend."); + break; + case EVENT_LOOP_END: + assert(0 && "We don't support the loop feature of audiotrack."); + break; + case EVENT_MARKER: + assert(stream->draining); + stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_DRAINED); + break; + case EVENT_NEW_POS: + assert(0 && "We don't support the setPositionUpdatePeriod feature of audiotrack."); + break; + case EVENT_BUFFER_END: + assert(0 && "Should not happen."); + break; + } +} + +/* We are running on froyo if we found the right AudioTrack constructor */ +static int +audiotrack_version_is_froyo(cubeb * ctx) +{ + return ctx->klass.ctor_froyo != NULL; +} + +int +audiotrack_get_min_frame_count(cubeb * ctx, cubeb_stream_params * params, int * min_frame_count) +{ + status_t status; + /* Recent Android have a getMinFrameCount method. On Froyo, we have to compute it by hand. */ + if (audiotrack_version_is_froyo(ctx)) { + int samplerate, frame_count, latency, min_buffer_count; + status = ctx->klass.get_output_frame_count(&frame_count, AUDIO_STREAM_TYPE_MUSIC); + if (status) { + ALOG("error getting the output frame count."); + return CUBEB_ERROR; + } + status = ctx->klass.get_output_latency((uint32_t*)&latency, AUDIO_STREAM_TYPE_MUSIC); + if (status) { + ALOG("error getting the output frame count."); + return CUBEB_ERROR; + } + status = ctx->klass.get_output_samplingrate(&samplerate, AUDIO_STREAM_TYPE_MUSIC); + if (status) { + ALOG("error getting the output frame count."); + return CUBEB_ERROR; + } + + /* Those numbers were found reading the Android source. It is the minimum + * numbers that will be accepted by the AudioTrack class, hence yielding the + * best latency possible. + * See https://android.googlesource.com/platform/frameworks/base/+/android-2.2.3_r2.1/media/libmedia/AudioTrack.cpp + * around line 181 for Android 2.2 */ + min_buffer_count = latency / ((1000 * frame_count) / samplerate); + min_buffer_count = min_buffer_count < 2 ? min_buffer_count : 2; + *min_frame_count = (frame_count * params->rate * min_buffer_count) / samplerate; + return CUBEB_OK; + } + /* Recent Android have a getMinFrameCount method. */ + status = ctx->klass.get_min_frame_count(min_frame_count, AUDIO_STREAM_TYPE_MUSIC, params->rate); + if (status != 0) { + ALOG("error getting the min frame count"); + return CUBEB_ERROR; + } + return CUBEB_OK; +} + +int +audiotrack_init(cubeb ** context, char const * context_name) +{ + cubeb * ctx; + struct AudioTrack* c; + + assert(context); + *context = NULL; + + ctx = calloc(1, sizeof(*ctx)); + assert(ctx); + + /* If we use an absolute path here ("/system/lib/libmedia.so"), and on Android + * 2.2, the dlopen succeeds, all the dlsym succeed, but a segfault happens on + * the first call to a dlsym'ed function. Somehow this does not happen when + * using only the name of the library. */ + ctx->library = dlopen("libmedia.so", RTLD_LAZY); + if (!ctx->library) { + ALOG("dlopen error: %s.", dlerror()); + free(ctx); + return CUBEB_ERROR; + } + + /* Recent Android first, then Froyo. */ + DLSYM_DLERROR("_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii", ctx->klass.ctor, ctx->library); + if (!ctx->klass.ctor) { + DLSYM_DLERROR("_ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i", ctx->klass.ctor_froyo, ctx->library); + assert(ctx->klass.ctor_froyo); + } + DLSYM_DLERROR("_ZN7android10AudioTrackD1Ev", ctx->klass.dtor, ctx->library); + + DLSYM_DLERROR("_ZNK7android10AudioTrack7latencyEv", ctx->klass.latency, ctx->library); + DLSYM_DLERROR("_ZNK7android10AudioTrack9initCheckEv", ctx->klass.check, ctx->library); + + /* |getMinFrameCount| is not available on Froyo. */ + if (audiotrack_version_is_froyo(ctx)) { + DLSYM_DLERROR("_ZN7android11AudioSystem19getOutputFrameCountEPii", ctx->klass.get_output_frame_count, ctx->library); + DLSYM_DLERROR("_ZN7android11AudioSystem16getOutputLatencyEPji", ctx->klass.get_output_latency, ctx->library); + DLSYM_DLERROR("_ZN7android11AudioSystem21getOutputSamplingRateEPii", ctx->klass.get_output_samplingrate, ctx->library); + } else { + DLSYM_DLERROR("_ZN7android10AudioTrack16getMinFrameCountEPi19audio_stream_type_tj", ctx->klass.get_min_frame_count, ctx->library); + } + + DLSYM_DLERROR("_ZN7android10AudioTrack5startEv", ctx->klass.start, ctx->library); + DLSYM_DLERROR("_ZN7android10AudioTrack5pauseEv", ctx->klass.pause, ctx->library); + DLSYM_DLERROR("_ZN7android10AudioTrack11getPositionEPj", ctx->klass.get_position, ctx->library); + DLSYM_DLERROR("_ZN7android10AudioTrack17setMarkerPositionEj", ctx->klass.set_marker_position, ctx->library); + + /* check that we have a combination of symbol that makes sense */ + c = &ctx->klass; + if(!((c->ctor || c->ctor_froyo) && /* at least on ctor. */ + c->dtor && c->latency && c->check && + /* at least one way to get the minimum frame count to request. */ + ((c->get_output_frame_count && c->get_output_latency && c->get_output_samplingrate) || + c->get_min_frame_count) && + c->start && c->pause && c->get_position && c->set_marker_position)) { + ALOG("Could not find all the symbols we need."); + audiotrack_destroy(ctx); + return CUBEB_ERROR; + } + + ctx->ops = &audiotrack_ops; + + *context = ctx; + + return CUBEB_OK; +} + +char const * +audiotrack_get_backend_id(cubeb * context) +{ + return "audiotrack"; +} + +void +audiotrack_destroy(cubeb * context) +{ + assert(context); + + dlclose(context->library); + + free(context); +} + +int +audiotrack_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, + cubeb_stream_params stream_params, unsigned int latency, + cubeb_data_callback data_callback, + cubeb_state_callback state_callback, + void * user_ptr) +{ + struct cubeb_stream * stm; + int32_t channels; + int32_t min_frame_count; + + assert(ctx && stream); + + if (stream_params.format == CUBEB_SAMPLE_FLOAT32LE || + stream_params.format == CUBEB_SAMPLE_FLOAT32BE) { + return CUBEB_ERROR_INVALID_FORMAT; + } + + if (audiotrack_get_min_frame_count(ctx, &stream_params, &min_frame_count)) { + return CUBEB_ERROR; + } + + stm = calloc(1, sizeof(*stm)); + assert(stm); + + stm->context = ctx; + stm->data_callback = data_callback; + stm->state_callback = state_callback; + stm->user_ptr = user_ptr; + stm->params = stream_params; + + stm->instance = calloc(SIZE_AUDIOTRACK_INSTANCE, 1); + (*(uint32_t*)((intptr_t)stm->instance + SIZE_AUDIOTRACK_INSTANCE - 4)) = 0xbaadbaad; + assert(stm->instance && "cubeb: EOM"); + + if (audiotrack_version_is_froyo(ctx)) { + channels = stm->params.channels == 2 ? AUDIO_CHANNEL_OUT_STEREO_Froyo : AUDIO_CHANNEL_OUT_MONO_Froyo; + } else { + channels = stm->params.channels == 2 ? AUDIO_CHANNEL_OUT_STEREO_ICS : AUDIO_CHANNEL_OUT_MONO_ICS; + } + + if (audiotrack_version_is_froyo(ctx)) { + ctx->klass.ctor_froyo(stm->instance, + AUDIO_STREAM_TYPE_MUSIC, + stm->params.rate, + AUDIO_FORMAT_PCM_16_BIT, + channels, + min_frame_count, + 0, + audiotrack_refill, + stm, + 0); + } else { + ctx->klass.ctor(stm->instance, + AUDIO_STREAM_TYPE_MUSIC, + stm->params.rate, + AUDIO_FORMAT_PCM_16_BIT, + channels, + min_frame_count, + 0, + audiotrack_refill, + stm, + 0, + 0); + } + + assert((*(uint32_t*)((intptr_t)stm->instance + SIZE_AUDIOTRACK_INSTANCE - 4)) == 0xbaadbaad); + + if (ctx->klass.check(stm->instance)) { + ALOG("stream not initialized properly."); + audiotrack_stream_destroy(stm); + return CUBEB_ERROR; + } + + *stream = stm; + + return CUBEB_OK; +} + +void +audiotrack_stream_destroy(cubeb_stream * stream) +{ + assert(stream->context); + + stream->context->klass.dtor(stream->instance); + + free(stream->instance); + stream->instance = NULL; + free(stream); +} + +int +audiotrack_stream_start(cubeb_stream * stream) +{ + assert(stream->instance); + + stream->context->klass.start(stream->instance); + stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_STARTED); + + return CUBEB_OK; +} + +int +audiotrack_stream_stop(cubeb_stream * stream) +{ + assert(stream->instance); + + stream->context->klass.pause(stream->instance); + stream->state_callback(stream, stream->user_ptr, CUBEB_STATE_STOPPED); + + return CUBEB_OK; +} + +int +audiotrack_stream_get_position(cubeb_stream * stream, uint64_t * position) +{ + uint32_t p; + + assert(stream->instance && position); + stream->context->klass.get_position(stream->instance, &p); + *position = p; + + return CUBEB_OK; +} + +static struct cubeb_ops const audiotrack_ops = { + .init = audiotrack_init, + .get_backend_id = audiotrack_get_backend_id, + .destroy = audiotrack_destroy, + .stream_init = audiotrack_stream_init, + .stream_destroy = audiotrack_stream_destroy, + .stream_start = audiotrack_stream_start, + .stream_stop = audiotrack_stream_stop, + .stream_get_position = audiotrack_stream_get_position +}; diff --git a/media/libcubeb/src/cubeb_opensl.c b/media/libcubeb/src/cubeb_opensl.c index ffeca02f3b66..27c6a61a8c15 100644 --- a/media/libcubeb/src/cubeb_opensl.c +++ b/media/libcubeb/src/cubeb_opensl.c @@ -10,6 +10,7 @@ #include #include #if defined(__ANDROID__) +#include "android/sles_definitions.h" #include #endif #include "cubeb/cubeb.h" @@ -123,6 +124,8 @@ opensl_init(cubeb ** context, char const * context_name) ctx = calloc(1, sizeof(*ctx)); assert(ctx); + ctx->ops = &opensl_ops; + ctx->lib = dlopen("libOpenSLES.so", RTLD_LAZY); if (!ctx->lib) { free(ctx); diff --git a/media/libcubeb/src/cubeb_sndio.c b/media/libcubeb/src/cubeb_sndio.c index d39290e94dcb..49f7deed488c 100644 --- a/media/libcubeb/src/cubeb_sndio.c +++ b/media/libcubeb/src/cubeb_sndio.c @@ -12,7 +12,7 @@ #include "cubeb/cubeb.h" #include "cubeb-internal.h" -#ifdef CUBEB_SNDIO_DEBUG +#if defined(CUBEB_SNDIO_DEBUG) #define DPR(...) fprintf(stderr, __VA_ARGS__); #else #define DPR(...) do {} while(0) diff --git a/media/libcubeb/src/cubeb_winmm.c b/media/libcubeb/src/cubeb_winmm.c index bd4e03ac6c6c..e8b20bfb8540 100644 --- a/media/libcubeb/src/cubeb_winmm.c +++ b/media/libcubeb/src/cubeb_winmm.c @@ -19,7 +19,7 @@ #include "cubeb-internal.h" /* This is missing from the MinGW headers. Use a safe fallback. */ -#ifndef MEMORY_ALLOCATION_ALIGNMENT +#if !defined(MEMORY_ALLOCATION_ALIGNMENT) #define MEMORY_ALLOCATION_ALIGNMENT 16 #endif diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh index 403c4f13a042..f3cfc0e3d07d 100644 --- a/media/libcubeb/update.sh +++ b/media/libcubeb/update.sh @@ -10,6 +10,9 @@ cp $1/src/cubeb_audiounit.c src cp $1/src/cubeb_pulse.c src cp $1/src/cubeb_sndio.c src cp $1/src/cubeb_opensl.c src +cp $1/src/cubeb_audiotrack.c src +cp $1/src/android/audiotrack_definitions.h src/android +cp $1/src/android/sles_definitions.h src/android cp $1/LICENSE . cp $1/README . cp $1/AUTHORS .