Backed out 9 changesets (bug 1410456) for Mochitest failure on mobile/android/tests/browser/chrome/test_media_playback.html
authorDorel Luca <dluca@mozilla.com>
Mon, 19 Feb 2018 21:45:10 +0200
changeset 456899 a75f30d856c949c557b59607e411a1b37ea2b5f0
parent 456898 38577c007450d641cfe792a974787cde0bbe1410
child 456900 92d362925563bf9dfb056255d5d018a84c63bc44
push id8799
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 16:46:23 +0000
treeherdermozilla-beta@15334014dc67 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1410456
milestone60.0a1
backs out36f6b40dfa8881839bcbc4053094b7bdfb944277
19f3248502d9f066883be6c8df528eb4cd644500
18ef18999175f7f66b614a74a64e02926ec53968
0ec75a56b4c7d164b2419e9326ca9da948c54645
f7eae1545d5e215081780c894340654d9781b698
d59060ecd24c545fef8bb9a9197aaac66da7ef81
f996b9dce4a69bf8d03e92746251bf3560a2166f
1f75636b5bce590ab6b16384ba26a0d8a0dbcbd1
c170d37b1a04906273272ecb3ce080713e0a7d54
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
Backed out 9 changesets (bug 1410456) for Mochitest failure on mobile/android/tests/browser/chrome/test_media_playback.html Backed out changeset 36f6b40dfa88 (bug 1410456) Backed out changeset 19f3248502d9 (bug 1410456) Backed out changeset 18ef18999175 (bug 1410456) Backed out changeset 0ec75a56b4c7 (bug 1410456) Backed out changeset f7eae1545d5e (bug 1410456) Backed out changeset d59060ecd24c (bug 1410456) Backed out changeset f996b9dce4a6 (bug 1410456) Backed out changeset 1f75636b5bce (bug 1410456) Backed out changeset c170d37b1a04 (bug 1410456)
dom/media/CubebUtils.cpp
dom/media/CubebUtils.h
dom/media/GraphDriver.cpp
media/libcubeb/README_MOZILLA
media/libcubeb/src/cubeb-jni-instances.h
media/libcubeb/src/cubeb-jni.cpp
media/libcubeb/src/cubeb-jni.h
media/libcubeb/src/cubeb_opensl.c
media/libcubeb/src/moz.build
media/libcubeb/update.sh
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
widget/android/GeneratedJNIWrappers.h
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -20,19 +20,16 @@
 #include "nsAutoRef.h"
 #include "nsDebug.h"
 #include "nsIStringBundle.h"
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "prdtoa.h"
 #include <algorithm>
 #include <stdint.h>
-#ifdef MOZ_WIDGET_ANDROID
-#include "GeneratedJNIWrappers.h"
-#endif
 
 #define PREF_VOLUME_SCALE "media.volume_scale"
 #define PREF_CUBEB_BACKEND "media.cubeb.backend"
 #define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
 #define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
 #define PREF_CUBEB_LOGGING_LEVEL "media.cubeb.logging_level"
 #define PREF_CUBEB_SANDBOX "media.cubeb.sandbox"
 
@@ -117,18 +114,18 @@ enum class CubebState {
   Uninitialized = 0,
   Initialized,
   Shutdown
 } sCubebState = CubebState::Uninitialized;
 cubeb* sCubebContext;
 double sVolumeScale = 1.0;
 uint32_t sCubebPlaybackLatencyInMilliseconds = 100;
 uint32_t sCubebMSGLatencyInFrames = 512;
-bool sCubebPlaybackLatencyPrefSet = false;
-bool sCubebMSGLatencyPrefSet = false;
+bool sCubebPlaybackLatencyPrefSet;
+bool sCubebMSGLatencyPrefSet;
 bool sAudioStreamInitEverSucceeded = false;
 #ifdef MOZ_CUBEB_REMOTING
 bool sCubebSandbox;
 #endif
 StaticAutoPtr<char> sBrandName;
 StaticAutoPtr<char> sCubebBackendName;
 
 const char kBrandBundleURL[]      = "chrome://branding/locale/brand.properties";
@@ -303,25 +300,21 @@ bool InitPreferredSampleRate()
   StaticMutexAutoLock lock(sMutex);
   if (sPreferredSampleRate != 0) {
     return true;
   }
   cubeb* context = GetCubebContextUnlocked();
   if (!context) {
     return false;
   }
-#ifdef MOZ_WIDGET_ANDROID
-  sPreferredSampleRate = AndroidGetAudioOutputSampleRate();
-#else
   if (cubeb_get_preferred_sample_rate(context,
                                       &sPreferredSampleRate) != CUBEB_OK) {
 
     return false;
   }
