1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <jni.h> 20 #include <thread> 21 22 namespace android { 23 namespace webcam { 24 25 typedef struct { 26 jmethodID setStreamConfig; 27 jmethodID startStreaming; 28 jmethodID stopStreaming; 29 jmethodID returnImage; 30 jmethodID stopService; 31 } JavaMethods; 32 33 /** 34 * Container class for java interactions. All interaction to/from java must happen from this class. 35 */ 36 class DeviceAsWebcamNative { 37 public: 38 static const JNINativeMethod sMethods[]; 39 static int registerJNIMethods(JNIEnv* e, JavaVM* jvm); 40 41 static JavaVM* kJVM; 42 43 // Native implementations of Java Methods. 44 static jint com_android_DeviceAsWebcam_encodeImage(JNIEnv* env, jobject thiz, 45 jobject hardwareBuffer, jlong timestamp, 46 jint rotation); 47 static jint com_android_DeviceAsWebcam_setupServicesAndStartListening(JNIEnv*, jobject, 48 jobjectArray); 49 static jboolean com_android_DeviceAsWebcam_shouldStartService(JNIEnv*, jclass, jobjectArray); 50 static void com_android_DeviceAsWebcam_onDestroy(JNIEnv*, jobject); 51 52 // Methods that call back into java code. The method signatures match their java counterparts 53 // All threads calling these functions must be bound to kJVM and pass their JNIEnv to 54 // these functions 55 static void setStreamConfig(jobject thiz, bool mjpeg, uint32_t width, uint32_t height, 56 uint32_t fps); 57 static void startStreaming(jobject thiz); 58 static void stopStreaming(jobject thiz); 59 static void returnImage(jobject thiz, long timestamp); 60 static void stopService(jobject thiz); 61 62 // Utility method to get JNIEnv associated with the current thread or abort the program. Care 63 // must be taken to only call this from a thread that is attached to kJVM as it will 64 // terminate the program otherwise. 65 static JNIEnv* getJNIEnvOrAbort(); 66 67 /** 68 * Returns a std::thread can call Java methods in the current JVM. 69 * There is a non-trivial cost to attaching and detaching threads to the JVM, these 70 * threads must not be spammed. Better to have a long running thread that is attached instead. 71 * 72 * Usage: 73 * std::thread myThread = createJniAttachedThread([] () -> { 74 * // Thread logic that might call into java 75 * ... 76 * }); 77 */ 78 template <class F, typename... Args> createJniAttachedThread(F f,Args &&...args)79 static std::thread createJniAttachedThread(F f, Args&&... args) { 80 return std::thread([f, args...]() mutable { 81 // Attach Thread to JVM for java calls 82 JNIEnv* env; 83 ScopedAttach _jniScope(&env); 84 // Call the passed function 85 std::invoke(f, std::forward<Args...>(args...)); 86 // Thread detaches from the JVM automatically when _jniScope goes out of scope 87 }); 88 } 89 90 // Methods that call back into java code 91 // must only be called via their corresponding public methods. 92 static JavaMethods kJavaMethods; 93 94 /** 95 * Class to Provide a RAII style means for attaching the current thread to the JVM. The thread 96 * is attached to the JVM when this object is created, and detached when the object goes out of 97 * scope. 98 */ 99 class ScopedAttach { 100 public: ScopedAttach(JNIEnv ** env)101 explicit ScopedAttach(JNIEnv** env) { kJVM->AttachCurrentThread(env, nullptr); } ~ScopedAttach()102 ~ScopedAttach() { kJVM->DetachCurrentThread(); } 103 }; 104 }; 105 106 } // namespace webcam 107 } // namespace android 108