Move ownership of AudioEngine object into Java
diff --git a/samples/MegaDrone/src/main/cpp/native-lib.cpp b/samples/MegaDrone/src/main/cpp/native-lib.cpp
index aaca8b7..294790d 100644
--- a/samples/MegaDrone/src/main/cpp/native-lib.cpp
+++ b/samples/MegaDrone/src/main/cpp/native-lib.cpp
@@ -19,8 +19,7 @@
 #include <vector>
 
 #include "AudioEngine.h"
-
-std::unique_ptr<AudioEngine> engine;
+#include "../../../../../src/common/OboeDebug.h"
 
 std::vector<int> convertJavaArrayToVector(JNIEnv *env, jintArray intArray){
 
@@ -37,26 +36,70 @@
     return v;
 }
 
-extern "C"
-JNIEXPORT void JNICALL
-Java_com_example_oboe_megadrone_MainActivity_startEngine(JNIEnv *env, jobject instance,
+extern "C" {
+
+/**
+ * Start the audio engine
+ *
+ * @param env
+ * @param instance
+ * @param jCpuIds - CPU core IDs which the audio process should affine to
+ * @return a pointer to the audio engine. This should be passed to other methods
+ */
+JNIEXPORT jlong JNICALL
+Java_com_example_oboe_megadrone_MainActivity_startEngine(JNIEnv *env, jobject /*unused*/,
                                                          jintArray jCpuIds) {
-    engine = std::make_unique<AudioEngine>();
-    std::vector<int> cpuIds = convertJavaArrayToVector(env, jCpuIds);
-    engine->start(cpuIds);
+    // We use std::nothrow so `new` returns a nullptr if the engine creation fails
+    AudioEngine *engine = new(std::nothrow) AudioEngine();
+    if (engine) {
+        std::vector<int> cpuIds = convertJavaArrayToVector(env, jCpuIds);
+        engine->start(cpuIds);
+        LOGD("Engine started");
+    } else {
+        LOGE("Failed to create audio engine");
+    }
+    return reinterpret_cast<jlong>(engine);
 }
 
-extern "C"
+/**
+ * Stop the audio engine
+ *
+ * @param env
+ * @param instance
+ * @param jEngineHandle - pointer to the audio engine
+ */
 JNIEXPORT void JNICALL
-Java_com_example_oboe_megadrone_MainActivity_stopEngine(JNIEnv *env, jobject instance) {
-
-    engine->stop();
+Java_com_example_oboe_megadrone_MainActivity_stopEngine( JNIEnv * /*unused*/, jobject /*unused*/,
+                                                         jlong jEngineHandle) {
+    auto *engine = reinterpret_cast<AudioEngine *>(jEngineHandle);
+    if (engine) {
+        engine->stop();
+        delete engine;
+        LOGD("Engine stopped");
+    } else {
+        LOGE("Engine handle is invalid, call startEngine() to create a new one");
+        return;
+    }
 }
 
-
-extern "C"
+/**
+ * Send a tap event to the audio engine
+ *
+ * @param env
+ * @param instance
+ * @param jEngineHandle - pointer to audio engine
+ * @param isDown - true if user is tapping down on screen, false user is lifting finger off screen
+ */
 JNIEXPORT void JNICALL
-Java_com_example_oboe_megadrone_MainActivity_tap(JNIEnv *env, jobject instance, jboolean b) {
+Java_com_example_oboe_megadrone_MainActivity_tap(JNIEnv * /*unused*/, jobject /*unused*/,
+                                                 jlong jEngineHandle,
+                                                 jboolean isDown) {
+    auto *engine = reinterpret_cast<AudioEngine *>(jEngineHandle);
+    if (engine){
+        engine->tap(isDown);
+    } else {
+        LOGE("Engine handle is invalid, call createEngine() to create a new one");
+    }
+}
 
-    engine->tap(b);
-}
\ No newline at end of file
+} // extern "C"
\ No newline at end of file
diff --git a/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java b/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java
index 4c8f6b5..b1a8424 100644
--- a/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java
+++ b/samples/MegaDrone/src/main/java/com/example/oboe/megadrone/MainActivity.java
@@ -25,6 +25,11 @@
 public class MainActivity extends AppCompatActivity {
 
     private final String TAG = MainActivity.class.toString();
+    private static long mEngineHandle = 0;
+
+    private native long startEngine(int[] cpuIds);
+    private native void stopEngine(long engineHandle);
+    private native void tap(long engineHandle, boolean isDown);
 
     // Used to load the 'native-lib' library on application startup.
     static {
@@ -35,32 +40,29 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
+
     }
 
+    @Override
     protected void onResume(){
+        mEngineHandle = startEngine(getExclusiveCores());
         super.onResume();
-        startEngine(getExclusiveCores());
     }
 
+    @Override
     protected void onPause(){
-        stopEngine();
+        stopEngine(mEngineHandle);
         super.onPause();
     }
 
-    private native void stopEngine();
-
-    private native void startEngine(int[] cpuIds);
-
     @Override
     public boolean onTouchEvent(MotionEvent event) {
 
         if (event.getAction() == MotionEvent.ACTION_DOWN){
-            tap(true);
+            tap(mEngineHandle, true);
         } else if (event.getAction() == MotionEvent.ACTION_UP){
-            tap(false);
+            tap(mEngineHandle, false);
         }
-
-
         return super.onTouchEvent(event);
     }
 
@@ -68,7 +70,7 @@
     // bound to these cores to avoids the risk of it being migrated to slower or more contended
     // core(s).
     private int[] getExclusiveCores(){
-        int exclusiveCores[] = {};
+        int[] exclusiveCores = {};
 
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
             Log.w(TAG, "getExclusiveCores() not supported. Only available on API " +
@@ -82,10 +84,6 @@
         }
         return exclusiveCores;
     }
-
-    private native void tap(boolean b);
-
-
 }