-#endif
   MOZ_ASSERT(sPreferredSampleRate);
   return true;
 }
 
 uint32_t PreferredSampleRate()
 {
   if (!InitPreferredSampleRate()) {
     return 44100;
@@ -529,38 +522,24 @@ bool CubebPlaybackLatencyPrefSet()
 }
 
 bool CubebMSGLatencyPrefSet()
 {
   StaticMutexAutoLock lock(sMutex);
   return sCubebMSGLatencyPrefSet;
 }
 
-uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params)
+Maybe<uint32_t> GetCubebMSGLatencyInFrames()
 {
   StaticMutexAutoLock lock(sMutex);
-  if (sCubebMSGLatencyPrefSet) {
-    MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
-    return sCubebMSGLatencyInFrames;
+  if (!sCubebMSGLatencyPrefSet) {
+    return Maybe<uint32_t>();
   }
-
-#ifdef MOZ_WIDGET_ANDROID
-  return AndroidGetAudioOutputFramesPerBuffer();
-#else
-  cubeb* context = GetCubebContextUnlocked();
-  if (!context) {
-    return sCubebMSGLatencyInFrames; // default 512
-  }
-  uint32_t latency_frames = 0;
-  if (cubeb_get_min_latency(context, params, &latency_frames) != CUBEB_OK) {
-    NS_WARNING("Could not get minimal latency from cubeb.");
-    return sCubebMSGLatencyInFrames; // default 512
-  }
-  return latency_frames;
-#endif
+  MOZ_ASSERT(sCubebMSGLatencyInFrames > 0);
+  return Some(sCubebMSGLatencyInFrames);
 }
 
 void InitLibrary()
 {
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_VOLUME_SCALE);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_PLAYBACK);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_LATENCY_MSG);
   Preferences::RegisterCallbackAndCall(PrefChanged, PREF_CUBEB_BACKEND);
@@ -757,25 +736,10 @@ void GetDeviceCollection(nsTArray<RefPtr
                               device.latency_lo);
         aDeviceInfos.AppendElement(info);
       }
     }
     cubeb_device_collection_destroy(context, &collection);
   }
 }
 
-#ifdef MOZ_WIDGET_ANDROID
-uint32_t AndroidGetAudioOutputSampleRate()
-{
-  int32_t sample_rate = java::GeckoAppShell::GetAudioOutputSampleRate();
-  MOZ_ASSERT(sample_rate > 0);
-  return sample_rate;
-}
-uint32_t AndroidGetAudioOutputFramesPerBuffer()
-{
-  int32_t frames = java::GeckoAppShell::GetAudioOutputFramesPerBuffer();
-  MOZ_ASSERT(frames > 0);
-  return frames;
-}
-#endif
-
 } // namespace CubebUtils
 } // namespace mozilla
--- a/dom/media/CubebUtils.h
+++ b/dom/media/CubebUtils.h
@@ -39,25 +39,20 @@ enum Side {
 };
 
 double GetVolumeScale();
 bool GetFirstStream();
 cubeb* GetCubebContext();
 void ReportCubebStreamInitFailure(bool aIsFirstStream);
 void ReportCubebBackendUsed();
 uint32_t GetCubebPlaybackLatencyInMilliseconds();
-uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params);
+Maybe<uint32_t> GetCubebMSGLatencyInFrames();
 bool CubebLatencyPrefSet();
 cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap);
 void GetCurrentBackend(nsAString& aBackend);
 void GetPreferredChannelLayout(nsAString& aLayout);
 void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& aDeviceInfos,
                          Side aSide);
 cubeb_channel_layout GetPreferredChannelLayoutOrSMPTE(cubeb* context, uint32_t aChannels);
-
-#ifdef MOZ_WIDGET_ANDROID
-uint32_t AndroidGetAudioOutputSampleRate();
-uint32_t AndroidGetAudioOutputFramesPerBuffer();
-#endif
 } // namespace CubebUtils
 } // namespace mozilla
 
 #endif // CubebUtils_h_
--- a/dom/media/GraphDriver.cpp
+++ b/dom/media/GraphDriver.cpp
@@ -594,16 +594,17 @@ AudioCallbackDriver::Init()
     if (!mFromFallback) {
       CubebUtils::ReportCubebStreamInitFailure(true);
     }
     return false;
   }
 
   cubeb_stream_params output;
   cubeb_stream_params input;
+  uint32_t latency_frames;
   bool firstStream = CubebUtils::GetFirstStream();
 
   MOZ_ASSERT(!NS_IsMainThread(),
       "This is blocking and should never run on the main thread.");
 
   mSampleRate = output.rate = CubebUtils::PreferredSampleRate();
 
   if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
@@ -623,17 +624,24 @@ AudioCallbackDriver::Init()
 
   mBuffer = AudioCallbackBufferWrapper<AudioDataValue>(mOutputChannels);
   mScratchBuffer = SpillBuffer<AudioDataValue, WEBAUDIO_BLOCK_SIZE * 2>(mOutputChannels);
 
   output.channels = mOutputChannels;
   output.layout = CubebUtils::GetPreferredChannelLayoutOrSMPTE(cubebContext, mOutputChannels);
   output.prefs = CUBEB_STREAM_PREF_NONE;
 
-  uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output);
+  Maybe<uint32_t> latencyPref = CubebUtils::GetCubebMSGLatencyInFrames();
+  if (latencyPref) {
+    latency_frames = latencyPref.value();
+  } else {
+    if (cubeb_get_min_latency(cubebContext, &output, &latency_frames) != CUBEB_OK) {
+      NS_WARNING("Could not get minimal latency from cubeb.");
+    }
+  }
 
   // Macbook and MacBook air don't have enough CPU to run very low latency
   // MediaStreamGraphs, cap the minimal latency to 512 frames int this case.
   if (IsMacbookOrMacbookAir()) {
     latency_frames = std::max((uint32_t) 512, latency_frames);
   }
 
   input = output;
