Как инициализировать WebRT C из нативного C ++ в приложении Android? - PullRequest
0 голосов
/ 04 августа 2020

Описание проблемы

Я разрабатываю 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))
    );
...