Bug 1410456 - Keep the old mechanism for the older versions that jni method is not available. r?padenot draft
authorAlex Chronopoulos <achronop@gmail.com>
Tue, 27 Feb 2018 13:37:37 +0200
changeset 760842 3ba309225793cbab63686259ebae8249693f76a1
parent 758415 14735f6cd5452ece842537474998fbc3108bd6f3
child 760843 6f1206ac519752217e61af80885f5947bb69b84e
push id100767
push userachronop@gmail.com
push dateWed, 28 Feb 2018 10:03:58 +0000
reviewerspadenot
bugs1410456
milestone60.0a1
Bug 1410456 - Keep the old mechanism for the older versions that jni method is not available. r?padenot MozReview-Commit-ID: 3jXf3wuXqZu
media/libcubeb/src/android/cubeb-output-latency.h
media/libcubeb/src/android/cubeb_media_library.h
media/libcubeb/src/cubeb_opensl.c
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;