Audio recorder missing a callback protector

Bug: 14291968
Change-Id: I620d5e82f58e57e87097984a649b5c3a25c42963
diff --git a/src/android/AudioRecorder_to_android.cpp b/src/android/AudioRecorder_to_android.cpp
index ebb9592..800a767 100644
--- a/src/android/AudioRecorder_to_android.cpp
+++ b/src/android/AudioRecorder_to_android.cpp
@@ -212,6 +212,12 @@
     //SL_LOGV("audioRecorder_callback(%d, %p, %p) entering", event, user, info);
 
     CAudioRecorder *ar = (CAudioRecorder *)user;
+
+    if (!android::CallbackProtector::enterCbIfOk(ar->mCallbackProtector)) {
+        // it is not safe to enter the callback (the track is about to go away)
+        return;
+    }
+
     void * callbackPContext = NULL;
 
     switch(event) {
@@ -289,6 +295,8 @@
         break;
 
     }
+
+    ar->mCallbackProtector->exitCb();
 }
 
 
@@ -312,6 +320,7 @@
         // microphone to simple buffer queue
         ar->mAndroidObjType = AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE;
         ar->mAudioRecord.clear();
+        ar->mCallbackProtector = new android::CallbackProtector();
         ar->mRecordSource = AUDIO_SOURCE_DEFAULT;
     } else {
         result = SL_RESULT_CONTENT_UNSUPPORTED;
@@ -430,14 +439,29 @@
 
 
 //-----------------------------------------------------------------------------
+/**
+ * Called with a lock on AudioRecorder, and blocks until safe to destroy
+ */
+void android_audioRecorder_preDestroy(CAudioRecorder* ar) {
+    object_unlock_exclusive(&ar->mObject);
+    if (ar->mCallbackProtector != 0) {
+        ar->mCallbackProtector->requestCbExitAndWait();
+    }
+    object_lock_exclusive(&ar->mObject);
+}
+
+
+//-----------------------------------------------------------------------------
 void android_audioRecorder_destroy(CAudioRecorder* ar) {
     SL_LOGV("android_audioRecorder_destroy(%p) entering", ar);
 
     if (ar->mAudioRecord != 0) {
         ar->mAudioRecord->stop();
+        ar->mAudioRecord.clear();
     }
     // explicit destructor
     ar->mAudioRecord.~sp();
+    ar->mCallbackProtector.~sp();
 
 #ifdef MONITOR_RECORDING
     if (NULL != gMonitorFp) {
diff --git a/src/android/AudioRecorder_to_android.h b/src/android/AudioRecorder_to_android.h
index b8d4dd2..d561ca1 100644
--- a/src/android/AudioRecorder_to_android.h
+++ b/src/android/AudioRecorder_to_android.h
@@ -45,6 +45,8 @@
 
 extern SLresult android_audioRecorder_realize(CAudioRecorder* ar, SLboolean async);
 
+extern void android_audioRecorder_preDestroy(CAudioRecorder* ar);
+
 extern void android_audioRecorder_destroy(CAudioRecorder* ar);
 
 /**************************************************************************************************
diff --git a/src/classes.h b/src/classes.h
index 54ca0e8..f4ac305 100644
--- a/src/classes.h
+++ b/src/classes.h
@@ -153,6 +153,7 @@
     // FIXME consolidate the next several variables into ARecorder class to avoid placement new
     enum AndroidObjectType mAndroidObjType;
     android::sp<android::AudioRecord> mAudioRecord;
+    android::sp<android::CallbackProtector> mCallbackProtector;
     audio_source_t mRecordSource;
 #endif
 } /*CAudioRecorder*/;
diff --git a/src/itf/IEngine.c b/src/itf/IEngine.c
index 38b37dc..4ff32c9 100644
--- a/src/itf/IEngine.c
+++ b/src/itf/IEngine.c
@@ -457,6 +457,8 @@
                     // FIXME unnecessary once those fields are encapsulated in one class, rather
                     //   than a structure
                     (void) new (&thiz->mAudioRecord) android::sp<android::AudioRecord>();
+                    (void) new (&thiz->mCallbackProtector)
+                            android::sp<android::CallbackProtector>();
                     thiz->mRecordSource = AUDIO_SOURCE_DEFAULT;
 #endif
 
diff --git a/src/objects/CAudioRecorder.c b/src/objects/CAudioRecorder.c
index 956e987..6eab0cf 100644
--- a/src/objects/CAudioRecorder.c
+++ b/src/objects/CAudioRecorder.c
@@ -59,5 +59,9 @@
 
 predestroy_t CAudioRecorder_PreDestroy(void *self)
 {
+    CAudioRecorder *thiz = (CAudioRecorder *) self;
+#ifdef ANDROID
+    android_audioRecorder_preDestroy(thiz);
+#endif
     return predestroy_ok;
 }