Bug 1410456 - Keep the old mechanism for the older versions that jni method is not available. r?padenot
MozReview-Commit-ID: 3jXf3wuXqZu
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/src/android/cubeb-output-latency.h
@@ -0,0 +1,76 @@
+#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_
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/src/android/cubeb_media_library.h
@@ -0,0 +1,62 @@
+#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_
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -21,17 +21,17 @@
#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"
+#include "android/cubeb-output-latency.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)
@@ -75,17 +75,17 @@ struct cubeb {
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;
+ output_latency_function * p_output_latency_function;
};
#define NELEMS(A) (sizeof(A) / sizeof A[0])
#define NBUFS 4
struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
cubeb * context;
@@ -736,19 +736,19 @@ 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");
+ 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);
return CUBEB_OK;
}
@@ -772,18 +772,18 @@ opensl_get_max_channel_count(cubeb * ctx
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);
+ if (ctx->p_output_latency_function)
+ cubeb_output_latency_unload_method(ctx->p_output_latency_function);
free(ctx);
}
static void opensl_stream_destroy(cubeb_stream * stm);
static int
opensl_set_format(SLDataFormat_PCM * format, cubeb_stream_params * params)
{
@@ -1447,17 +1447,17 @@ opensl_stream_destroy(cubeb_stream * stm
static int
opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
{
SLmillisecond msec;
uint32_t compensation_msec = 0;
SLresult res;
- if (!stm->context->jni_obj) {
+ if (!cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
return CUBEB_ERROR_NOT_SUPPORTED;
}
res = (*stm->play)->GetPosition(stm->play, &msec);
if (res != SL_RESULT_SUCCESS)
return CUBEB_ERROR;
struct timespec t;
@@ -1466,17 +1466,17 @@ opensl_stream_get_position(cubeb_stream
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);
+ uint32_t mixer_latency = cubeb_get_output_latency(stm->context->p_output_latency_function);
pthread_mutex_lock(&stm->mutex);
int64_t maximum_position = stm->written * (int64_t)stm->user_output_rate / stm->output_configured_rate;
pthread_mutex_unlock(&stm->mutex);
assert(maximum_position >= 0);
if (msec > mixer_latency) {
int64_t unadjusted_position;