Bug 1349581: defer nativeRegistration for android Jni to avoid thread issues r=gcp a=lizzard
authorRandell Jesup <rjesup@jesup.org>
Mon, 03 Apr 2017 16:58:44 -0400
changeset 375728 632c2b8c17297a8d4c70fc33a518808d81fc18c7
parent 375727 c549338e76391ddf7725a633bad9dc240ba1ae82
child 375729 2448220fff6bafa99953032e8425fd63f25403bc
push id11018
push userrjesup@wgate.com
push dateWed, 05 Apr 2017 16:24:34 +0000
treeherdermozilla-aurora@632c2b8c1729 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgcp, lizzard
bugs1349581
milestone54.0a2
Bug 1349581: defer nativeRegistration for android Jni to avoid thread issues r=gcp a=lizzard MozReview-Commit-ID: Ep0ej5HkGE3
media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.cc
media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.h
--- a/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.cc
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.cc
@@ -82,41 +82,52 @@ AudioRecordJni::AudioRecordJni(AudioMana
       direct_buffer_capacity_in_bytes_(0),
       frames_per_buffer_(0),
       initialized_(false),
       recording_(false),
       audio_device_buffer_(nullptr) {
   ALOGD("ctor%s", GetThreadInfo().c_str());
   RTC_DCHECK(audio_parameters_.is_valid());
   RTC_CHECK(j_environment_);
-  JNINativeMethod native_methods[] = {
-      {"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
-      reinterpret_cast<void*>(
-          &webrtc::AudioRecordJni::CacheDirectBufferAddress)},
-      {"nativeDataIsRecorded", "(IJ)V",
-      reinterpret_cast<void*>(&webrtc::AudioRecordJni::DataIsRecorded)}};
-  j_native_registration_ = j_environment_->RegisterNatives(
-      "org/webrtc/voiceengine/WebRtcAudioRecord",
-      native_methods, arraysize(native_methods));
-  j_audio_record_.reset(new JavaAudioRecord(
-      j_native_registration_.get(),
-      j_native_registration_->NewObject(
-          "<init>", "(Landroid/content/Context;J)V",
-          JVM::GetInstance()->context(), PointerTojlong(this))));
+  // Defer creation of the j_audio_record object so we can defer native registration.
+  // See Mozilla bug 1349581
+
   // Detach from this thread since we want to use the checker to verify calls
   // from the Java based audio thread.
   thread_checker_java_.DetachFromThread();
 }
 
 AudioRecordJni::~AudioRecordJni() {
   ALOGD("~dtor%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   Terminate();
 }
 
+void
+AudioRecordJni::EnsureRecordObject()
+{
+  if (!j_audio_record_.get()) {
+    RTC_DCHECK(!j_native_registration_.get());
+    JNINativeMethod native_methods[] = {
+      {"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
+      reinterpret_cast<void*>(
+          &webrtc::AudioRecordJni::CacheDirectBufferAddress)},
+      {"nativeDataIsRecorded", "(IJ)V",
+      reinterpret_cast<void*>(&webrtc::AudioRecordJni::DataIsRecorded)}};
+    j_native_registration_ = j_environment_->RegisterNatives(
+      "org/webrtc/voiceengine/WebRtcAudioRecord",
+      native_methods, arraysize(native_methods));
+    j_audio_record_.reset(new JavaAudioRecord(
+      j_native_registration_.get(),
+      j_native_registration_->NewObject(
+      "<init>", "(Landroid/content/Context;J)V",
+      JVM::GetInstance()->context(), PointerTojlong(this))));
+  }
+}
+
 int32_t AudioRecordJni::Init() {
   ALOGD("Init%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   return 0;
 }
 
 int32_t AudioRecordJni::Terminate() {
   ALOGD("Terminate%s", GetThreadInfo().c_str());
@@ -125,16 +136,17 @@ int32_t AudioRecordJni::Terminate() {
   return 0;
 }
 
 int32_t AudioRecordJni::InitRecording() {
   ALOGD("InitRecording%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   RTC_DCHECK(!initialized_);
   RTC_DCHECK(!recording_);
+  EnsureRecordObject();
   int frames_per_buffer = j_audio_record_->InitRecording(
       audio_parameters_.sample_rate(), audio_parameters_.channels());
   if (frames_per_buffer < 0) {
     ALOGE("InitRecording failed!");
     return -1;
   }
   frames_per_buffer_ = static_cast<size_t>(frames_per_buffer);
   ALOGD("frames_per_buffer: %" PRIuS, frames_per_buffer_);
@@ -145,30 +157,32 @@ int32_t AudioRecordJni::InitRecording() 
   return 0;
 }
 
 int32_t AudioRecordJni::StartRecording() {
   ALOGD("StartRecording%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   RTC_DCHECK(initialized_);
   RTC_DCHECK(!recording_);
+  RTC_DCHECK(j_audio_record_.get());
   if (!j_audio_record_->StartRecording()) {
     ALOGE("StartRecording failed!");
     return -1;
   }
   recording_ = true;
   return 0;
 }
 
 int32_t AudioRecordJni::StopRecording() {
   ALOGD("StopRecording%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
   if (!initialized_ || !recording_) {
     return 0;
   }
+  RTC_DCHECK(j_audio_record_.get());
   if (!j_audio_record_->StopRecording()) {
     ALOGE("StopRecording failed!");
     return -1;
   }
   // If we don't detach here, we will hit a RTC_DCHECK in OnDataIsRecorded()
   // next time StartRecording() is called since it will create a new Java
   // thread.
   thread_checker_java_.DetachFromThread();
@@ -192,28 +206,31 @@ void AudioRecordJni::AttachAudioBuffer(A
       audio_manager_->GetDelayEstimateInMilliseconds();
   RTC_DCHECK_GT(total_delay_in_milliseconds_, 0);
   ALOGD("total_delay_in_milliseconds: %d", total_delay_in_milliseconds_);
 }
 
 int32_t AudioRecordJni::EnableBuiltInAEC(bool enable) {
   ALOGD("EnableBuiltInAEC%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  RTC_DCHECK(j_audio_record_.get());
   return j_audio_record_->EnableBuiltInAEC(enable) ? 0 : -1;
 }
 
 int32_t AudioRecordJni::EnableBuiltInAGC(bool enable) {
   ALOGD("EnableBuiltInAGC%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  RTC_DCHECK(j_audio_record_.get());
   return j_audio_record_->EnableBuiltInAGC(enable) ? 0 : -1;
 }
 
 int32_t AudioRecordJni::EnableBuiltInNS(bool enable) {
   ALOGD("EnableBuiltInNS%s", GetThreadInfo().c_str());
   RTC_DCHECK(thread_checker_.CalledOnValidThread());
+  RTC_DCHECK(j_audio_record_.get());
   return j_audio_record_->EnableBuiltInNS(enable) ? 0 : -1;
 }
 
 void JNICALL AudioRecordJni::CacheDirectBufferAddress(
     JNIEnv* env, jobject obj, jobject byte_buffer, jlong nativeAudioRecord) {
   webrtc::AudioRecordJni* this_object =
       reinterpret_cast<webrtc::AudioRecordJni*> (nativeAudioRecord);
   this_object->OnCacheDirectBufferAddress(env, byte_buffer);
--- a/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.h
+++ b/media/webrtc/trunk/webrtc/modules/audio_device/android/audio_record_jni.h
@@ -64,16 +64,18 @@ class AudioRecordJni {
     jmethodID enable_built_in_aec_;
     jmethodID enable_built_in_agc_;
     jmethodID enable_built_in_ns_;
   };
 
   explicit AudioRecordJni(AudioManager* audio_manager);
   ~AudioRecordJni();
 
+  void EnsureRecordObject();
+
   int32_t Init();
   int32_t Terminate();
 
   int32_t InitRecording();
   bool RecordingIsInitialized() const { return initialized_; }
 
   int32_t StartRecording();
   int32_t StopRecording();