From 5968b0947fe3b53ccd01c6ce3beffefef3ae59a2 Mon Sep 17 00:00:00 2001 From: Narcis Beleuzu Date: Mon, 26 Feb 2018 15:58:20 +0200 Subject: [PATCH] Backed out 10 changesets (bug 1410456) for Android mochitest crashes, e.g. in test_postMessages.html. CLOSED TREE Backed out changeset 7ec175446efd (bug 1410456) Backed out changeset 94457911bb24 (bug 1410456) Backed out changeset 5248a21216ae (bug 1410456) Backed out changeset f182ab7885db (bug 1410456) Backed out changeset e482347bdae3 (bug 1410456) Backed out changeset f7b646045e06 (bug 1410456) Backed out changeset 6a8ed4bf5d2f (bug 1410456) Backed out changeset 1a9c687ec277 (bug 1410456) Backed out changeset 82f6667c6758 (bug 1410456) Backed out changeset 7bf358e3e01b (bug 1410456) --- dom/media/CubebUtils.cpp | 50 +--- dom/media/CubebUtils.h | 7 +- dom/media/GraphDriver.cpp | 10 +- media/libcubeb/README_MOZILLA | 2 +- .../src/android/cubeb-output-latency.h | 76 ------ .../src/android/cubeb_media_library.h | 62 ----- media/libcubeb/src/cubeb-jni-instances.h | 34 --- media/libcubeb/src/cubeb-jni.cpp | 88 ------- media/libcubeb/src/cubeb-jni.h | 10 - media/libcubeb/src/cubeb_opensl.c | 239 +++++++++++++++--- media/libcubeb/src/moz.build | 1 - media/libcubeb/update.sh | 4 - .../java/org/mozilla/gecko/GeckoAppShell.java | 4 +- widget/android/GeneratedJNIWrappers.h | 4 +- 14 files changed, 228 insertions(+), 363 deletions(-) delete mode 100644 media/libcubeb/src/android/cubeb-output-latency.h delete mode 100644 media/libcubeb/src/android/cubeb_media_library.h delete mode 100644 media/libcubeb/src/cubeb-jni-instances.h delete mode 100644 media/libcubeb/src/cubeb-jni.cpp delete mode 100644 media/libcubeb/src/cubeb-jni.h diff --git a/dom/media/CubebUtils.cpp b/dom/media/CubebUtils.cpp index 4cda851197a7..9c47c2f2ea55 100644 --- a/dom/media/CubebUtils.cpp +++ b/dom/media/CubebUtils.cpp @@ -25,9 +25,6 @@ #include "prdtoa.h" #include #include -#ifdef MOZ_WIDGET_ANDROID -#include "GeneratedJNIWrappers.h" -#endif #define PREF_VOLUME_SCALE "media.volume_scale" #define PREF_CUBEB_BACKEND "media.cubeb.backend" @@ -122,8 +119,8 @@ 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; @@ -308,15 +305,11 @@ bool InitPreferredSampleRate() 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; } @@ -534,28 +527,14 @@ bool CubebMSGLatencyPrefSet() return sCubebMSGLatencyPrefSet; } -uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params) +Maybe GetCubebMSGLatencyInFrames() { StaticMutexAutoLock lock(sMutex); - if (sCubebMSGLatencyPrefSet) { - MOZ_ASSERT(sCubebMSGLatencyInFrames > 0); - return sCubebMSGLatencyInFrames; + if (!sCubebMSGLatencyPrefSet) { + return Maybe(); } - -#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() @@ -762,20 +741,5 @@ void GetDeviceCollection(nsTArray>& aDeviceInfos, } } -#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 diff --git a/dom/media/CubebUtils.h b/dom/media/CubebUtils.h index 79f52d9714e6..60e9eb1e477e 100644 --- a/dom/media/CubebUtils.h +++ b/dom/media/CubebUtils.h @@ -44,7 +44,7 @@ cubeb* GetCubebContext(); void ReportCubebStreamInitFailure(bool aIsFirstStream); void ReportCubebBackendUsed(); uint32_t GetCubebPlaybackLatencyInMilliseconds(); -uint32_t GetCubebMSGLatencyInFrames(cubeb_stream_params * params); +Maybe GetCubebMSGLatencyInFrames(); bool CubebLatencyPrefSet(); cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap); void GetCurrentBackend(nsAString& aBackend); @@ -52,11 +52,6 @@ void GetPreferredChannelLayout(nsAString& aLayout); void GetDeviceCollection(nsTArray>& 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 diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 62d10cce42c6..f3d8c05d6be5 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -599,6 +599,7 @@ AudioCallbackDriver::Init() cubeb_stream_params output; cubeb_stream_params input; + uint32_t latency_frames; bool firstStream = CubebUtils::GetFirstStream(); MOZ_ASSERT(!NS_IsMainThread(), @@ -628,7 +629,14 @@ AudioCallbackDriver::Init() output.layout = CubebUtils::GetPreferredChannelLayoutOrSMPTE(cubebContext, mOutputChannels); output.prefs = CUBEB_STREAM_PREF_NONE; - uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output); + Maybe 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. diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA index 828f2cae534f..e18180d14fb4 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 b1ee1ce7fa7bfb9675e529663f230685125fb694 (2018-02-26 13:40:08 +0200) +The git commit ID used was 1d53c3a3779cbeb860b16aa38cc7f51e196b9745 (2018-02-13 12:30:46 +1000) diff --git a/media/libcubeb/src/android/cubeb-output-latency.h b/media/libcubeb/src/android/cubeb-output-latency.h deleted file mode 100644 index a824fc1c2453..000000000000 --- a/media/libcubeb/src/android/cubeb-output-latency.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _CUBEB_OUTPUT_LATENCY_H_ -#define _CUBEB_OUTPUT_LATENCY_H_ - -#include -#include "cubeb_media_library.h" -#include "../cubeb-jni.h" - -struct output_latency_function { - media_lib * from_lib; - cubeb_jni * from_jni; - int version; -}; - -typedef struct output_latency_function output_latency_function; - -const int ANDROID_JELLY_BEAN_MR1_4_2 = 17; - -output_latency_function * -cubeb_output_latency_load_method(int version) -{ - output_latency_function * ol = NULL; - ol = calloc(1, sizeof(output_latency_function)); - - ol->version = version; - - if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){ - ol->from_jni = cubeb_jni_init(); - return ol; - } - - ol->from_lib = cubeb_load_media_library(); - return ol; -} - -bool -cubeb_output_latency_method_is_loaded(output_latency_function * ol) -{ - assert(ol && (ol->from_jni || ol->from_lib)); - if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){ - return !!ol->from_jni; - } - - return !!ol->from_lib; -} - -void -cubeb_output_latency_unload_method(output_latency_function * ol) -{ - if (!ol) { - return; - } - - if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2 && ol->from_jni) { - cubeb_jni_destroy(ol->from_jni); - } - - if (ol->version <= ANDROID_JELLY_BEAN_MR1_4_2 && ol->from_lib) { - cubeb_close_media_library(ol->from_lib); - } - - free(ol); -} - -uint32_t -cubeb_get_output_latency(output_latency_function * ol) -{ - assert(cubeb_output_latency_method_is_loaded(ol)); - - if (ol->version > ANDROID_JELLY_BEAN_MR1_4_2){ - return cubeb_get_output_latency_from_jni(ol->from_jni); - } - - return cubeb_get_output_latency_from_media_library(ol->from_lib); -} - -#endif // _CUBEB_OUTPUT_LATENCY_H_ diff --git a/media/libcubeb/src/android/cubeb_media_library.h b/media/libcubeb/src/android/cubeb_media_library.h deleted file mode 100644 index ab21b779dfad..000000000000 --- a/media/libcubeb/src/android/cubeb_media_library.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _CUBEB_MEDIA_LIBRARY_H_ -#define _CUBEB_MEDIA_LIBRARY_H_ - -struct media_lib { - void * libmedia; - int32_t (* get_output_latency)(uint32_t * latency, int stream_type); -}; - -typedef struct media_lib media_lib; - -media_lib * -cubeb_load_media_library() -{ - media_lib ml = {0}; - ml.libmedia = dlopen("libmedia.so", RTLD_LAZY); - if (!ml.libmedia) { - return NULL; - } - - // Get the latency, in ms, from AudioFlinger. First, try the most recent signature. - // status_t AudioSystem::getOutputLatency(uint32_t* latency, audio_stream_type_t streamType) - ml.get_output_latency = - dlsym(ml.libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPj19audio_stream_type_t"); - if (!ml.get_output_latency) { - // In case of failure, try the signature from legacy version. - // status_t AudioSystem::getOutputLatency(uint32_t* latency, int streamType) - ml.get_output_latency = - dlsym(ml.libmedia, "_ZN7android11AudioSystem16getOutputLatencyEPji"); - if (!ml.get_output_latency) { - return NULL; - } - } - - media_lib * rv = NULL; - rv = calloc(1, sizeof(media_lib)); - assert(rv); - *rv = ml; - return rv; -} - -void -cubeb_close_media_library(media_lib * ml) -{ - dlclose(ml->libmedia); - ml->libmedia = NULL; - ml->get_output_latency = NULL; - free(ml); -} - -uint32_t -cubeb_get_output_latency_from_media_library(media_lib * ml) -{ - uint32_t latency = 0; - const int audio_stream_type_music = 3; - int32_t r = ml->get_output_latency(&latency, audio_stream_type_music); - if (r) { - return 0; - } - return latency; -} - -#endif // _CUBEB_MEDIA_LIBRARY_H_ diff --git a/media/libcubeb/src/cubeb-jni-instances.h b/media/libcubeb/src/cubeb-jni-instances.h deleted file mode 100644 index dad62e4d3357..000000000000 --- 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_ diff --git a/media/libcubeb/src/cubeb-jni.cpp b/media/libcubeb/src/cubeb-jni.cpp deleted file mode 100644 index 3eba97d74dcc..000000000000 --- a/media/libcubeb/src/cubeb-jni.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include "jni.h" -#include -#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(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(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; -} diff --git a/media/libcubeb/src/cubeb-jni.h b/media/libcubeb/src/cubeb-jni.h deleted file mode 100644 index 8c7ddb6acf4d..000000000000 --- 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_ diff --git a/media/libcubeb/src/cubeb_opensl.c b/media/libcubeb/src/cubeb_opensl.c index a760fd8111ef..8e9d4c73f2d6 100644 --- a/media/libcubeb/src/cubeb_opensl.c +++ b/media/libcubeb/src/cubeb_opensl.c @@ -26,7 +26,6 @@ #include "cubeb_resampler.h" #include "cubeb-sles.h" #include "cubeb_array_queue.h" -#include "android/cubeb-output-latency.h" #if defined(__ANDROID__) #ifdef LOG @@ -62,13 +61,14 @@ #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__) @@ -80,11 +80,11 @@ struct cubeb { SLObjectItf engObj; SLEngineItf eng; SLObjectItf outmixObj; - output_latency_function * p_output_latency_function; }; #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. */ @@ -153,7 +153,7 @@ struct cubeb_stream { 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; @@ -236,6 +236,7 @@ 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: @@ -667,11 +668,30 @@ opensl_init(cubeb ** context, char const * context_name) 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 *, @@ -741,11 +761,6 @@ opensl_init(cubeb ** context, char const * context_name) return CUBEB_ERROR; } - ctx->p_output_latency_function = cubeb_output_latency_load_method(android_version); - if (!ctx->p_output_latency_function) { - LOG("Warning: output latency is not available, cubeb_stream_get_position() is not supported"); - } - *context = ctx; LOG("Cubeb init (%p) success", ctx); @@ -769,6 +784,124 @@ opensl_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) 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) { @@ -777,8 +910,7 @@ opensl_destroy(cubeb * ctx) if (ctx->engObj) cubeb_destroy_sles_engine(&ctx->engObj); dlclose(ctx->lib); - if (ctx->p_output_latency_function) - cubeb_output_latency_unload_method(ctx->p_output_latency_function); + dlclose(ctx->libmedia); free(ctx); } @@ -865,9 +997,13 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params) // 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, @@ -978,7 +1114,7 @@ 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; @@ -1015,7 +1151,20 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) { #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, @@ -1028,9 +1177,12 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) { } // 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, @@ -1048,7 +1200,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) { 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; @@ -1185,7 +1337,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name 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; @@ -1449,12 +1601,11 @@ 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 (!cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) { - 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) @@ -1470,11 +1621,15 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position) stm->lastPosition = msec; } - uint64_t samplerate = stm->user_output_rate; - uint32_t mixer_latency = cubeb_get_output_latency(stm->context->p_output_latency_function); + 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); @@ -1497,6 +1652,24 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position) 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) { @@ -1532,8 +1705,8 @@ 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, @@ -1544,7 +1717,7 @@ static struct cubeb_ops const opensl_ops = { .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, diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build index 15071f147ab8..6484e61fa915 100644 --- a/media/libcubeb/src/moz.build +++ b/media/libcubeb/src/moz.build @@ -77,7 +77,6 @@ if CONFIG['OS_TARGET'] == 'WINNT': 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', diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh index 0b33550a4923..827a0db37c50 100755 --- a/media/libcubeb/update.sh +++ b/media/libcubeb/update.sh @@ -20,10 +20,6 @@ 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/android/cubeb-output-latency.h src/android -cp $1/src/android/cubeb_media_library.h src/android cp $1/src/cubeb_osx_run_loop.h src cp $1/src/cubeb_panner.cpp src cp $1/src/cubeb_panner.h src diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 7dbb286cae04..d17c70913354 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -1836,7 +1836,7 @@ public class GeckoAppShell return sScreenSize; } - @WrapForJNI(calledFrom = "any") + @WrapForJNI(calledFrom = "gecko") public static int getAudioOutputFramesPerBuffer() { if (SysInfo.getVersion() < 17) { return 0; @@ -1853,7 +1853,7 @@ public class GeckoAppShell return Integer.parseInt(prop); } - @WrapForJNI(calledFrom = "any") + @WrapForJNI(calledFrom = "gecko") public static int getAudioOutputSampleRate() { if (SysInfo.getVersion() < 17) { return 0; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 46c780942619..3eb178b0894e 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -814,7 +814,7 @@ public: 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; }; @@ -833,7 +833,7 @@ public: 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; };