/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "DeviceAsWebcamNative" #include #include #include #include "DeviceAsWebcamNative.h" /** * Called by the JVM when JNI is loaded. This does not imply that the service is actually running, * only that the jni library is loaded. */ jint JNI_OnLoad(JavaVM* jvm, void*) { using namespace android::webcam; JNIEnv* e = NULL; if (jvm->GetEnv((void**)&e, JNI_VERSION_1_6)) { return JNI_ERR; } if (DeviceAsWebcamNative::registerJNIMethods(e, jvm)) { return JNI_ERR; } return JNI_VERSION_1_6; } namespace android { namespace webcam { // These will be initialized by registerJNIMethods JavaMethods DeviceAsWebcamNative::kJavaMethods = {}; JavaVM* DeviceAsWebcamNative::kJVM = nullptr; static inline jclass FindClassOrDie(JNIEnv* env, const char* class_name) { jclass clazz = env->FindClass(class_name); LOG_ALWAYS_FATAL_IF(clazz == nullptr, "Unable to find class %s", class_name); return clazz; } static inline jmethodID GetMethodIdOrDie(JNIEnv* env, jclass clazz, const char* method_name, const char* method_signature) { jmethodID res = env->GetMethodID(clazz, method_name, method_signature); LOG_ALWAYS_FATAL_IF(res == nullptr, "Unable to find method %s with signature %s", method_name, method_signature); return res; } const JNINativeMethod DeviceAsWebcamNative::sMethods[] = { {"setupServicesAndStartListeningNative", "()I", (void*)com_android_DeviceAsWebcam_setupServicesAndStartListening}, {"nativeOnDestroy", "()V", (void*)com_android_DeviceAsWebcam_onDestroy}, {"shouldStartServiceNative", "()Z", (void*)com_android_DeviceAsWebcam_shouldStartService}, {"nativeEncodeImage", "(Landroid/hardware/HardwareBuffer;J)I", (void*)com_android_DeviceAsWebcam_encodeImage}, }; int DeviceAsWebcamNative::registerJNIMethods(JNIEnv* e, JavaVM* jvm) { char clsName[] = "com/android/DeviceAsWebcam/DeviceAsWebcamFgService"; int ret = jniRegisterNativeMethods(e, clsName, sMethods, NELEM(sMethods)); if (ret) { return JNI_ERR; } jclass clazz = FindClassOrDie(e, clsName); kJavaMethods.setStreamConfig = GetMethodIdOrDie(e, clazz, "setStreamConfig", "(ZIII)V"); kJavaMethods.startStreaming = GetMethodIdOrDie(e, clazz, "startStreaming", "()V"); kJavaMethods.stopStreaming = GetMethodIdOrDie(e, clazz, "stopStreaming", "()V"); kJavaMethods.stopService = GetMethodIdOrDie(e, clazz, "stopService", "()V"); kJavaMethods.returnImage = GetMethodIdOrDie(e, clazz, "returnImage", "(J)V"); kJVM = jvm; return 0; } jint DeviceAsWebcamNative::com_android_DeviceAsWebcam_encodeImage(JNIEnv* env, jobject, jobject hardwareBuffer, jlong timestamp) { return DeviceAsWebcamServiceManager::kInstance->encodeImage(env, hardwareBuffer, timestamp); } jint DeviceAsWebcamNative::com_android_DeviceAsWebcam_setupServicesAndStartListening(JNIEnv* env, jobject thiz) { return DeviceAsWebcamServiceManager::kInstance->setupServicesAndStartListening(env, thiz); } jboolean DeviceAsWebcamNative::com_android_DeviceAsWebcam_shouldStartService(JNIEnv*, jclass) { return DeviceAsWebcamServiceManager::kInstance->shouldStartService(); } void DeviceAsWebcamNative::com_android_DeviceAsWebcam_onDestroy(JNIEnv*, jobject) { DeviceAsWebcamServiceManager::kInstance->onDestroy(); } void DeviceAsWebcamNative::setStreamConfig(jobject thiz, bool mjpeg, uint32_t width, uint32_t height, uint32_t fps) { JNIEnv* env = getJNIEnvOrAbort(); jboolean jMjpeg = mjpeg ? JNI_TRUE : JNI_FALSE; jint jWidth = static_cast(width); jint jHeight = static_cast(height); jint jFps = static_cast(fps); env->CallVoidMethod(thiz, kJavaMethods.setStreamConfig, jMjpeg, jWidth, jHeight, jFps); } void DeviceAsWebcamNative::startStreaming(jobject thiz) { JNIEnv* env = getJNIEnvOrAbort(); env->CallVoidMethod(thiz, kJavaMethods.startStreaming); } void DeviceAsWebcamNative::stopStreaming(jobject thiz) { JNIEnv* env = getJNIEnvOrAbort(); env->CallVoidMethod(thiz, kJavaMethods.stopStreaming); } void DeviceAsWebcamNative::returnImage(jobject thiz, long timestamp) { JNIEnv* env = getJNIEnvOrAbort(); jlong jTimestamp = static_cast(timestamp); env->CallVoidMethod(thiz, kJavaMethods.returnImage, jTimestamp); } void DeviceAsWebcamNative::stopService(jobject thiz) { JNIEnv* env = getJNIEnvOrAbort(); env->CallVoidMethod(thiz, kJavaMethods.stopService); } JNIEnv* DeviceAsWebcamNative::getJNIEnvOrAbort() { JNIEnv* env = nullptr; kJVM->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6); if (env == nullptr) { ALOGE("%s: Called from a thread not bound to the JVM", __FUNCTION__); // Call abort() to force creation of a tombstone for easier debugging. abort(); // :( } return env; } } // namespace webcam } // namespace android