--- 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 84e9568141447d13a3f9e03fcff29c2ab6befce1 (2018-02-19 17:50:15 +0200)
+The git commit ID used was 1d53c3a3779cbeb860b16aa38cc7f51e196b9745 (2018-02-13 12:30:46 +1000)
deleted file mode 100644
--- a/media/libcubeb/src/cubeb-jni-instances.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef _CUBEB_JNI_INSTANCES_H_
-#define _CUBEB_JNI_INSTANCES_H_
-
-#include "GeneratedJNIWrappers.h"
-#include "mozilla/jni/Utils.h"
-
-/*
- * The methods in this file offer a way to pass in the required
- * JNI instances in the cubeb library. By default they return NULL.
- * In this case part of the cubeb API that depends on JNI
- * will return CUBEB_ERROR_NOT_SUPPORTED. Currently only one
- * method depends on that:
- *
- * cubeb_stream_get_position()
- *
- * Users that want to use that cubeb API method must "override"
- * the methods bellow to return a valid instance of JavaVM
- * and application's Context object.
- * */
-
-JavaVM *
-cubeb_jni_get_java_vm()
-{
-  return mozilla::jni::GetVM();
-}
-
-jobject
-cubeb_jni_get_context_instance()
-{
-  auto context = mozilla::java::GeckoAppShell::GetApplicationContext();
-  return context.Forget();
-}
-
-#endif //_CUBEB_JNI_INSTANCES_H_
deleted file mode 100644
--- a/media/libcubeb/src/cubeb-jni.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-#include "jni.h"
-#include <assert.h>
-#include "cubeb-jni-instances.h"
-
-#define AUDIO_STREAM_TYPE_MUSIC 3
-
-JNIEnv *
-cubeb_jni_get_env_for_thread(JavaVM * java_vm)
-{
-    JNIEnv * env = nullptr;
-    if (!java_vm->AttachCurrentThread(&env, nullptr)) {
-        assert(env);
-        return env;
-    }
-
-    assert(false && "Failed to get JNIEnv for thread");
-    return nullptr; // unreachable
-}
-
-struct cubeb_jni {
-  JavaVM * s_java_vm = nullptr;
-  jobject s_audio_manager_obj = nullptr;
-  jclass s_audio_manager_class = nullptr;
-  jmethodID s_get_output_latency_id = nullptr;
-};
-
-extern "C"
-cubeb_jni *
-cubeb_jni_init()
-{
-  JavaVM * javaVM = cubeb_jni_get_java_vm();
-  jobject ctx_obj = cubeb_jni_get_context_instance();
-
-  if (!javaVM || !ctx_obj) {
-    return nullptr;
-  }
-
-  JNIEnv * jni_env = cubeb_jni_get_env_for_thread(javaVM);
-  assert(jni_env);
-
-  cubeb_jni * cubeb_jni_ptr = new cubeb_jni;
-  assert(cubeb_jni_ptr);
-
-  cubeb_jni_ptr->s_java_vm = javaVM;
-
-  // Find the audio manager object and make it global to call it from another method
-  jclass context_class = jni_env->FindClass("android/content/Context");
-  jfieldID audio_service_field = jni_env->GetStaticFieldID(context_class, "AUDIO_SERVICE", "Ljava/lang/String;");
-  jstring jstr = (jstring)jni_env->GetStaticObjectField(context_class, audio_service_field);
-  jmethodID get_system_service_id = jni_env->GetMethodID(context_class, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
-  jobject audio_manager_obj = jni_env->CallObjectMethod(ctx_obj, get_system_service_id, jstr);
-  cubeb_jni_ptr->s_audio_manager_obj = reinterpret_cast<jobject>(jni_env->NewGlobalRef(audio_manager_obj));
-
-  // Make the audio manager class a global reference in order to preserve method id
-  jclass audio_manager_class = jni_env->FindClass("android/media/AudioManager");
-  cubeb_jni_ptr->s_audio_manager_class = reinterpret_cast<jclass>(jni_env->NewGlobalRef(audio_manager_class));
-  cubeb_jni_ptr->s_get_output_latency_id = jni_env->GetMethodID (audio_manager_class, "getOutputLatency", "(I)I");
-
-  jni_env->DeleteLocalRef(ctx_obj);
-  jni_env->DeleteLocalRef(context_class);
-  jni_env->DeleteLocalRef(jstr);
-  jni_env->DeleteLocalRef(audio_manager_obj);
-  jni_env->DeleteLocalRef(audio_manager_class);
-
-  return cubeb_jni_ptr;
-}
-
-extern "C"
-int cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr)
-{
-  assert(cubeb_jni_ptr);
-  JNIEnv * jni_env = cubeb_jni_get_env_for_thread(cubeb_jni_ptr->s_java_vm);
-  return jni_env->CallIntMethod(cubeb_jni_ptr->s_audio_manager_obj, cubeb_jni_ptr->s_get_output_latency_id, AUDIO_STREAM_TYPE_MUSIC); //param: AudioManager.STREAM_MUSIC
-}
-
-extern "C"
-void cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr)
-{
-  assert(cubeb_jni_ptr);
-
-  JNIEnv * jni_env = cubeb_jni_get_env_for_thread(cubeb_jni_ptr->s_java_vm);
-  assert(jni_env);
-
-  jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_obj);
-  jni_env->DeleteGlobalRef(cubeb_jni_ptr->s_audio_manager_class);
-
-  delete cubeb_jni_ptr;
-}
deleted file mode 100644
--- a/media/libcubeb/src/cubeb-jni.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _CUBEB_JNI_H_
-#define _CUBEB_JNI_H_
-
-typedef struct cubeb_jni cubeb_jni;
-
-cubeb_jni * cubeb_jni_init();
-int cubeb_get_output_latency_from_jni(cubeb_jni * cubeb_jni_ptr);
-void cubeb_jni_destroy(cubeb_jni * cubeb_jni_ptr);
-
-#endif // _CUBEB_JNI_H_
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -21,17 +21,16 @@
 #include <android/log.h>
 #include <android/api-level.h>
 #endif
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 #include "cubeb_resampler.h"
 #include "cubeb-sles.h"
 #include "cubeb_array_queue.h"
