Описание проблемы
Я разрабатываю C ++ API для многоплатформенного (iOS и Android) приложения видеочата с использованием WebRT C. Идея состоит в том, чтобы скрыть всю функциональность WebRT C за API, написанным на C ++, в то время как приложения написаны на Swift и Java соответственно, с доступом к API через простой заголовок C ++. Уровни приложений не могут знать о базовой реализации, и, в частности, они не должны знать о WebRT C.
Я получил это для работы с iOS, но не смог для вызова функции инициализации WebRT C при работе на Android. Функция инициализации выглядит так:
void InitializeWebRTC(std::unique_ptr<webrtc::VideoEncoderFactory> encoderFactory,
std::unique_ptr<webrtc::VideoDecoderFactory> decoderFactory);
Моя проблема в том, что VideoEncoderFactory
и VideoDecoderFactory
должны быть созданы в контексте уровня приложения, что в случае Android означает что их нужно создать как Java объектов. Обычно я создавал их в Java как
videoEncoderFactory = new DefaultVideoEncoderFactory()
videoDecoderFactory = new DefaultVideoDecoderFactory()
, а затем передавал эти объекты через метод JNI как jobject
экземпляры в собственный код, где можно было вызвать функцию инициализации. Я не могу сделать это сейчас, так как для этого требуется, чтобы приложение знало о структурах данных WebRT C, чего я хочу избежать. Есть ли способ создать фабрики кодировщиков / декодеров в собственном коде C ++ вместо Java?
Что я пробовал
Я пробовал передать экземпляр JavaVM*
в API через функция JNI_OnLoad
. Цель состояла в том, чтобы создать видеокодер / декодер с использованием JNIEnv
, но InitializeWebRTC
не работает во время выполнения, поэтому что-то кажется go неправильным. В целом это тоже очень запутанное решение. Следующий код выполняется при вызове функции API init()
.
// Setup JNIEnv
RTC_CHECK_GE(webrtc::jni::InitGlobalJniVariables(vm), 0);
webrtc::InitClassLoader(webrtc::jni::GetEnv());
webrtc::JVM::Initialize(javaVM, (jobject)applicationContext);
JNIEnv* env = webrtc::jni::AttachCurrentThreadIfNeeded();
// Create EglBase
webrtc::ScopedJavaLocalRef<jclass> clazz = webrtc::GetClass(env, "org/webrtc/EglBase");
jmethodID methodID = env->GetStaticMethodID(clazz.obj(), "create", "()Lorg/webrtc/EglBase;");
jobject eglBase = env->CallStaticObjectMethod(clazz.obj(), methodID);
jobject globalEglBase = env->NewGlobalRef(eglBase); // TODO: Save a (static) reference to this object
// Get EglBaseContext
methodID = env->GetMethodID(clazz.obj(), "getEglBaseContext", "()Lorg/webrtc/EglBase$Context;");
jobject context = env->CallObjectMethod(globalEglBase, methodID);
// Create DefaultVideoEncoderFactory
clazz = webrtc::GetClass(env, "org/webrtc/DefaultVideoEncoderFactory");
methodID = env->GetMethodID(clazz.obj(), "<init>", "(Lorg/webrtc/EglBase$Context;ZZ)V");
jobject encoderFactory = env->NewObject(clazz.obj(), methodID, context, true, true);
jobject gEncoderFactory = env->NewGlobalRef(encoderFactory);
// Create DefaultVideoDecoderFactory
clazz = webrtc::GetClass(env, "org/webrtc/DefaultVideoDecoderFactory");
methodID = env->GetMethodID(clazz.obj(), "<init>", "(Lorg/webrtc/EglBase$Context;)V");
jobject decoderFactory = env->NewObject(clazz.obj(), methodID, context);
jobject gDecoderFactory = env->NewGlobalRef(decoderFactory);
InitializeWebRTC(
absl::make_unique<webrtc::jni::VideoEncoderFactoryWrapper>(env, webrtc::JavaParamRef<jobject>(env, gEncoderFactory)),
absl::make_unique<webrtc::jni::VideoDecoderFactoryWrapper>(env, webrtc::JavaParamRef<jobject>(env, gDecoderFactory))
);