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