mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
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)
This commit is contained in:
parent
c597c8df87
commit
5968b0947f
@ -25,9 +25,6 @@
|
||||
#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"
|
||||
@ -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<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()
|
||||
@ -762,20 +741,5 @@ void GetDeviceCollection(nsTArray<RefPtr<AudioDeviceInfo>>& 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
|
||||
|
@ -44,7 +44,7 @@ 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);
|
||||
@ -52,11 +52,6 @@ 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
|
||||
|
||||
|
@ -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<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.
|
||||
|
@ -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)
|
||||
|
@ -1,76 +0,0 @@
|
||||
#ifndef _CUBEB_OUTPUT_LATENCY_H_
|
||||
#define _CUBEB_OUTPUT_LATENCY_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#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_
|
@ -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_
|
@ -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_
|
@ -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;
|
||||
}
|
@ -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_
|
@ -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,
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user