-#include "cubeb-jni.h"
 
 #if defined(__ANDROID__)
 #ifdef LOG
 #undef LOG
 #endif
 //#define LOGGING_ENABLED
 #ifdef LOGGING_ENABLED
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Cubeb_OpenSL" , ## args)
@@ -57,39 +56,40 @@
 #endif
 
 #define ANDROID_VERSION_GINGERBREAD_MR1 10
 #define ANDROID_VERSION_LOLLIPOP 21
 #define ANDROID_VERSION_MARSHMALLOW 23
 #endif
 
 #define DEFAULT_SAMPLE_RATE 48000
-#define DEFAULT_NUM_OF_FRAMES 480
 
 static struct cubeb_ops const opensl_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
   void * lib;
+  void * libmedia;
+  int32_t (* get_output_latency)(uint32_t * latency, int stream_type);
   SLInterfaceID SL_IID_BUFFERQUEUE;
   SLInterfaceID SL_IID_PLAY;
 #if defined(__ANDROID__)
   SLInterfaceID SL_IID_ANDROIDCONFIGURATION;
   SLInterfaceID SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
 #endif
   SLInterfaceID SL_IID_VOLUME;
   SLInterfaceID SL_IID_RECORD;
   SLObjectItf engObj;
   SLEngineItf eng;
   SLObjectItf outmixObj;
-  cubeb_jni * jni_obj;
 };
 
 #define NELEMS(A) (sizeof(A) / sizeof A[0])
 #define NBUFS 4
