Bug 698328 - Add a new cubeb backend based on AudioTrack.cpp. r=kinetik
authorPaul Adenot <paul@paul.cx>
Wed, 13 Mar 2013 19:36:46 +0100
changeset 124850 3080f18ba53d60e1102dc5b4c17778abf04b6b95
parent 124849 0b147c3f682be92d6e05205a275cc86432122f1a
child 124851 0044e4c2dc535d760c1ba7bd2fedaed5575ed7c2
push id24438
push userphilringnalda@gmail.com
push dateSat, 16 Mar 2013 22:12:32 +0000
treeherdermozilla-central@0b052daa913c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs698328
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 698328 - Add a new cubeb backend based on AudioTrack.cpp. r=kinetik
configure.in
media/libcubeb/AUTHORS
media/libcubeb/README_MOZILLA
media/libcubeb/include/cubeb.h
media/libcubeb/src/Makefile.in
media/libcubeb/src/android/audiotrack_definitions.h
media/libcubeb/src/android/sles_definitions.h
media/libcubeb/src/audiotrack_definitions.h
media/libcubeb/src/cubeb-internal.h
media/libcubeb/src/cubeb.c
media/libcubeb/src/cubeb_audiotrack.c
media/libcubeb/src/cubeb_opensl.c
media/libcubeb/src/cubeb_sndio.c
media/libcubeb/src/cubeb_winmm.c
media/libcubeb/update.sh
--- a/configure.in
+++ b/configure.in
@@ -5652,20 +5652,17 @@ fi
 
 if test -n "$MOZ_SOUNDTOUCH"; then
     AC_DEFINE(MOZ_SOUNDTOUCH)
 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)
         ;;
     *-mingw*)
         AC_DEFINE(MOZ_CUBEB)
         ;;
     *-darwin*)
--- a/media/libcubeb/AUTHORS
+++ b/media/libcubeb/AUTHORS
@@ -1,3 +1,4 @@
 Matthew Gregan <kinetik@flim.org>
 Alexandre Ratchov <alex@caoua.org>
 Michael Wu <mwu@mozilla.com>
+Paul Adenot <paul@paul.cx>
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 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.
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -1,20 +1,20 @@
 /*
  * Copyright © 2011 Mozilla Foundation
  *
  * 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 <cubeb/cubeb-stdint.h>
 
-#ifdef __cplusplus
+#if defined(__cplusplus)
 extern "C" {
 #endif
 
 /** @mainpage
 
     @section intro Introduction
 
     This is the documentation for the <tt>libcubeb</tt> C API.
@@ -221,13 +221,13 @@ int cubeb_stream_stop(cubeb_stream * str
 
 /** Get the current stream playback position.
     @param stream
     @param position Playback position in frames.
     @retval CUBEB_OK
     @retval CUBEB_ERROR */
 int cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position);
 
-#ifdef __cplusplus
+#if defined(__cplusplus)
 }
 #endif
 
 #endif /* CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 */
--- a/media/libcubeb/src/Makefile.in
+++ b/media/libcubeb/src/Makefile.in
@@ -23,24 +23,27 @@ CSRCS           = \
 ifeq ($(OS_TARGET),WINNT)
 CSRCS           += \
                 cubeb_winmm.c \
                 $(NULL)
 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           += \
                 cubeb_audiounit.c \
                 $(NULL)
 DEFINES         += -DUSE_AUDIOUNIT
 endif
 
new file mode 100644
--- /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 <cubeb/cubeb-stdint.h>
+
+/*
+ * 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;
+
new file mode 100644
--- /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_ */
new file mode 100644
--- /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 <cubeb/cubeb-stdint.h>
+
+/*
+ * 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;
+
--- a/media/libcubeb/src/cubeb-internal.h
+++ b/media/libcubeb/src/cubeb-internal.h
@@ -1,16 +1,16 @@
 /*
  * Copyright © 2013 Mozilla Foundation
  *
  * 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"
 
 struct cubeb_ops {
   int (* init)(cubeb ** context, char const * context_name);
   char const * (* get_backend_id)(cubeb * context);
   void (* destroy)(cubeb * context);
   int (* stream_init)(cubeb * context, cubeb_stream ** stream, char const * stream_name,
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -1,55 +1,58 @@
 /*
  * Copyright © 2013 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #include <stddef.h>
-#ifdef HAVE_CONFIG_H
+#if defined(HAVE_CONFIG_H)
 #include "config.h"
 #endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 
 #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0])))
 
 struct cubeb {
   struct cubeb_ops * ops;
 };
 
 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)
 {
   if (stream_params.rate < 1 || stream_params.rate > 192000 ||
       stream_params.channels < 1 || stream_params.channels > 8) {
     return CUBEB_ERROR_INVALID_FORMAT;
   }
@@ -73,40 +76,43 @@ validate_latency(int latency)
   }
   return CUBEB_OK;
 }
 
 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;
 
   if (!context) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
   for (i = 0; i < NELEMS(init); ++i) {
new file mode 100644
--- /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 <assert.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
+#include <dlfcn.h>
+#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
+};
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -5,16 +5,17 @@
  * accompanying file LICENSE for details.
  */
 #undef NDEBUG
 #include <assert.h>
 #include <dlfcn.h>
 #include <stdlib.h>
 #include <SLES/OpenSLES.h>
 #if defined(__ANDROID__)
+#include "android/sles_definitions.h"
 #include <SLES/OpenSLES_Android.h>
 #endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 
 static struct cubeb_ops const opensl_ops;
 
 struct cubeb {
@@ -118,16 +119,18 @@ opensl_init(cubeb ** context, char const
 {
   cubeb * ctx;
 
   *context = NULL;
 
   ctx = calloc(1, sizeof(*ctx));
   assert(ctx);
 
+  ctx->ops = &opensl_ops;
+
   ctx->lib = dlopen("libOpenSLES.so", RTLD_LAZY);
   if (!ctx->lib) {
     free(ctx);
     return CUBEB_ERROR;
   }
 
   typedef SLresult (*slCreateEngine_t)(SLObjectItf *,
                                        SLuint32,
--- a/media/libcubeb/src/cubeb_sndio.c
+++ b/media/libcubeb/src/cubeb_sndio.c
@@ -7,17 +7,17 @@
 #include <poll.h>
 #include <pthread.h>
 #include <sndio.h>
 #include <stdlib.h>
 #include <stdio.h>
 #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)
 #endif
 
 static struct cubeb_ops const sndio_ops;
 
 struct cubeb {
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -14,17 +14,17 @@
 #include <mmreg.h>
 #include <mmsystem.h>
 #include <process.h>
 #include <stdlib.h>
 #include "cubeb/cubeb.h"
 #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
 
 #define CUBEB_STREAM_MAX 32
 #define NBUFS 4
 
 const GUID KSDATAFORMAT_SUBTYPE_PCM =
 { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -5,16 +5,19 @@ cp $1/include/cubeb/cubeb.h include
 cp $1/src/cubeb.c src
 cp $1/src/cubeb-internal.h src
 cp $1/src/cubeb_alsa.c src
 cp $1/src/cubeb_winmm.c src
 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 .
 if [ -d $1/.git ]; then
   rev=$(cd $1 && git rev-parse --verify HEAD)
   dirty=$(cd $1 && git diff-index --name-only HEAD)
 fi