c++ 調用 java
c++ 調用java方法的寫法很繁瑣,webrtc中為了避免大量的重復代碼,自己實現了一套jni的生成替換方法,從而使得代碼看起來更“干凈”,但給看代碼帶來了一些麻煩,記錄一下webrtc Android代碼的jni調用
sdk中有一個jni目錄
我們以一個文件為例 webrtc/sdk/android/src/jni/videoencoderfactorywrapper.cc
可以看到這里面調用了一些jni方法,例如Java_VideoEncoderFactory_createEncode,但我們卻無法找到這個的定義
namespace webrtc { namespace jni { std::unique_ptr<VideoEncoder> VideoEncoderFactoryWrapper::CreateVideoEncoder( const SdpVideoFormat& format) { JNIEnv* jni = AttachCurrentThreadIfNeeded(); ScopedJavaLocalRef<jobject> j_codec_info = SdpVideoFormatToVideoCodecInfo(jni, format); ScopedJavaLocalRef<jobject> encoder = Java_VideoEncoderFactory_createEncoder( jni, encoder_factory_, j_codec_info); if (!encoder.obj()) return nullptr; return JavaToNativeVideoEncoder(jni, encoder); } } // namespace jni } // namespace webrtc
我們可以看到webrtc/sdk/android/api/org/webrtc/mozi/VideoEncoderFactory.java,這里面定義了createEncoder方法,但卻不是我們直接要的Java_VideoEncoderFactory_createEncode方法
public interface VideoEncoderFactory { /** Creates an encoder for the given video codec. */ @Nullable @CalledByNative VideoEncoder createEncoder(VideoCodecInfo info); /** * Enumerates the list of supported video codecs. This method will only be called once and the * result will be cached. */ @CalledByNative VideoCodecInfo[] getSupportedCodecs(); }
我們在編譯的目錄里面搜索,看到有一些相關的jni文件
root@eae2b520e6c8:# find -name "VideoEncoderFactory_jni.h" ./releasearm64/gen/sdk/android/generated_video_jni/jni/VideoEncoderFactory_jni.h ./releasearm64/gen/third_party/webrtc/sdk/android/generated_video_jni/jni/VideoEncoderFactory_jni.h ./releasearm/gen/sdk/android/generated_video_jni/jni/VideoEncoderFactory_jni.h ./releasearm/gen/third_party/webrtc/sdk/android/generated_video_jni/jni/VideoEncoderFactory_jni.h
打開看下內容如下,可以看到我們想要的Java_VideoEncoderFactory_createEncode就在這里了
#ifndef org_webrtc_mozi_VideoEncoderFactory_JNI #define org_webrtc_mozi_VideoEncoderFactory_JNI #include <jni.h> #include "../../../../../../../third_party/webrtc/sdk/android/src/jni/jni_generator_helper.h" // Step 1: Forward declarations. JNI_REGISTRATION_EXPORT extern const char kClassPath_org_webrtc_mozi_VideoEncoderFactory[]; const char kClassPath_org_webrtc_mozi_VideoEncoderFactory[] = "org/webrtc/mozi/VideoEncoderFactory"; // Leaking this jclass as we cannot use LazyInstance from some threads. JNI_REGISTRATION_EXPORT std::atomic<jclass> g_org_webrtc_mozi_VideoEncoderFactory_clazz(nullptr); #ifndef org_webrtc_mozi_VideoEncoderFactory_clazz_defined #define org_webrtc_mozi_VideoEncoderFactory_clazz_defined inline jclass org_webrtc_mozi_VideoEncoderFactory_clazz(JNIEnv* env) { return base::android::LazyGetClass(env, kClassPath_org_webrtc_mozi_VideoEncoderFactory, &g_org_webrtc_mozi_VideoEncoderFactory_clazz); } #endif // Step 2: Constants (optional). // Step 3: Method stubs. namespace webrtc { namespace jni { static std::atomic<jmethodID> g_org_webrtc_mozi_VideoEncoderFactory_createEncoder(nullptr); static base::android::ScopedJavaLocalRef<jobject> Java_VideoEncoderFactory_createEncoder(JNIEnv* env, const base::android::JavaRef<jobject>& obj, const base::android::JavaRef<jobject>& info) { CHECK_CLAZZ(env, obj.obj(), org_webrtc_mozi_VideoEncoderFactory_clazz(env), NULL); jmethodID method_id = base::android::MethodID::LazyGet< base::android::MethodID::TYPE_INSTANCE>( env, org_webrtc_mozi_VideoEncoderFactory_clazz(env), "createEncoder", "(Lorg/webrtc/mozi/VideoCodecInfo;)Lorg/webrtc/mozi/VideoEncoder;", &g_org_webrtc_mozi_VideoEncoderFactory_createEncoder); jobject ret = env->CallObjectMethod(obj.obj(), method_id, info.obj()); jni_generator::CheckException(env); return base::android::ScopedJavaLocalRef<jobject>(env, ret); } } // namespace jni } // namespace webrtc #endif // org_webrtc_mozi_VideoEncoderFactory_JNI
總結一下調用鏈路
c++ ->sdk 里面的jni接口->編譯生成的jni方法->Java方法
其中webrtc簡化的是c++調用java這里的繁瑣寫法
Java調用c++
我們可以看到webrtc/sdk/android/src/jni/pc/peerconnectionfactory.h只定義了一個方法,但.cc實現文件里面內容很多,多了很多jni方法的實現,這些方法其實是在這個"sdk/android/generated_peerconnection_jni/jni/PeerConnectionFactory_jni.h"(編譯生成)的里面聲明的,這些jni方法對應的是PeerConnectionFactory.java里面的native方法
例如我們看到webrtc/sdk/android/src/java/org/webrtc/mozi/NativeCapturerObserver.java的nativeOnFrameCaptured方法,卻找不到對應的實現,有兩種方法
1. 先去編譯后的目錄(src/out)中尋找(find -name "NativeCapturerObserver_jni*"),找到對應文件(./releasearm/gen/sdk/android/generated_video_jni/jni/NativeCapturerObserver_jni.h),在文件中找OnFrameCaptured,基本能找到對應的jni方法聲明(JNI_NativeCapturerObserver_OnFrameCaptured),然后在源碼中就能找到對應的實現函數了
2. 代碼有對應關系,直接搜索NativeCapturerObserver.java對應的c++實現文件webrtc/sdk/android/src/jni/nativecapturerobserver.cc(這建立在有對應文件的前提下)
end