+#define AUDIO_STREAM_TYPE_MUSIC 3
 
 struct cubeb_stream {
   /* Note: Must match cubeb_stream layout in cubeb.c. */
   cubeb * context;
   void * user_ptr;
   /**/
   pthread_mutex_t mutex;
   SLObjectItf playerObj;
@@ -148,17 +148,17 @@ struct cubeb_stream {
    * stream::mutex lock. */
   uint32_t shutdown;
   /* Store user callback. */
   cubeb_data_callback data_callback;
   /* Store state callback. */
   cubeb_state_callback state_callback;
 
   cubeb_resampler * resampler;
-  unsigned int user_output_rate;
+  unsigned int inputrate;
   unsigned int output_configured_rate;
   unsigned int latency_frames;
   int64_t lastPosition;
   int64_t lastPositionTimeStamp;
   int64_t lastCompensativePosition;
 };
 
 /* Forward declaration. */
@@ -231,16 +231,17 @@ opensl_set_shutdown(cubeb_stream * stm, 
   assert(value == 0 || value == 1);
   stm->shutdown = value;
 }
 
 static void
 play_callback(SLPlayItf caller, void * user_ptr, SLuint32 event)
 {
   cubeb_stream * stm = user_ptr;
+  int draining;
   assert(stm);
   switch (event) {
     case SL_PLAYEVENT_HEADATMARKER:
       opensl_notify_drained(stm);
     break;
   default:
     break;
   }
@@ -662,21 +663,40 @@ opensl_init(cubeb ** context, char const
   *context = NULL;
 
   ctx = calloc(1, sizeof(*ctx));
   assert(ctx);
 
   ctx->ops = &opensl_ops;
 
   ctx->lib = dlopen("libOpenSLES.so", RTLD_LAZY);
-  if (!ctx->lib) {
+  ctx->libmedia = dlopen("libmedia.so", RTLD_LAZY);
+  if (!ctx->lib || !ctx->libmedia) {
     free(ctx);
     return CUBEB_ERROR;
   }
 
+  /* Get the latency, in ms, from AudioFlinger */
+  /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
+   *                                        audio_stream_type_t streamType) */
+  /* First, try the most recent signature. */
+  ctx->get_output_latency =
+    dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t");
+  if (!ctx->get_output_latency) {
+    /* in case of failure, try the legacy version. */
+    /* status_t AudioSystem::getOutputLatency(uint32_t* latency,
+     *                                        int streamType) */
+    ctx->get_output_latency =
+      dlsym(ctx->libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji");
+    if (!ctx->get_output_latency) {
+      opensl_destroy(ctx);
+      return CUBEB_ERROR;
+    }
+  }
+
   typedef SLresult (*slCreateEngine_t)(SLObjectItf *,
                                        SLuint32,
                                        const SLEngineOption *,
                                        SLuint32,
                                        const SLInterfaceID *,
                                        const SLboolean *);
   slCreateEngine_t f_slCreateEngine =
     (slCreateEngine_t)dlsym(ctx->lib, "slCreateEngine");
@@ -736,21 +756,16 @@ opensl_init(cubeb ** context, char const
   }
 
   res = (*ctx->outmixObj)->Realize(ctx->outmixObj, SL_BOOLEAN_FALSE);
   if (res != SL_RESULT_SUCCESS) {
     opensl_destroy(ctx);
     return CUBEB_ERROR;
   }
 
-  ctx->jni_obj = cubeb_jni_init();
-  if (!ctx->jni_obj) {
-    LOG("Warning: jni is not initialized, cubeb_stream_get_position() is not supported");
-  }
-
   *context = ctx;
 
   LOG("Cubeb init (%p) success", ctx);
   return CUBEB_OK;
 }
 
 static char const *
 opensl_get_backend_id(cubeb * ctx)
@@ -764,26 +779,143 @@ opensl_get_max_channel_count(cubeb * ctx
   assert(ctx && max_channels);
   /* The android mixer handles up to two channels, see
      http://androidxref.com/4.2.2_r1/xref/frameworks/av/services/audioflinger/AudioFlinger.h#67 */
   *max_channels = 2;
 
   return CUBEB_OK;
 }
 
+static int
+opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
+{
+  /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
+   * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
+   * so we just dlopen the library and get the two symbols we need. */
+  int r;
+  void * libmedia;
+  uint32_t (*get_primary_output_samplingrate)();
+  uint32_t (*get_output_samplingrate)(int * samplingRate, int streamType);
+
+  libmedia = dlopen("libmedia.so", RTLD_LAZY);
+  if (!libmedia) {
+    return CUBEB_ERROR;
+  }
+
+  /* uint32_t AudioSystem::getPrimaryOutputSamplingRate(void) */
+  get_primary_output_samplingrate =
+    dlsym(libmedia, "_ZN7android11AudioSystem28getPrimaryOutputSamplingRateEv");
+  if (!get_primary_output_samplingrate) {
+    /* fallback to
+     * status_t AudioSystem::getOutputSamplingRate(int* samplingRate, int streamType)
+     * if we cannot find getPrimaryOutputSamplingRate. */
+    get_output_samplingrate =
+      dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPj19audio_stream_type_t");
+    if (!get_output_samplingrate) {
+      /* Another signature exists, with a int instead of an audio_stream_type_t */
+      get_output_samplingrate =
+        dlsym(libmedia, "_ZN7android11AudioSystem21getOutputSamplingRateEPii");
+      if (!get_output_samplingrate) {
+        dlclose(libmedia);
+        return CUBEB_ERROR;
+      }
+    }
+  }
+
+  if (get_primary_output_samplingrate) {
+    *rate = get_primary_output_samplingrate();
+  } else {
+    /* We don't really know about the type, here, so we just pass music. */
+    r = get_output_samplingrate((int *) rate, AUDIO_STREAM_TYPE_MUSIC);
+    if (r) {
+      dlclose(libmedia);
+      return CUBEB_ERROR;
+    }
+  }
+
+  dlclose(libmedia);
+
+  /* Depending on which method we called above, we can get a zero back, yet have
+   * a non-error return value, especially if the audio system is not
+   * ready/shutting down (i.e. when we can't get our hand on the AudioFlinger
+   * thread). */
+  if (*rate == 0) {
+    return CUBEB_ERROR;
+  }
+
+  return CUBEB_OK;
+}
+
+static int
+opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
+{
+  /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html
+   * We don't want to deal with JNI here (and we don't have Java on b2g anyways),
+   * so we just dlopen the library and get the two symbols we need. */
+
+  int r;
+  void * libmedia;
+  size_t (*get_primary_output_frame_count)(void);
+  int (*get_output_frame_count)(size_t * frameCount, int streamType);
+  uint32_t primary_sampling_rate;
+  size_t primary_buffer_size;
+
+  r = opensl_get_preferred_sample_rate(ctx, &primary_sampling_rate);
+
+  if (r) {
+    return CUBEB_ERROR;
+  }
+
+  libmedia = dlopen("libmedia.so", RTLD_LAZY);
+  if (!libmedia) {
+    return CUBEB_ERROR;
+  }
+
+  /* JB variant */
+  /* size_t AudioSystem::getPrimaryOutputFrameCount(void) */
+  get_primary_output_frame_count =
+    dlsym(libmedia, "_ZN7android11AudioSystem26getPrimaryOutputFrameCountEv");
+  if (!get_primary_output_frame_count) {
+    /* ICS variant */
+    /* status_t AudioSystem::getOutputFrameCount(int* frameCount, int streamType) */
+    get_output_frame_count =
+      dlsym(libmedia, "_ZN7android11AudioSystem19getOutputFrameCountEPii");
+    if (!get_output_frame_count) {
+      dlclose(libmedia);
+      return CUBEB_ERROR;
+    }
+  }
+
+  if (get_primary_output_frame_count) {
+    primary_buffer_size = get_primary_output_frame_count();
+  } else {
+    if (get_output_frame_count(&primary_buffer_size, AUDIO_STREAM_TYPE_MUSIC) != 0) {
+      return CUBEB_ERROR;
+    }
+  }
+
+  /* To get a fast track in Android's mixer, we need to be at the native
+   * samplerate, which is device dependant. Some devices might be able to
+   * resample when playing a fast track, but it's pretty rare. */
+  *latency_frames = primary_buffer_size;
+
+  dlclose(libmedia);
+
+  return CUBEB_OK;
+}
+
 static void
 opensl_destroy(cubeb * ctx)
 {
   if (ctx->outmixObj)
     (*ctx->outmixObj)->Destroy(ctx->outmixObj);
   if (ctx->engObj)
     cubeb_destroy_sles_engine(&ctx->engObj);
   dlclose(ctx->lib);
-  if (ctx->jni_obj)
-    cubeb_jni_destroy(ctx->jni_obj);
+  dlclose(ctx->libmedia);
   free(ctx);
 }
 
 static void opensl_stream_destroy(cubeb_stream * stm);
 
 static int
 opensl_set_format(SLDataFormat_PCM * format, cubeb_stream_params * params)
 {
@@ -860,19 +992,23 @@ opensl_configure_capture(cubeb_stream * 
                                                            lSoundRecorderReqs);
   // Sample rate not supported. Try again with default sample rate!
   if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
     if (stm->output_enabled && stm->output_configured_rate != 0) {
       // Set the same with the player. Since there is no
       // api for input device this is a safe choice.
       stm->input_device_rate = stm->output_configured_rate;
     } else  {
-      // The output preferred rate is used for an input only scenario.
-      // The default rate expected to be supported from all android devices.
-      stm->input_device_rate = DEFAULT_SAMPLE_RATE;
+      // The output preferred rate is used for input only scenario. This is
+      // the correct rate to use to get a fast track for input only.
+      r = opensl_get_preferred_sample_rate(stm->context, &stm->input_device_rate);
+      if (r != CUBEB_OK) {
+        // If everything else fail use a safe choice for Android.
+        stm->input_device_rate = DEFAULT_SAMPLE_RATE;
+      }
     }
     lDataFormat.samplesPerSec = stm->input_device_rate * 1000;
     res = (*stm->context->eng)->CreateAudioRecorder(stm->context->eng,
                                                     &stm->recorderObj,
                                                     &lDataSource,
                                                     &lDataSink,
                                                     lSoundRecorderIIDCount,
                                                     lSoundRecorderIIDs,
@@ -973,17 +1109,17 @@ opensl_configure_capture(cubeb_stream * 
   return CUBEB_OK;
 }
 
 static int
 opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
   assert(stm);
   assert(params);
 
-  stm->user_output_rate = params->rate;
+  stm->inputrate = params->rate;
   stm->framesize = params->channels * sizeof(int16_t);
   stm->lastPosition = -1;
   stm->lastPositionTimeStamp = 0;
   stm->lastCompensativePosition = -1;
 
   SLDataFormat_PCM format;
   int r = opensl_set_format(&format, params);
   if (r != CUBEB_OK) {
@@ -1010,32 +1146,48 @@ opensl_configure_playback(cubeb_stream *
                                stm->context->SL_IID_ANDROIDCONFIGURATION};
   const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
 #else
   const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_VOLUME};
   const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
 #endif
   assert(NELEMS(ids) == NELEMS(req));
 
-  uint32_t preferred_sampling_rate = stm->user_output_rate;
+  unsigned int latency_frames = stm->latency_frames;
+  uint32_t preferred_sampling_rate = stm->inputrate;
+#if defined(__ANDROID__)
+  if (get_android_version() >= ANDROID_VERSION_MARSHMALLOW) {
+    // Reset preferred samping rate to trigger fallback to native sampling rate.
+    preferred_sampling_rate = 0;
+    if (opensl_get_min_latency(stm->context, *params, &latency_frames) != CUBEB_OK) {
+      // Default to AudioFlinger's advertised fast track latency of 10ms.
+      latency_frames = 440;
+    }
+    stm->latency_frames = latency_frames;
+  }
+#endif
+
   SLresult res = SL_RESULT_CONTENT_UNSUPPORTED;
   if (preferred_sampling_rate) {
     res = (*stm->context->eng)->CreateAudioPlayer(stm->context->eng,
                                                   &stm->playerObj,
                                                   &source,
                                                   &sink,
                                                   NELEMS(ids),
                                                   ids,
                                                   req);
   }
 
   // Sample rate not supported? Try again with primary sample rate!
-  if (res == SL_RESULT_CONTENT_UNSUPPORTED &&
-      preferred_sampling_rate != DEFAULT_SAMPLE_RATE) {
-    preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
+  if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
+    if (opensl_get_preferred_sample_rate(stm->context, &preferred_sampling_rate)) {
+      // If fail default is used
+      preferred_sampling_rate = DEFAULT_SAMPLE_RATE;
+    }
+
     format.samplesPerSec = preferred_sampling_rate * 1000;
     res = (*stm->context->eng)->CreateAudioPlayer(stm->context->eng,
                                                   &stm->playerObj,
                                                   &source,
                                                   &sink,
                                                   NELEMS(ids),
                                                   ids,
                                                   req);
@@ -1043,17 +1195,17 @@ opensl_configure_playback(cubeb_stream *
 
   if (res != SL_RESULT_SUCCESS) {
     LOG("Failed to create audio player. Error code: %lu", res);
     return CUBEB_ERROR;
   }
 
   stm->output_configured_rate = preferred_sampling_rate;
   stm->bytespersec = stm->output_configured_rate * stm->framesize;
-  stm->queuebuf_len = stm->framesize * stm->latency_frames;
+  stm->queuebuf_len = stm->framesize * latency_frames;
 
   // Calculate the capacity of input array
   stm->queuebuf_capacity = NBUFS;
   if (stm->output_enabled) {
     // Full duplex, update capacity to hold 1 sec of data
     stm->queuebuf_capacity = 1 * stm->output_configured_rate / stm->queuebuf_len;
   }
   // Allocate input array
@@ -1180,17 +1332,17 @@ opensl_stream_init(cubeb * ctx, cubeb_st
 
   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->latency_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
+  stm->latency_frames = latency_frames;
   stm->input_enabled = (input_stream_params) ? 1 : 0;
   stm->output_enabled = (output_stream_params) ? 1 : 0;
   stm->shutdown = 1;
 
 #ifdef DEBUG
   pthread_mutexattr_t attr;
   pthread_mutexattr_init(&attr);
   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
@@ -1444,42 +1596,45 @@ opensl_stream_destroy(cubeb_stream * stm
   LOG("Cubeb stream (%p) destroyed", stm);
   free(stm);
 }
 
 static int
 opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   SLmillisecond msec;
-  uint32_t compensation_msec = 0;
+  uint64_t samplerate;
   SLresult res;
-
-  if (!stm->context->jni_obj) {
-    return CUBEB_ERROR_NOT_SUPPORTED;
-  }
+  int r;
+  uint32_t mixer_latency;
+  uint32_t compensation_msec = 0;
 
   res = (*stm->play)->GetPosition(stm->play, &msec);
   if (res != SL_RESULT_SUCCESS)
     return CUBEB_ERROR;
 
   struct timespec t;
   clock_gettime(CLOCK_MONOTONIC, &t);
   if(stm->lastPosition == msec) {
     compensation_msec =
       (t.tv_sec*1000000000LL + t.tv_nsec - stm->lastPositionTimeStamp) / 1000000;
   } else {
     stm->lastPositionTimeStamp = t.tv_sec*1000000000LL + t.tv_nsec;
     stm->lastPosition = msec;
   }
 
-  uint64_t samplerate = stm->user_output_rate;
-  uint32_t mixer_latency = cubeb_get_output_latency_from_jni(stm->context->jni_obj);
+  samplerate = stm->inputrate;
+
+  r = stm->context->get_output_latency(&mixer_latency, AUDIO_STREAM_TYPE_MUSIC);
+  if (r) {
+    return CUBEB_ERROR;
+  }
 
   pthread_mutex_lock(&stm->mutex);
-  int64_t maximum_position = stm->written * (int64_t)stm->user_output_rate / stm->output_configured_rate;
+  int64_t maximum_position = stm->written * (int64_t)stm->inputrate / stm->output_configured_rate;
   pthread_mutex_unlock(&stm->mutex);
   assert(maximum_position >= 0);
 
   if (msec > mixer_latency) {
     int64_t unadjusted_position;
     if (stm->lastCompensativePosition > msec + compensation_msec) {
       // Over compensation, use lastCompensativePosition.
       unadjusted_position =
@@ -1493,16 +1648,34 @@ opensl_stream_get_position(cubeb_stream 
       unadjusted_position : maximum_position;
   } else {
     *position = 0;
   }
   return CUBEB_OK;
 }
 
 int
+opensl_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
+{
+  int r;
+  uint32_t mixer_latency; // The latency returned by AudioFlinger is in ms.
+
+  /* audio_stream_type_t is an int, so this is okay. */
+  r = stm->context->get_output_latency(&mixer_latency, AUDIO_STREAM_TYPE_MUSIC);
+  if (r) {
+    return CUBEB_ERROR;
+  }
+
+  *latency = stm->latency_frames + // OpenSL latency
+    mixer_latency * stm->inputrate / 1000; // AudioFlinger latency
+
+  return CUBEB_OK;
+}
+
+int
 opensl_stream_set_volume(cubeb_stream * stm, float volume)
 {
   SLresult res;
   SLmillibel max_level, millibels;
   float unclamped_millibels;
 
   res = (*stm->volume)->GetMaxVolumeLevel(stm->volume, &max_level);
 
@@ -1527,28 +1700,28 @@ opensl_stream_set_volume(cubeb_stream * 
   }
   return CUBEB_OK;
 }
 
 static struct cubeb_ops const opensl_ops = {
   .init = opensl_init,
   .get_backend_id = opensl_get_backend_id,
   .get_max_channel_count = opensl_get_max_channel_count,
-  .get_min_latency = NULL,
-  .get_preferred_sample_rate = NULL,
+  .get_min_latency = opensl_get_min_latency,
+  .get_preferred_sample_rate = opensl_get_preferred_sample_rate,
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = opensl_destroy,
   .stream_init = opensl_stream_init,
   .stream_destroy = opensl_stream_destroy,
   .stream_start = opensl_stream_start,
   .stream_stop = opensl_stream_stop,
   .stream_reset_default_device = NULL,
   .stream_get_position = opensl_stream_get_position,
-  .stream_get_latency = NULL,
+  .stream_get_latency = opensl_stream_get_latency,
   .stream_set_volume = opensl_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
 };
--- a/media/libcubeb/src/moz.build
+++ b/media/libcubeb/src/moz.build
@@ -72,17 +72,16 @@ if CONFIG['OS_TARGET'] == 'WINNT':
       "avrt",
     ]
     if CONFIG['CC_TYPE'] in ('msvc', 'clang-cl'):
         CXXFLAGS += ['-wd4005'] # C4005: '_USE_MATH_DEFINES' : macro redefinition
 
 if CONFIG['OS_TARGET'] == 'Android':
     SOURCES += ['cubeb_opensl.c']
     SOURCES += ['cubeb_resampler.cpp']
-    SOURCES += ['cubeb-jni.cpp']
     DEFINES['USE_OPENSL'] = True
     SOURCES += [
         'cubeb_audiotrack.c',
     ]
     DEFINES['USE_AUDIOTRACK'] = True
 
 FINAL_LIBRARY = 'gkmedias'
 
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -15,18 +15,16 @@ cp $1/src/cubeb_array_queue.h src
 cp $1/src/cubeb_audiotrack.c src
 cp $1/src/cubeb_audiounit.cpp src
 cp $1/src/cubeb_jack.cpp src
 cp $1/src/cubeb_log.cpp src
 cp $1/src/cubeb_log.h src
 cp $1/src/cubeb_mixer.cpp src
 cp $1/src/cubeb_mixer.h src
 cp $1/src/cubeb_opensl.c src
-cp $1/src/cubeb-jni.cpp src
-cp $1/src/cubeb-jni.h src
 cp $1/src/cubeb_osx_run_loop.h src
 cp $1/src/cubeb_panner.cpp src
 cp $1/src/cubeb_panner.h src
 cp $1/src/cubeb_pulse.c src
 cp $1/src/cubeb_resampler.cpp src
 cp $1/src/cubeb_resampler.h src
 cp $1/src/cubeb_resampler_internal.h src
 cp $1/src/cubeb_ring_array.h src
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -1831,34 +1831,34 @@ public class GeckoAppShell
             final WindowManager wm = (WindowManager)
                     getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
             final Display disp = wm.getDefaultDisplay();
             sScreenSize = new Rect(0, 0, disp.getWidth(), disp.getHeight());
         }
         return sScreenSize;
     }
 
-    @WrapForJNI(calledFrom = "any")
+    @WrapForJNI(calledFrom = "gecko")
     public static int getAudioOutputFramesPerBuffer() {
         if (SysInfo.getVersion() < 17) {
             return 0;
         }
         final AudioManager am = (AudioManager)getApplicationContext()
                                 .getSystemService(Context.AUDIO_SERVICE);
         if (am == null) {
             return 0;
         }
         final String prop = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
         if (prop == null) {
             return 0;
         }
         return Integer.parseInt(prop);
     }
 
-    @WrapForJNI(calledFrom = "any")
+    @WrapForJNI(calledFrom = "gecko")
     public static int getAudioOutputSampleRate() {
         if (SysInfo.getVersion() < 17) {
             return 0;
         }
         final AudioManager am = (AudioManager)getApplicationContext()
                                 .getSystemService(Context.AUDIO_SERVICE);
         if (am == null) {
             return 0;
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -809,17 +809,17 @@ public:
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "getAudioOutputFramesPerBuffer";
         static constexpr char signature[] =
                 "()I";
         static const bool isStatic = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
         static const mozilla::jni::CallingThread callingThread =
-                mozilla::jni::CallingThread::ANY;
+                mozilla::jni::CallingThread::GECKO;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto GetAudioOutputFramesPerBuffer() -> int32_t;
 
     struct GetAudioOutputSampleRate_t {
         typedef GeckoAppShell Owner;
@@ -828,17 +828,17 @@ public:
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "getAudioOutputSampleRate";
         static constexpr char signature[] =
                 "()I";
         static const bool isStatic = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
         static const mozilla::jni::CallingThread callingThread =
-                mozilla::jni::CallingThread::ANY;
+                mozilla::jni::CallingThread::GECKO;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto GetAudioOutputSampleRate() -> int32_t;
 
     struct GetConnection_t {
         typedef GeckoAppShell Owner;