From 03b0768c574ab3aaa6b0877e9f85cc0df329d0ce Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Wed, 4 Apr 2018 09:55:22 +0200 Subject: [PATCH 1/2] #68 - Camera does not get reclaimed --- src/android/OpenTokAndroidPlugin.java | 94 +++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/src/android/OpenTokAndroidPlugin.java b/src/android/OpenTokAndroidPlugin.java index 3f307c1a..c532407d 100644 --- a/src/android/OpenTokAndroidPlugin.java +++ b/src/android/OpenTokAndroidPlugin.java @@ -24,6 +24,7 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.graphics.Color; +import android.hardware.camera2.CameraManager; import android.util.Log; import android.util.DisplayMetrics; import android.view.View; @@ -45,6 +46,7 @@ import com.opentok.android.Subscriber; import com.opentok.android.SubscriberKit; import com.opentok.android.BaseVideoRenderer; +import com.opentok.android.BaseVideoCapturer; public class OpenTokAndroidPlugin extends CordovaPlugin implements Session.SessionListener, @@ -78,6 +80,8 @@ public class OpenTokAndroidPlugin extends CordovaPlugin public static final String[] perms = {Manifest.permission.INTERNET, Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO}; public CallbackContext permissionsCallback; + public boolean inBackground = false; + public boolean claimedInBackground = false; public class RunnableUpdateViews implements Runnable { public JSONArray mProperty; @@ -124,6 +128,16 @@ public int getZIndex() { } } + public void removeView() { + cordova.getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + ViewGroup parent = (ViewGroup) webView.getView().getParent(); + parent.removeView(mView); + } + }); + } + @SuppressLint("NewApi") @Override public void run() { @@ -169,6 +183,50 @@ public class RunnablePublisher extends RunnableUpdateViews implements audioFallbackEnabled, audioBitrate, audioSource, videoSource, frameRate, cameraResolution] */ public Publisher mPublisher; + public boolean publishing = false; + public boolean oldPublishVideoState = false; + + private final CameraManager.AvailabilityCallback cameraAvailableCallback = new CameraManager.AvailabilityCallback() { + @Override + public void onCameraAvailable(String cameraId) { + super.onCameraAvailable(cameraId); + if(mPublisher != null && publishing) { + BaseVideoCapturer bvc = mPublisher.getCapturer(); + // If not yet capturing.. Initialize and start capturing.. + if (bvc != null && !bvc.isCaptureStarted()) { + Log.i(TAG, "Camera available"); + try { + // Camera claimed in background. + if(inBackground) { + claimedInBackground = true; + } + bvc.init(); + bvc.startCapture(); + mPublisher.setPublishVideo(oldPublishVideoState); + } catch(Exception e) { + + } + } + } + } + + @Override + public void onCameraUnavailable(String cameraId) { + super.onCameraUnavailable(cameraId); + // If app is in background, and not camera yet claimed by us in background.. release camera. + if(mPublisher != null && inBackground && !claimedInBackground) { + BaseVideoCapturer bvc = mPublisher.getCapturer(); + // If still capturing, stop it and release. + if(bvc != null && bvc.isCaptureStarted() ){ + Log.i(TAG, "Camera unavailable"); + oldPublishVideoState = mPublisher.getPublishVideo(); + bvc.stopCapture(); + bvc.destroy(); + mPublisher.setPublishVideo(false); + } + } + } + }; public RunnablePublisher(JSONArray args) { this.mProperty = args; @@ -228,21 +286,31 @@ public RunnablePublisher(JSONArray args) { mPublisher.setPublishVideo(publishVideo); mPublisher.setPublishAudio(publishAudio); + oldPublishVideoState = publishVideo; + if (cameraName.equals("back")) { mPublisher.cycleCamera(); } + + CameraManager manager = (CameraManager) cordova.getActivity().getSystemService(Context.CAMERA_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + manager.registerAvailabilityCallback(cameraAvailableCallback, null); + } } + public void setPropertyFromArray(JSONArray args) { this.mProperty = args; } public void startPublishing() { + publishing = true; mSession.publish(mPublisher); cordova.getActivity().runOnUiThread(this); } public void stopPublishing() { + publishing = false; ViewGroup parent = (ViewGroup) webView.getView().getParent(); parent.removeView(this.mView); if(this.mPublisher != null){ @@ -255,8 +323,12 @@ public void stopPublishing() { } public void destroyPublisher() { - ViewGroup parent = (ViewGroup) webView.getView().getParent(); - parent.removeView(this.mView); + CameraManager manager = (CameraManager) cordova.getActivity().getSystemService(Context.CAMERA_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + manager.unregisterAvailabilityCallback(cameraAvailableCallback); + } + + this.removeView(); if (this.mPublisher != null) { this.mPublisher.destroy(); this.mPublisher = null; @@ -361,8 +433,7 @@ public void setPropertyFromArray(JSONArray args) { } public void removeStreamView() { - ViewGroup parent = (ViewGroup) webView.getView().getParent(); - parent.removeView(this.mView); + this.removeView(); if(mSubscriber != null) { try { mSession.unsubscribe(mSubscriber); @@ -678,6 +749,21 @@ public void onRequestPermissionResult(int requestCode, String[] permissions, int } } + @Override + public void onPause(boolean multitasking) { + super.onPause(multitasking); + inBackground = true; + Log.i(TAG, "Pause"); + } + + @Override + public void onResume(boolean multitasking) { + super.onResume(multitasking); + inBackground = false; + Log.i(TAG, "Resume"); + claimedInBackground = false; // We are on foreground, so its now claimed in foreground. + } + public void alertUser(String message) { // 1. Instantiate an AlertDialog.Builder with its constructor AlertDialog.Builder builder = new AlertDialog.Builder(cordova.getActivity()); From 1491f55ad6ddeacf3ac7ca778c8d13f95fe87a62 Mon Sep 17 00:00:00 2001 From: Jochum van der Ploeg Date: Tue, 1 May 2018 10:19:31 +0200 Subject: [PATCH 2/2] #68 - Added correct remove(thread) in the stopPublishing method. --- src/android/OpenTokAndroidPlugin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/android/OpenTokAndroidPlugin.java b/src/android/OpenTokAndroidPlugin.java index c532407d..3d63774d 100644 --- a/src/android/OpenTokAndroidPlugin.java +++ b/src/android/OpenTokAndroidPlugin.java @@ -311,8 +311,7 @@ public void startPublishing() { public void stopPublishing() { publishing = false; - ViewGroup parent = (ViewGroup) webView.getView().getParent(); - parent.removeView(this.mView); + this.removeView(); if(this.mPublisher != null){ try { mSession.unpublish(this.mPublisher);