Split peerconnection_jni.cc into separate files.
For now: java_helpers - JNI convenience functions etc. Can in theory be moved to libjingle / webrtc general one day. classreferenceholder - app/webrtc specific Java class loader. androidvideocapturer_jni - the jni part of the video capturer I added. peerconnection_jni - all the rest. This also move all jni specifics into ns webrtc_jni to avoid naming collision. R=glaznev@webrtc.org Review URL: https://webrtc-codereview.appspot.com/38099004 Cr-Commit-Position: refs/heads/master@{#8363} git-svn-id: http://webrtc.googlecode.com/svn/trunk@8363 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
8db5854eb0
commit
96e4db9bea
123
talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
Normal file
123
talk/app/webrtc/java/jni/androidvideocapturer_jni.cc
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
|
||||
|
||||
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
jobject AndroidVideoCapturerJni::application_context_ = nullptr;
|
||||
|
||||
// static
|
||||
int AndroidVideoCapturerJni::SetAndroidObjects(JNIEnv* jni,
|
||||
jobject appliction_context) {
|
||||
if (application_context_) {
|
||||
jni->DeleteGlobalRef(application_context_);
|
||||
}
|
||||
application_context_ = NewGlobalRef(jni, appliction_context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AndroidVideoCapturerJni::AndroidVideoCapturerJni(JNIEnv* jni,
|
||||
jobject j_video_capturer)
|
||||
: j_capturer_global_(jni, j_video_capturer),
|
||||
j_video_capturer_class_(
|
||||
jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")),
|
||||
j_frame_observer_class_(
|
||||
jni,
|
||||
FindClass(jni,
|
||||
"org/webrtc/VideoCapturerAndroid$NativeFrameObserver")) {
|
||||
}
|
||||
|
||||
AndroidVideoCapturerJni::~AndroidVideoCapturerJni() {}
|
||||
|
||||
void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
|
||||
webrtc::AndroidVideoCapturer* capturer) {
|
||||
j_frame_observer_ = NewGlobalRef(
|
||||
jni(),
|
||||
jni()->NewObject(*j_frame_observer_class_,
|
||||
GetMethodID(jni(),
|
||||
*j_frame_observer_class_,
|
||||
"<init>",
|
||||
"(J)V"),
|
||||
jlongFromPointer(capturer)));
|
||||
CHECK_EXCEPTION(jni()) << "error during NewObject";
|
||||
|
||||
jmethodID m = GetMethodID(
|
||||
jni(), *j_video_capturer_class_, "startCapture",
|
||||
"(IIILandroid/content/Context;"
|
||||
"Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V");
|
||||
jni()->CallVoidMethod(*j_capturer_global_,
|
||||
m, width, height,
|
||||
framerate,
|
||||
application_context_,
|
||||
j_frame_observer_);
|
||||
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
|
||||
}
|
||||
|
||||
bool AndroidVideoCapturerJni::Stop() {
|
||||
jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
|
||||
"stopCapture", "()Z");
|
||||
jboolean result = jni()->CallBooleanMethod(*j_capturer_global_, m);
|
||||
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
|
||||
DeleteGlobalRef(jni(), j_frame_observer_);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string AndroidVideoCapturerJni::GetSupportedFormats() {
|
||||
jmethodID m =
|
||||
GetMethodID(jni(), *j_video_capturer_class_,
|
||||
"getSupportedFormatsAsJson", "()Ljava/lang/String;");
|
||||
jstring j_json_caps =
|
||||
(jstring) jni()->CallObjectMethod(*j_capturer_global_, m);
|
||||
CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson";
|
||||
return JavaToStdString(jni(), j_json_caps);
|
||||
}
|
||||
|
||||
JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
|
||||
|
||||
JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeOnFrameCaptured)
|
||||
(JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame,
|
||||
jint rotation, jlong ts) {
|
||||
jbyte* bytes = jni->GetByteArrayElements(j_frame, NULL);
|
||||
reinterpret_cast<webrtc::AndroidVideoCapturer*>(
|
||||
j_capturer)->OnIncomingFrame(bytes, jni->GetArrayLength(j_frame),
|
||||
rotation, ts);
|
||||
jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
|
||||
}
|
||||
|
||||
JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeCapturerStarted)
|
||||
(JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
|
||||
reinterpret_cast<webrtc::AndroidVideoCapturer*>(
|
||||
j_capturer)->OnCapturerStarted(j_success);
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
69
talk/app/webrtc/java/jni/androidvideocapturer_jni.h
Normal file
69
talk/app/webrtc/java/jni/androidvideocapturer_jni.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_JAVA_JNI_ANDROIDVIDEOCAPTURER_JNI_H_
|
||||
#define TALK_APP_WEBRTC_JAVA_JNI_ANDROIDVIDEOCAPTURER_JNI_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "talk/app/webrtc/androidvideocapturer.h"
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
// AndroidVideoCapturerJni implements AndroidVideoCapturerDelegate.
|
||||
// The purpose of the delegate is to hide the JNI specifics from the C++ only
|
||||
// AndroidVideoCapturer.
|
||||
class AndroidVideoCapturerJni : public webrtc::AndroidVideoCapturerDelegate {
|
||||
public:
|
||||
static int SetAndroidObjects(JNIEnv* jni, jobject appliction_context);
|
||||
AndroidVideoCapturerJni(JNIEnv* jni, jobject j_video_capturer);
|
||||
~AndroidVideoCapturerJni();
|
||||
|
||||
void Start(int width, int height, int framerate,
|
||||
webrtc::AndroidVideoCapturer* capturer) override;
|
||||
bool Stop() override;
|
||||
|
||||
std::string GetSupportedFormats() override;
|
||||
|
||||
private:
|
||||
JNIEnv* jni();
|
||||
|
||||
const ScopedGlobalRef<jobject> j_capturer_global_;
|
||||
const ScopedGlobalRef<jclass> j_video_capturer_class_;
|
||||
const ScopedGlobalRef<jclass> j_frame_observer_class_;
|
||||
jobject j_frame_observer_;
|
||||
|
||||
static jobject application_context_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(AndroidVideoCapturerJni);
|
||||
};
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // TALK_APP_WEBRTC_JAVA_JNI_ANDROIDVIDEOCAPTURER_JNI_H_
|
141
talk/app/webrtc/java/jni/classreferenceholder.cc
Normal file
141
talk/app/webrtc/java/jni/classreferenceholder.cc
Normal file
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
|
||||
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
// ClassReferenceHolder holds global reference to Java classes in app/webrtc.
|
||||
class ClassReferenceHolder {
|
||||
public:
|
||||
explicit ClassReferenceHolder(JNIEnv* jni);
|
||||
~ClassReferenceHolder();
|
||||
|
||||
void FreeReferences(JNIEnv* jni);
|
||||
jclass GetClass(const std::string& name);
|
||||
|
||||
private:
|
||||
void LoadClass(JNIEnv* jni, const std::string& name);
|
||||
|
||||
std::map<std::string, jclass> classes_;
|
||||
};
|
||||
|
||||
// Allocated in LoadGlobalClassReferenceHolder(),
|
||||
// freed in FreeGlobalClassReferenceHolder().
|
||||
static ClassReferenceHolder* g_class_reference_holder = nullptr;
|
||||
|
||||
void LoadGlobalClassReferenceHolder() {
|
||||
CHECK(g_class_reference_holder == nullptr);
|
||||
g_class_reference_holder = new ClassReferenceHolder(GetEnv());
|
||||
}
|
||||
|
||||
void FreeGlobalClassReferenceHolder() {
|
||||
g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
|
||||
delete g_class_reference_holder;
|
||||
g_class_reference_holder = nullptr;
|
||||
}
|
||||
|
||||
ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
||||
LoadClass(jni, "java/nio/ByteBuffer");
|
||||
LoadClass(jni, "org/webrtc/AudioTrack");
|
||||
LoadClass(jni, "org/webrtc/DataChannel");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$Buffer");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$Init");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$State");
|
||||
LoadClass(jni, "org/webrtc/IceCandidate");
|
||||
#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
LoadClass(jni, "android/graphics/SurfaceTexture");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeFrameObserver");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
|
||||
jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
|
||||
jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
|
||||
j_decoder_class, "isEGL14Supported", "()Z");
|
||||
bool is_egl14_supported = jni->CallStaticBooleanMethod(
|
||||
j_decoder_class, j_is_egl14_supported_method);
|
||||
CHECK_EXCEPTION(jni);
|
||||
if (is_egl14_supported) {
|
||||
LoadClass(jni, "android/opengl/EGLContext");
|
||||
}
|
||||
#endif
|
||||
LoadClass(jni, "org/webrtc/MediaSource$State");
|
||||
LoadClass(jni, "org/webrtc/MediaStream");
|
||||
LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
|
||||
LoadClass(jni, "org/webrtc/SessionDescription");
|
||||
LoadClass(jni, "org/webrtc/SessionDescription$Type");
|
||||
LoadClass(jni, "org/webrtc/StatsReport");
|
||||
LoadClass(jni, "org/webrtc/StatsReport$Value");
|
||||
LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturer");
|
||||
LoadClass(jni, "org/webrtc/VideoTrack");
|
||||
}
|
||||
|
||||
ClassReferenceHolder::~ClassReferenceHolder() {
|
||||
CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
|
||||
}
|
||||
|
||||
void ClassReferenceHolder::FreeReferences(JNIEnv* jni) {
|
||||
for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
|
||||
it != classes_.end(); ++it) {
|
||||
jni->DeleteGlobalRef(it->second);
|
||||
}
|
||||
classes_.clear();
|
||||
}
|
||||
|
||||
jclass ClassReferenceHolder::GetClass(const std::string& name) {
|
||||
std::map<std::string, jclass>::iterator it = classes_.find(name);
|
||||
CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void ClassReferenceHolder::LoadClass(JNIEnv* jni, const std::string& name) {
|
||||
jclass localRef = jni->FindClass(name.c_str());
|
||||
CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
|
||||
CHECK(localRef) << name;
|
||||
jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
|
||||
CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
|
||||
CHECK(globalRef) << name;
|
||||
bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
|
||||
CHECK(inserted) << "Duplicate class name: " << name;
|
||||
}
|
||||
|
||||
// Returns a global reference guaranteed to be valid for the lifetime of the
|
||||
// process.
|
||||
jclass FindClass(JNIEnv* jni, const char* name) {
|
||||
return g_class_reference_holder->GetClass(name);
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
59
talk/app/webrtc/java/jni/classreferenceholder.h
Normal file
59
talk/app/webrtc/java/jni/classreferenceholder.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
// Android's FindClass() is trickier than usual because the app-specific
|
||||
// ClassLoader is not consulted when there is no app-specific frame on the
|
||||
// stack. Consequently, we only look up all classes once in app/webrtc.
|
||||
// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_JAVA_JNI_CLASSREFERENCEHOLDER_H_
|
||||
#define TALK_APP_WEBRTC_JAVA_JNI_CLASSREFERENCEHOLDER_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
// LoadGlobalClassReferenceHolder must be called in JNI_OnLoad.
|
||||
void LoadGlobalClassReferenceHolder();
|
||||
// FreeGlobalClassReferenceHolder must be called in JNI_UnLoad.
|
||||
void FreeGlobalClassReferenceHolder();
|
||||
|
||||
// Returns a global reference guaranteed to be valid for the lifetime of the
|
||||
// process.
|
||||
jclass FindClass(JNIEnv* jni, const char* name);
|
||||
|
||||
// Convenience macro defining JNI-accessible methods in the org.webrtc package.
|
||||
// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
|
||||
#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
|
||||
Java_org_webrtc_##name
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // TALK_APP_WEBRTC_JAVA_JNI_CLASSREFERENCEHOLDER_H_
|
295
talk/app/webrtc/java/jni/jni_helpers.cc
Normal file
295
talk/app/webrtc/java/jni/jni_helpers.cc
Normal file
@ -0,0 +1,295 @@
|
||||
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
static JavaVM* g_jvm = nullptr;
|
||||
|
||||
static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
|
||||
// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
|
||||
// were attached by the JVM because of a Java->native call.
|
||||
static pthread_key_t g_jni_ptr;
|
||||
|
||||
using icu::UnicodeString;
|
||||
|
||||
JavaVM *GetJVM() {
|
||||
CHECK(g_jvm) << "JNI_OnLoad failed to run?";
|
||||
return g_jvm;
|
||||
}
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
|
||||
JNIEnv* GetEnv() {
|
||||
void* env = NULL;
|
||||
jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
|
||||
CHECK(((env != NULL) && (status == JNI_OK)) ||
|
||||
((env == NULL) && (status == JNI_EDETACHED)))
|
||||
<< "Unexpected GetEnv return: " << status << ":" << env;
|
||||
return reinterpret_cast<JNIEnv*>(env);
|
||||
}
|
||||
|
||||
static void ThreadDestructor(void* prev_jni_ptr) {
|
||||
// This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
|
||||
// we were responsible for originally attaching the thread, so are responsible
|
||||
// for detaching it now. However, because some JVM implementations (notably
|
||||
// Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
|
||||
// the JVMs accounting info for this thread may already be wiped out by the
|
||||
// time this is called. Thus it may appear we are already detached even though
|
||||
// it was our responsibility to detach! Oh well.
|
||||
if (!GetEnv())
|
||||
return;
|
||||
|
||||
CHECK(GetEnv() == prev_jni_ptr)
|
||||
<< "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
|
||||
jint status = g_jvm->DetachCurrentThread();
|
||||
CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
|
||||
CHECK(!GetEnv()) << "Detaching was a successful no-op???";
|
||||
}
|
||||
|
||||
static void CreateJNIPtrKey() {
|
||||
CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
|
||||
<< "pthread_key_create";
|
||||
}
|
||||
|
||||
jint InitGlobalJniVariables(JavaVM *jvm) {
|
||||
CHECK(!g_jvm) << "InitGlobalJniVariables!";
|
||||
g_jvm = jvm;
|
||||
CHECK(g_jvm) << "InitGlobalJniVariables handed NULL?";
|
||||
|
||||
CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
|
||||
|
||||
JNIEnv* jni = nullptr;
|
||||
if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
|
||||
return -1;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
// Return thread ID as a string.
|
||||
static std::string GetThreadId() {
|
||||
char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
|
||||
CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
|
||||
sizeof(buf))
|
||||
<< "Thread id is bigger than uint64??";
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// Return the current thread's name.
|
||||
static std::string GetThreadName() {
|
||||
char name[17];
|
||||
CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
|
||||
name[16] = '\0';
|
||||
return std::string(name);
|
||||
}
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
|
||||
JNIEnv* AttachCurrentThreadIfNeeded() {
|
||||
JNIEnv* jni = GetEnv();
|
||||
if (jni)
|
||||
return jni;
|
||||
CHECK(!pthread_getspecific(g_jni_ptr))
|
||||
<< "TLS has a JNIEnv* but not attached?";
|
||||
|
||||
std::string name(GetThreadName() + " - " + GetThreadId());
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_6;
|
||||
args.name = &name[0];
|
||||
args.group = NULL;
|
||||
// Deal with difference in signatures between Oracle's jni.h and Android's.
|
||||
#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
|
||||
void* env = NULL;
|
||||
#else
|
||||
JNIEnv* env = NULL;
|
||||
#endif
|
||||
CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
|
||||
CHECK(env) << "AttachCurrentThread handed back NULL!";
|
||||
jni = reinterpret_cast<JNIEnv*>(env);
|
||||
CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
|
||||
return jni;
|
||||
}
|
||||
|
||||
// Return a |jlong| that will correctly convert back to |ptr|. This is needed
|
||||
// because the alternative (of silently passing a 32-bit pointer to a vararg
|
||||
// function expecting a 64-bit param) picks up garbage in the high 32 bits.
|
||||
jlong jlongFromPointer(void* ptr) {
|
||||
static_assert(sizeof(intptr_t) <= sizeof(jlong),
|
||||
"Time to rethink the use of jlongs");
|
||||
// Going through intptr_t to be obvious about the definedness of the
|
||||
// conversion from pointer to integral type. intptr_t to jlong is a standard
|
||||
// widening by the static_assert above.
|
||||
jlong ret = reinterpret_cast<intptr_t>(ptr);
|
||||
DCHECK(reinterpret_cast<void*>(ret) == ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
|
||||
// object/class/method/field is non-null.
|
||||
jmethodID GetMethodID(
|
||||
JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
|
||||
jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
|
||||
<< signature;
|
||||
CHECK(m) << name << ", " << signature;
|
||||
return m;
|
||||
}
|
||||
|
||||
jmethodID GetStaticMethodID(
|
||||
JNIEnv* jni, jclass c, const char* name, const char* signature) {
|
||||
jmethodID m = jni->GetStaticMethodID(c, name, signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
|
||||
<< signature;
|
||||
CHECK(m) << name << ", " << signature;
|
||||
return m;
|
||||
}
|
||||
|
||||
jfieldID GetFieldID(
|
||||
JNIEnv* jni, jclass c, const char* name, const char* signature) {
|
||||
jfieldID f = jni->GetFieldID(c, name, signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetFieldID";
|
||||
CHECK(f) << name << ", " << signature;
|
||||
return f;
|
||||
}
|
||||
|
||||
jclass GetObjectClass(JNIEnv* jni, jobject object) {
|
||||
jclass c = jni->GetObjectClass(object);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectClass";
|
||||
CHECK(c) << "GetObjectClass returned NULL";
|
||||
return c;
|
||||
}
|
||||
|
||||
jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jobject o = jni->GetObjectField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectField";
|
||||
CHECK(o) << "GetObjectField returned NULL";
|
||||
return o;
|
||||
}
|
||||
|
||||
jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
return static_cast<jstring>(GetObjectField(jni, object, id));
|
||||
}
|
||||
|
||||
jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jlong l = jni->GetLongField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetLongField";
|
||||
return l;
|
||||
}
|
||||
|
||||
jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jint i = jni->GetIntField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetIntField";
|
||||
return i;
|
||||
}
|
||||
|
||||
bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jboolean b = jni->GetBooleanField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetBooleanField";
|
||||
return b;
|
||||
}
|
||||
|
||||
// Java references to "null" can only be distinguished as such in C++ by
|
||||
// creating a local reference, so this helper wraps that logic.
|
||||
bool IsNull(JNIEnv* jni, jobject obj) {
|
||||
ScopedLocalRefFrame local_ref_frame(jni);
|
||||
return jni->NewLocalRef(obj) == NULL;
|
||||
}
|
||||
|
||||
// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
|
||||
jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
|
||||
UnicodeString ustr(UnicodeString::fromUTF8(native));
|
||||
jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
|
||||
CHECK_EXCEPTION(jni) << "error during NewString";
|
||||
return jstr;
|
||||
}
|
||||
|
||||
// Given a (UTF-16) jstring return a new UTF-8 native string.
|
||||
std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
|
||||
const jchar* jchars = jni->GetStringChars(j_string, NULL);
|
||||
CHECK_EXCEPTION(jni) << "Error during GetStringChars";
|
||||
UnicodeString ustr(jchars, jni->GetStringLength(j_string));
|
||||
CHECK_EXCEPTION(jni) << "Error during GetStringLength";
|
||||
jni->ReleaseStringChars(j_string, jchars);
|
||||
CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
|
||||
std::string ret;
|
||||
return ustr.toUTF8String(ret);
|
||||
}
|
||||
|
||||
// Return the (singleton) Java Enum object corresponding to |index|;
|
||||
jobject JavaEnumFromIndex(JNIEnv* jni, jclass state_class,
|
||||
const std::string& state_class_name, int index) {
|
||||
jmethodID state_values_id = GetStaticMethodID(
|
||||
jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
|
||||
jobjectArray state_values = static_cast<jobjectArray>(
|
||||
jni->CallStaticObjectMethod(state_class, state_values_id));
|
||||
CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
|
||||
jobject ret = jni->GetObjectArrayElement(state_values, index);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
|
||||
return ret;
|
||||
}
|
||||
|
||||
jobject NewGlobalRef(JNIEnv* jni, jobject o) {
|
||||
jobject ret = jni->NewGlobalRef(o);
|
||||
CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
|
||||
CHECK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeleteGlobalRef(JNIEnv* jni, jobject o) {
|
||||
jni->DeleteGlobalRef(o);
|
||||
CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
|
||||
}
|
||||
|
||||
WeakRef::WeakRef(JNIEnv* jni, jweak ref)
|
||||
: jni_(jni), obj_(jni_->NewLocalRef(ref)) {
|
||||
CHECK_EXCEPTION(jni) << "error during NewLocalRef";
|
||||
}
|
||||
WeakRef::~WeakRef() {
|
||||
if (obj_) {
|
||||
jni_->DeleteLocalRef(obj_);
|
||||
CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
|
||||
}
|
||||
}
|
||||
|
||||
// Scope Java local references to the lifetime of this object. Use in all C++
|
||||
// callbacks (i.e. entry points that don't originate in a Java callstack
|
||||
// through a "native" method call).
|
||||
ScopedLocalRefFrame::ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
|
||||
CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
|
||||
}
|
||||
ScopedLocalRefFrame::~ScopedLocalRefFrame() {
|
||||
jni_->PopLocalFrame(NULL);
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
156
talk/app/webrtc/java/jni/jni_helpers.h
Normal file
156
talk/app/webrtc/java/jni/jni_helpers.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2015 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
// This file contain convenience functions and classes for JNI.
|
||||
// Before using any of the methods, InitGlobalJniVariables must be called.
|
||||
|
||||
#ifndef TALK_APP_WEBRTC_JAVA_JNI_JNI_HELPERS_H_
|
||||
#define TALK_APP_WEBRTC_JAVA_JNI_JNI_HELPERS_H_
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "third_party/icu/source/common/unicode/unistr.h"
|
||||
|
||||
// Abort the process if |jni| has a Java exception pending.
|
||||
// This macros uses the comma operator to execute ExceptionDescribe
|
||||
// and ExceptionClear ignoring their return values and sending ""
|
||||
// to the error stream.
|
||||
#define CHECK_EXCEPTION(jni) \
|
||||
CHECK(!jni->ExceptionCheck()) \
|
||||
<< (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
|
||||
|
||||
// Helper that calls ptr->Release() and aborts the process with a useful
|
||||
// message if that didn't actually delete *ptr because of extra refcounts.
|
||||
#define CHECK_RELEASE(ptr) \
|
||||
CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
|
||||
|
||||
namespace webrtc_jni {
|
||||
|
||||
jint InitGlobalJniVariables(JavaVM *jvm);
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
|
||||
JNIEnv* GetEnv();
|
||||
|
||||
JavaVM *GetJVM();
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
|
||||
JNIEnv* AttachCurrentThreadIfNeeded();
|
||||
|
||||
// Return a |jlong| that will correctly convert back to |ptr|. This is needed
|
||||
// because the alternative (of silently passing a 32-bit pointer to a vararg
|
||||
// function expecting a 64-bit param) picks up garbage in the high 32 bits.
|
||||
jlong jlongFromPointer(void* ptr);
|
||||
|
||||
// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
|
||||
// object/class/method/field is non-null.
|
||||
jmethodID GetMethodID(
|
||||
JNIEnv* jni, jclass c, const std::string& name, const char* signature);
|
||||
|
||||
jmethodID GetStaticMethodID(
|
||||
JNIEnv* jni, jclass c, const char* name, const char* signature);
|
||||
|
||||
jfieldID GetFieldID(JNIEnv* jni, jclass c, const char* name,
|
||||
const char* signature);
|
||||
|
||||
jclass GetObjectClass(JNIEnv* jni, jobject object);
|
||||
|
||||
jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id);
|
||||
|
||||
jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id);
|
||||
|
||||
jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id);
|
||||
|
||||
jint GetIntField(JNIEnv* jni, jobject object, jfieldID id);
|
||||
|
||||
bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id);
|
||||
|
||||
// Java references to "null" can only be distinguished as such in C++ by
|
||||
// creating a local reference, so this helper wraps that logic.
|
||||
bool IsNull(JNIEnv* jni, jobject obj);
|
||||
|
||||
// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
|
||||
jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native);
|
||||
|
||||
// Given a (UTF-16) jstring return a new UTF-8 native string.
|
||||
std::string JavaToStdString(JNIEnv* jni, const jstring& j_string);
|
||||
|
||||
// Return the (singleton) Java Enum object corresponding to |index|;
|
||||
jobject JavaEnumFromIndex(JNIEnv* jni, jclass state_class,
|
||||
const std::string& state_class_name, int index);
|
||||
|
||||
jobject NewGlobalRef(JNIEnv* jni, jobject o);
|
||||
|
||||
void DeleteGlobalRef(JNIEnv* jni, jobject o);
|
||||
|
||||
// Given a jweak reference, allocate a (strong) local reference scoped to the
|
||||
// lifetime of this object if the weak reference is still valid, or NULL
|
||||
// otherwise.
|
||||
class WeakRef {
|
||||
public:
|
||||
WeakRef(JNIEnv* jni, jweak ref);
|
||||
~WeakRef();
|
||||
jobject obj() { return obj_; }
|
||||
|
||||
private:
|
||||
JNIEnv* const jni_;
|
||||
jobject const obj_;
|
||||
};
|
||||
|
||||
// Scope Java local references to the lifetime of this object. Use in all C++
|
||||
// callbacks (i.e. entry points that don't originate in a Java callstack
|
||||
// through a "native" method call).
|
||||
class ScopedLocalRefFrame {
|
||||
public:
|
||||
explicit ScopedLocalRefFrame(JNIEnv* jni);
|
||||
~ScopedLocalRefFrame();
|
||||
|
||||
private:
|
||||
JNIEnv* jni_;
|
||||
};
|
||||
|
||||
// Scoped holder for global Java refs.
|
||||
template<class T> // T is jclass, jobject, jintArray, etc.
|
||||
class ScopedGlobalRef {
|
||||
public:
|
||||
ScopedGlobalRef(JNIEnv* jni, T obj)
|
||||
: obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
|
||||
~ScopedGlobalRef() {
|
||||
DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
|
||||
}
|
||||
T operator*() const {
|
||||
return obj_;
|
||||
}
|
||||
private:
|
||||
T obj_;
|
||||
};
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
||||
#endif // TALK_APP_WEBRTC_JAVA_JNI_JNI_HELPERS_H_
|
@ -56,13 +56,10 @@
|
||||
#undef JNIEXPORT
|
||||
#define JNIEXPORT __attribute__((visibility("default")))
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
||||
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
|
||||
#include "talk/app/webrtc/java/jni/jni_helpers.h"
|
||||
#include "talk/app/webrtc/mediaconstraintsinterface.h"
|
||||
#include "talk/app/webrtc/peerconnectioninterface.h"
|
||||
#include "talk/app/webrtc/videosourceinterface.h"
|
||||
@ -92,6 +89,7 @@
|
||||
#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
#include <android/log.h>
|
||||
#include "talk/app/webrtc/androidvideocapturer.h"
|
||||
#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
|
||||
#include "webrtc/modules/video_render/video_render_internal.h"
|
||||
#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
|
||||
#include "webrtc/system_wrappers/interface/tick_util.h"
|
||||
@ -106,7 +104,6 @@ using webrtc::TickTime;
|
||||
using webrtc::VideoCodec;
|
||||
#endif
|
||||
|
||||
using icu::UnicodeString;
|
||||
using rtc::Bind;
|
||||
using rtc::Thread;
|
||||
using rtc::ThreadManager;
|
||||
@ -139,28 +136,7 @@ using webrtc::VideoTrackInterface;
|
||||
using webrtc::VideoTrackVector;
|
||||
using webrtc::kVideoCodecVP8;
|
||||
|
||||
// Abort the process if |jni| has a Java exception pending.
|
||||
// This macros uses the comma operator to execute ExceptionDescribe
|
||||
// and ExceptionClear ignoring their return values and sending ""
|
||||
// to the error stream.
|
||||
#define CHECK_EXCEPTION(jni) \
|
||||
CHECK(!jni->ExceptionCheck()) \
|
||||
<< (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
|
||||
|
||||
// Helper that calls ptr->Release() and aborts the process with a useful
|
||||
// message if that didn't actually delete *ptr because of extra refcounts.
|
||||
#define CHECK_RELEASE(ptr) \
|
||||
CHECK_EQ(0, (ptr)->Release()) << "Unexpected refcount."
|
||||
|
||||
namespace {
|
||||
|
||||
static JavaVM* g_jvm = NULL; // Set in JNI_OnLoad().
|
||||
|
||||
static pthread_once_t g_jni_ptr_once = PTHREAD_ONCE_INIT;
|
||||
// Key for per-thread JNIEnv* data. Non-NULL in threads attached to |g_jvm| by
|
||||
// AttachCurrentThreadIfNeeded(), NULL in unattached threads and threads that
|
||||
// were attached by the JVM because of a Java->native call.
|
||||
static pthread_key_t g_jni_ptr;
|
||||
namespace webrtc_jni {
|
||||
|
||||
// Field trials initialization string
|
||||
static char *field_trials_init_string = NULL;
|
||||
@ -171,388 +147,29 @@ static bool factory_static_initialized = false;
|
||||
static bool vp8_hw_acceleration_enabled = true;
|
||||
#endif
|
||||
|
||||
|
||||
// Return thread ID as a string.
|
||||
static std::string GetThreadId() {
|
||||
char buf[21]; // Big enough to hold a kuint64max plus terminating NULL.
|
||||
CHECK_LT(snprintf(buf, sizeof(buf), "%llu", syscall(__NR_gettid)),
|
||||
sizeof(buf))
|
||||
<< "Thread id is bigger than uint64??";
|
||||
return std::string(buf);
|
||||
}
|
||||
|
||||
// Return the current thread's name.
|
||||
static std::string GetThreadName() {
|
||||
char name[17];
|
||||
CHECK_EQ(0, prctl(PR_GET_NAME, name)) << "prctl(PR_GET_NAME) failed";
|
||||
name[16] = '\0';
|
||||
return std::string(name);
|
||||
}
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread or NULL if this thread is detached.
|
||||
static JNIEnv* GetEnv() {
|
||||
void* env = NULL;
|
||||
jint status = g_jvm->GetEnv(&env, JNI_VERSION_1_6);
|
||||
CHECK(((env != NULL) && (status == JNI_OK)) ||
|
||||
((env == NULL) && (status == JNI_EDETACHED)))
|
||||
<< "Unexpected GetEnv return: " << status << ":" << env;
|
||||
return reinterpret_cast<JNIEnv*>(env);
|
||||
}
|
||||
|
||||
static void ThreadDestructor(void* prev_jni_ptr) {
|
||||
// This function only runs on threads where |g_jni_ptr| is non-NULL, meaning
|
||||
// we were responsible for originally attaching the thread, so are responsible
|
||||
// for detaching it now. However, because some JVM implementations (notably
|
||||
// Oracle's http://goo.gl/eHApYT) also use the pthread_key_create mechanism,
|
||||
// the JVMs accounting info for this thread may already be wiped out by the
|
||||
// time this is called. Thus it may appear we are already detached even though
|
||||
// it was our responsibility to detach! Oh well.
|
||||
if (!GetEnv())
|
||||
return;
|
||||
|
||||
CHECK(GetEnv() == prev_jni_ptr)
|
||||
<< "Detaching from another thread: " << prev_jni_ptr << ":" << GetEnv();
|
||||
jint status = g_jvm->DetachCurrentThread();
|
||||
CHECK(status == JNI_OK) << "Failed to detach thread: " << status;
|
||||
CHECK(!GetEnv()) << "Detaching was a successful no-op???";
|
||||
}
|
||||
|
||||
static void CreateJNIPtrKey() {
|
||||
CHECK(!pthread_key_create(&g_jni_ptr, &ThreadDestructor))
|
||||
<< "pthread_key_create";
|
||||
}
|
||||
|
||||
// Return a |JNIEnv*| usable on this thread. Attaches to |g_jvm| if necessary.
|
||||
static JNIEnv* AttachCurrentThreadIfNeeded() {
|
||||
JNIEnv* jni = GetEnv();
|
||||
if (jni)
|
||||
return jni;
|
||||
CHECK(!pthread_getspecific(g_jni_ptr))
|
||||
<< "TLS has a JNIEnv* but not attached?";
|
||||
|
||||
char* name = strdup((GetThreadName() + " - " + GetThreadId()).c_str());
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_6;
|
||||
args.name = name;
|
||||
args.group = NULL;
|
||||
// Deal with difference in signatures between Oracle's jni.h and Android's.
|
||||
#ifdef _JAVASOFT_JNI_H_ // Oracle's jni.h violates the JNI spec!
|
||||
void* env = NULL;
|
||||
#else
|
||||
JNIEnv* env = NULL;
|
||||
#endif
|
||||
CHECK(!g_jvm->AttachCurrentThread(&env, &args)) << "Failed to attach thread";
|
||||
free(name);
|
||||
CHECK(env) << "AttachCurrentThread handed back NULL!";
|
||||
jni = reinterpret_cast<JNIEnv*>(env);
|
||||
CHECK(!pthread_setspecific(g_jni_ptr, jni)) << "pthread_setspecific";
|
||||
return jni;
|
||||
}
|
||||
|
||||
// Return a |jlong| that will correctly convert back to |ptr|. This is needed
|
||||
// because the alternative (of silently passing a 32-bit pointer to a vararg
|
||||
// function expecting a 64-bit param) picks up garbage in the high 32 bits.
|
||||
static jlong jlongFromPointer(void* ptr) {
|
||||
static_assert(sizeof(intptr_t) <= sizeof(jlong),
|
||||
"Time to rethink the use of jlongs");
|
||||
// Going through intptr_t to be obvious about the definedness of the
|
||||
// conversion from pointer to integral type. intptr_t to jlong is a standard
|
||||
// widening by the static_assert above.
|
||||
jlong ret = reinterpret_cast<intptr_t>(ptr);
|
||||
assert(reinterpret_cast<void*>(ret) == ptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Android's FindClass() is trickier than usual because the app-specific
|
||||
// ClassLoader is not consulted when there is no app-specific frame on the
|
||||
// stack. Consequently, we only look up classes once in JNI_OnLoad.
|
||||
// http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
|
||||
class ClassReferenceHolder {
|
||||
public:
|
||||
explicit ClassReferenceHolder(JNIEnv* jni) {
|
||||
LoadClass(jni, "java/nio/ByteBuffer");
|
||||
LoadClass(jni, "org/webrtc/AudioTrack");
|
||||
LoadClass(jni, "org/webrtc/DataChannel");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$Buffer");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$Init");
|
||||
LoadClass(jni, "org/webrtc/DataChannel$State");
|
||||
LoadClass(jni, "org/webrtc/IceCandidate");
|
||||
#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
LoadClass(jni, "android/graphics/SurfaceTexture");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeFrameObserver");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder");
|
||||
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecoderOutputBufferInfo");
|
||||
jclass j_decoder_class = GetClass("org/webrtc/MediaCodecVideoDecoder");
|
||||
jmethodID j_is_egl14_supported_method = jni->GetStaticMethodID(
|
||||
j_decoder_class, "isEGL14Supported", "()Z");
|
||||
bool is_egl14_supported = jni->CallStaticBooleanMethod(
|
||||
j_decoder_class, j_is_egl14_supported_method);
|
||||
CHECK_EXCEPTION(jni);
|
||||
if (is_egl14_supported) {
|
||||
LoadClass(jni, "android/opengl/EGLContext");
|
||||
}
|
||||
#endif
|
||||
LoadClass(jni, "org/webrtc/MediaSource$State");
|
||||
LoadClass(jni, "org/webrtc/MediaStream");
|
||||
LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$IceConnectionState");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$IceGatheringState");
|
||||
LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
|
||||
LoadClass(jni, "org/webrtc/SessionDescription");
|
||||
LoadClass(jni, "org/webrtc/SessionDescription$Type");
|
||||
LoadClass(jni, "org/webrtc/StatsReport");
|
||||
LoadClass(jni, "org/webrtc/StatsReport$Value");
|
||||
LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
|
||||
LoadClass(jni, "org/webrtc/VideoCapturer");
|
||||
LoadClass(jni, "org/webrtc/VideoTrack");
|
||||
}
|
||||
|
||||
~ClassReferenceHolder() {
|
||||
CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
|
||||
}
|
||||
|
||||
void FreeReferences(JNIEnv* jni) {
|
||||
for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
|
||||
it != classes_.end(); ++it) {
|
||||
jni->DeleteGlobalRef(it->second);
|
||||
}
|
||||
classes_.clear();
|
||||
}
|
||||
|
||||
jclass GetClass(const std::string& name) {
|
||||
std::map<std::string, jclass>::iterator it = classes_.find(name);
|
||||
CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
void LoadClass(JNIEnv* jni, const std::string& name) {
|
||||
jclass localRef = jni->FindClass(name.c_str());
|
||||
CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
|
||||
CHECK(localRef) << name;
|
||||
jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
|
||||
CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
|
||||
CHECK(globalRef) << name;
|
||||
bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
|
||||
CHECK(inserted) << "Duplicate class name: " << name;
|
||||
}
|
||||
|
||||
std::map<std::string, jclass> classes_;
|
||||
};
|
||||
|
||||
// Allocated in JNI_OnLoad(), freed in JNI_OnUnLoad().
|
||||
static ClassReferenceHolder* g_class_reference_holder = NULL;
|
||||
|
||||
// JNIEnv-helper methods that CHECK success: no Java exception thrown and found
|
||||
// object/class/method/field is non-null.
|
||||
jmethodID GetMethodID(
|
||||
JNIEnv* jni, jclass c, const std::string& name, const char* signature) {
|
||||
jmethodID m = jni->GetMethodID(c, name.c_str(), signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetMethodID: " << name << ", "
|
||||
<< signature;
|
||||
CHECK(m) << name << ", " << signature;
|
||||
return m;
|
||||
}
|
||||
|
||||
jmethodID GetStaticMethodID(
|
||||
JNIEnv* jni, jclass c, const char* name, const char* signature) {
|
||||
jmethodID m = jni->GetStaticMethodID(c, name, signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetStaticMethodID: " << name << ", "
|
||||
<< signature;
|
||||
CHECK(m) << name << ", " << signature;
|
||||
return m;
|
||||
}
|
||||
|
||||
jfieldID GetFieldID(
|
||||
JNIEnv* jni, jclass c, const char* name, const char* signature) {
|
||||
jfieldID f = jni->GetFieldID(c, name, signature);
|
||||
CHECK_EXCEPTION(jni) << "error during GetFieldID";
|
||||
CHECK(f) << name << ", " << signature;
|
||||
return f;
|
||||
}
|
||||
|
||||
// Returns a global reference guaranteed to be valid for the lifetime of the
|
||||
// process.
|
||||
jclass FindClass(JNIEnv* jni, const char* name) {
|
||||
return g_class_reference_holder->GetClass(name);
|
||||
}
|
||||
|
||||
jclass GetObjectClass(JNIEnv* jni, jobject object) {
|
||||
jclass c = jni->GetObjectClass(object);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectClass";
|
||||
CHECK(c) << "GetObjectClass returned NULL";
|
||||
return c;
|
||||
}
|
||||
|
||||
jobject GetObjectField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jobject o = jni->GetObjectField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectField";
|
||||
CHECK(o) << "GetObjectField returned NULL";
|
||||
return o;
|
||||
}
|
||||
|
||||
jstring GetStringField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
return static_cast<jstring>(GetObjectField(jni, object, id));
|
||||
}
|
||||
|
||||
jlong GetLongField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jlong l = jni->GetLongField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetLongField";
|
||||
return l;
|
||||
}
|
||||
|
||||
jint GetIntField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jint i = jni->GetIntField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetIntField";
|
||||
return i;
|
||||
}
|
||||
|
||||
bool GetBooleanField(JNIEnv* jni, jobject object, jfieldID id) {
|
||||
jboolean b = jni->GetBooleanField(object, id);
|
||||
CHECK_EXCEPTION(jni) << "error during GetBooleanField";
|
||||
return b;
|
||||
}
|
||||
|
||||
jobject NewGlobalRef(JNIEnv* jni, jobject o) {
|
||||
jobject ret = jni->NewGlobalRef(o);
|
||||
CHECK_EXCEPTION(jni) << "error during NewGlobalRef";
|
||||
CHECK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DeleteGlobalRef(JNIEnv* jni, jobject o) {
|
||||
jni->DeleteGlobalRef(o);
|
||||
CHECK_EXCEPTION(jni) << "error during DeleteGlobalRef";
|
||||
}
|
||||
|
||||
// Convenience macro defining JNI-accessible methods in the org.webrtc package.
|
||||
// Eliminates unnecessary boilerplate and line-wraps, reducing visual clutter.
|
||||
#define JOW(rettype, name) extern "C" rettype JNIEXPORT JNICALL \
|
||||
Java_org_webrtc_##name
|
||||
|
||||
extern "C" jint JNIEXPORT JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
|
||||
CHECK(!g_jvm) << "JNI_OnLoad called more than once!";
|
||||
g_jvm = jvm;
|
||||
CHECK(g_jvm) << "JNI_OnLoad handed NULL?";
|
||||
|
||||
CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
|
||||
jint ret = InitGlobalJniVariables(jvm);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
CHECK(rtc::InitializeSSL()) << "Failed to InitializeSSL()";
|
||||
LoadGlobalClassReferenceHolder();
|
||||
|
||||
JNIEnv* jni;
|
||||
if (jvm->GetEnv(reinterpret_cast<void**>(&jni), JNI_VERSION_1_6) != JNI_OK)
|
||||
return -1;
|
||||
g_class_reference_holder = new ClassReferenceHolder(jni);
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern "C" void JNIEXPORT JNICALL JNI_OnUnLoad(JavaVM *jvm, void *reserved) {
|
||||
g_class_reference_holder->FreeReferences(AttachCurrentThreadIfNeeded());
|
||||
delete g_class_reference_holder;
|
||||
g_class_reference_holder = NULL;
|
||||
FreeGlobalClassReferenceHolder();
|
||||
CHECK(rtc::CleanupSSL()) << "Failed to CleanupSSL()";
|
||||
g_jvm = NULL;
|
||||
}
|
||||
|
||||
// Given a jweak reference, allocate a (strong) local reference scoped to the
|
||||
// lifetime of this object if the weak reference is still valid, or NULL
|
||||
// otherwise.
|
||||
class WeakRef {
|
||||
public:
|
||||
WeakRef(JNIEnv* jni, jweak ref)
|
||||
: jni_(jni), obj_(jni_->NewLocalRef(ref)) {
|
||||
CHECK_EXCEPTION(jni) << "error during NewLocalRef";
|
||||
}
|
||||
~WeakRef() {
|
||||
if (obj_) {
|
||||
jni_->DeleteLocalRef(obj_);
|
||||
CHECK_EXCEPTION(jni_) << "error during DeleteLocalRef";
|
||||
}
|
||||
}
|
||||
jobject obj() { return obj_; }
|
||||
|
||||
private:
|
||||
JNIEnv* const jni_;
|
||||
jobject const obj_;
|
||||
};
|
||||
|
||||
// Scope Java local references to the lifetime of this object. Use in all C++
|
||||
// callbacks (i.e. entry points that don't originate in a Java callstack
|
||||
// through a "native" method call).
|
||||
class ScopedLocalRefFrame {
|
||||
public:
|
||||
explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
|
||||
CHECK(!jni_->PushLocalFrame(0)) << "Failed to PushLocalFrame";
|
||||
}
|
||||
~ScopedLocalRefFrame() {
|
||||
jni_->PopLocalFrame(NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* jni_;
|
||||
};
|
||||
|
||||
// Scoped holder for global Java refs.
|
||||
template<class T> // T is jclass, jobject, jintArray, etc.
|
||||
class ScopedGlobalRef {
|
||||
public:
|
||||
ScopedGlobalRef(JNIEnv* jni, T obj)
|
||||
: obj_(static_cast<T>(jni->NewGlobalRef(obj))) {}
|
||||
~ScopedGlobalRef() {
|
||||
DeleteGlobalRef(AttachCurrentThreadIfNeeded(), obj_);
|
||||
}
|
||||
T operator*() const {
|
||||
return obj_;
|
||||
}
|
||||
private:
|
||||
T obj_;
|
||||
};
|
||||
|
||||
// Java references to "null" can only be distinguished as such in C++ by
|
||||
// creating a local reference, so this helper wraps that logic.
|
||||
static bool IsNull(JNIEnv* jni, jobject obj) {
|
||||
ScopedLocalRefFrame local_ref_frame(jni);
|
||||
return jni->NewLocalRef(obj) == NULL;
|
||||
}
|
||||
|
||||
// Return the (singleton) Java Enum object corresponding to |index|;
|
||||
// |state_class_fragment| is something like "MediaSource$State".
|
||||
jobject JavaEnumFromIndex(
|
||||
JNIEnv* jni, const std::string& state_class_fragment, int index) {
|
||||
std::string state_class_name = "org/webrtc/" + state_class_fragment;
|
||||
jclass state_class = FindClass(jni, state_class_name.c_str());
|
||||
jmethodID state_values_id = GetStaticMethodID(
|
||||
jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
|
||||
jobjectArray state_values = static_cast<jobjectArray>(
|
||||
jni->CallStaticObjectMethod(state_class, state_values_id));
|
||||
CHECK_EXCEPTION(jni) << "error during CallStaticObjectMethod";
|
||||
jobject ret = jni->GetObjectArrayElement(state_values, index);
|
||||
CHECK_EXCEPTION(jni) << "error during GetObjectArrayElement";
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Given a UTF-8 encoded |native| string return a new (UTF-16) jstring.
|
||||
static jstring JavaStringFromStdString(JNIEnv* jni, const std::string& native) {
|
||||
UnicodeString ustr(UnicodeString::fromUTF8(native));
|
||||
jstring jstr = jni->NewString(ustr.getBuffer(), ustr.length());
|
||||
CHECK_EXCEPTION(jni) << "error during NewString";
|
||||
return jstr;
|
||||
}
|
||||
|
||||
// Given a (UTF-16) jstring return a new UTF-8 native string.
|
||||
static std::string JavaToStdString(JNIEnv* jni, const jstring& j_string) {
|
||||
const jchar* jchars = jni->GetStringChars(j_string, NULL);
|
||||
CHECK_EXCEPTION(jni) << "Error during GetStringChars";
|
||||
UnicodeString ustr(jchars, jni->GetStringLength(j_string));
|
||||
CHECK_EXCEPTION(jni) << "Error during GetStringLength";
|
||||
jni->ReleaseStringChars(j_string, jchars);
|
||||
CHECK_EXCEPTION(jni) << "Error during ReleaseStringChars";
|
||||
std::string ret;
|
||||
return ustr.toUTF8String(ret);
|
||||
const std::string state_class = "org/webrtc/" + state_class_fragment;
|
||||
return JavaEnumFromIndex(jni, FindClass(jni, state_class.c_str()),
|
||||
state_class, index);
|
||||
}
|
||||
|
||||
static DataChannelInit JavaDataChannelInitToNative(
|
||||
@ -1242,7 +859,7 @@ class JavaVideoRendererWrapper : public VideoRendererInterface {
|
||||
// into its own .h/.cc pair, if/when the JNI helper stuff above is extracted
|
||||
// from this file.
|
||||
|
||||
//#define TRACK_BUFFER_TIMING
|
||||
// #define TRACK_BUFFER_TIMING
|
||||
#define TAG "MediaCodecVideo"
|
||||
#ifdef TRACK_BUFFER_TIMING
|
||||
#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
|
||||
@ -1377,7 +994,7 @@ class MediaCodecVideoEncoder : public webrtc::VideoEncoder,
|
||||
int height_; // Frame height in pixels.
|
||||
bool inited_;
|
||||
uint16_t picture_id_;
|
||||
enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
|
||||
enum libyuv::FourCC encoder_fourcc_; // Encoder color space format.
|
||||
int last_set_bitrate_kbps_; // Last-requested bitrate in kbps.
|
||||
int last_set_fps_; // Last-requested frame rate.
|
||||
int64_t current_timestamp_us_; // Current frame timestamps in us.
|
||||
@ -1764,7 +1381,7 @@ int32_t MediaCodecVideoEncoder::ReleaseOnCodecThread() {
|
||||
CheckOnCodecThread();
|
||||
JNIEnv* jni = AttachCurrentThreadIfNeeded();
|
||||
ALOGD("EncoderRelease: Frames received: %d. Frames dropped: %d.",
|
||||
frames_received_,frames_dropped_);
|
||||
frames_received_, frames_dropped_);
|
||||
ScopedLocalRefFrame local_ref_frame(jni);
|
||||
for (size_t i = 0; i < input_buffers_.size(); ++i)
|
||||
jni->DeleteGlobalRef(input_buffers_[i]);
|
||||
@ -1888,7 +1505,7 @@ bool MediaCodecVideoEncoder::DeliverPendingOutputs(JNIEnv* jni) {
|
||||
current_encoding_time_ms_ / current_frames_, statistic_time_ms);
|
||||
start_time_ms_ = GetCurrentTimeMs();
|
||||
current_frames_ = 0;
|
||||
current_bytes_= 0;
|
||||
current_bytes_ = 0;
|
||||
current_encoding_time_ms_ = 0;
|
||||
}
|
||||
|
||||
@ -2517,7 +2134,8 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs(
|
||||
decoded_image_.CreateFrame(
|
||||
stride * slice_height, payload,
|
||||
(stride * slice_height) / 4, payload + (stride * slice_height),
|
||||
(stride * slice_height) / 4, payload + (5 * stride * slice_height / 4),
|
||||
(stride * slice_height) / 4,
|
||||
payload + (5 * stride * slice_height / 4),
|
||||
width, height,
|
||||
stride, stride / 2, stride / 2);
|
||||
} else {
|
||||
@ -2575,7 +2193,7 @@ bool MediaCodecVideoDecoder::DeliverPendingOutputs(
|
||||
current_decoding_time_ms_ / current_frames_, statistic_time_ms);
|
||||
start_time_ms_ = GetCurrentTimeMs();
|
||||
current_frames_ = 0;
|
||||
current_bytes_= 0;
|
||||
current_bytes_ = 0;
|
||||
current_decoding_time_ms_ = 0;
|
||||
}
|
||||
|
||||
@ -2672,108 +2290,8 @@ void MediaCodecVideoDecoderFactory::DestroyVideoDecoder(
|
||||
delete decoder;
|
||||
}
|
||||
|
||||
// AndroidVideoCapturerJni implements AndroidVideoCapturerDelegate.
|
||||
// The purpose of the delegate is to hide the JNI specifics from the C++ only
|
||||
// AndroidVideoCapturer.
|
||||
// TODO(perkj): Refactor this to a separate file once the jni utility functions
|
||||
// and classes have been moved.
|
||||
class AndroidVideoCapturerJni : public webrtc::AndroidVideoCapturerDelegate {
|
||||
public:
|
||||
static int SetAndroidObjects(JNIEnv* jni, jobject appliction_context) {
|
||||
if (application_context_) {
|
||||
jni->DeleteGlobalRef(application_context_);
|
||||
}
|
||||
application_context_ = NewGlobalRef(jni, appliction_context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
AndroidVideoCapturerJni(JNIEnv* jni, jobject j_video_capturer)
|
||||
: j_capturer_global_(jni, j_video_capturer),
|
||||
j_video_capturer_class_(
|
||||
jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")),
|
||||
j_frame_observer_class_(
|
||||
jni,
|
||||
FindClass(jni,
|
||||
"org/webrtc/VideoCapturerAndroid$NativeFrameObserver")) {
|
||||
}
|
||||
|
||||
void Start(int width, int height, int framerate,
|
||||
webrtc::AndroidVideoCapturer* capturer) override {
|
||||
j_frame_observer_ = NewGlobalRef(
|
||||
jni(),
|
||||
jni()->NewObject(*j_frame_observer_class_,
|
||||
GetMethodID(jni(),
|
||||
*j_frame_observer_class_,
|
||||
"<init>",
|
||||
"(J)V"),
|
||||
jlongFromPointer(capturer)));
|
||||
CHECK_EXCEPTION(jni()) << "error during NewObject";
|
||||
|
||||
jmethodID m = GetMethodID(
|
||||
jni(), *j_video_capturer_class_, "startCapture",
|
||||
"(IIILandroid/content/Context;"
|
||||
"Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V");
|
||||
jni()->CallVoidMethod(*j_capturer_global_,
|
||||
m, width, height,
|
||||
framerate,
|
||||
application_context_,
|
||||
j_frame_observer_);
|
||||
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
|
||||
}
|
||||
|
||||
bool Stop() override {
|
||||
jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
|
||||
"stopCapture", "()Z");
|
||||
jboolean result = jni()->CallBooleanMethod(*j_capturer_global_, m);
|
||||
CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
|
||||
DeleteGlobalRef(jni(), j_frame_observer_);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetSupportedFormats() override {
|
||||
jmethodID m =
|
||||
GetMethodID(jni(), *j_video_capturer_class_,
|
||||
"getSupportedFormatsAsJson", "()Ljava/lang/String;");
|
||||
jstring j_json_caps =
|
||||
(jstring) jni()->CallObjectMethod(*j_capturer_global_, m);
|
||||
CHECK_EXCEPTION(jni()) << "error during supportedFormatsAsJson";
|
||||
return JavaToStdString(jni(), j_json_caps);
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* jni() { return AttachCurrentThreadIfNeeded(); }
|
||||
|
||||
const ScopedGlobalRef<jobject> j_capturer_global_;
|
||||
const ScopedGlobalRef<jclass> j_video_capturer_class_;
|
||||
const ScopedGlobalRef<jclass> j_frame_observer_class_;
|
||||
jobject j_frame_observer_;
|
||||
|
||||
static jobject application_context_;
|
||||
};
|
||||
|
||||
jobject AndroidVideoCapturerJni::application_context_ = nullptr;
|
||||
|
||||
JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeOnFrameCaptured)
|
||||
(JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame,
|
||||
jint rotation, jlong ts) {
|
||||
jbyte* bytes = jni->GetByteArrayElements(j_frame, NULL);
|
||||
reinterpret_cast<webrtc::AndroidVideoCapturer*>(
|
||||
j_capturer)->OnIncomingFrame(bytes, jni->GetArrayLength(j_frame),
|
||||
rotation, ts);
|
||||
jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
|
||||
}
|
||||
|
||||
JOW(void, VideoCapturerAndroid_00024NativeFrameObserver_nativeCapturerStarted)
|
||||
(JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
|
||||
reinterpret_cast<webrtc::AndroidVideoCapturer*>(
|
||||
j_capturer)->OnCapturerStarted(j_success);
|
||||
}
|
||||
|
||||
#endif // #if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
static DataChannelInterface* ExtractNativeDC(JNIEnv* jni, jobject j_dc) {
|
||||
jfieldID native_dc_id = GetFieldID(jni,
|
||||
GetObjectClass(jni, j_dc), "nativeDataChannel", "J");
|
||||
@ -2923,16 +2441,15 @@ JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
|
||||
JNIEnv* jni, jclass, jobject context,
|
||||
jboolean initialize_audio, jboolean initialize_video,
|
||||
jboolean vp8_hw_acceleration, jobject render_egl_context) {
|
||||
CHECK(g_jvm) << "JNI_OnLoad failed to run?";
|
||||
bool failure = false;
|
||||
vp8_hw_acceleration_enabled = vp8_hw_acceleration;
|
||||
if (!factory_static_initialized) {
|
||||
if (initialize_video) {
|
||||
failure |= webrtc::SetRenderAndroidVM(g_jvm);
|
||||
failure |= webrtc::SetRenderAndroidVM(GetJVM());
|
||||
failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context);
|
||||
}
|
||||
if (initialize_audio)
|
||||
failure |= webrtc::VoiceEngine::SetAndroidObjects(g_jvm, jni, context);
|
||||
failure |= webrtc::VoiceEngine::SetAndroidObjects(GetJVM(), jni, context);
|
||||
factory_static_initialized = true;
|
||||
}
|
||||
if (initialize_video) {
|
||||
@ -2953,7 +2470,7 @@ JOW(void, PeerConnectionFactory_initializeFieldTrials)(
|
||||
field_trials_init_string = new char[init_string_length + 1];
|
||||
rtc::strcpyn(field_trials_init_string, init_string_length + 1, init_string);
|
||||
jni->ReleaseStringUTFChars(j_trials_init_string, init_string);
|
||||
LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string ;
|
||||
LOG(LS_INFO) << "initializeFieldTrials: " << field_trials_init_string;
|
||||
}
|
||||
webrtc::field_trial::InitFieldTrialsFromString(field_trials_init_string);
|
||||
}
|
||||
@ -3505,3 +3022,5 @@ JOW(void, VideoTrack_nativeRemoveRenderer)(
|
||||
reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
|
||||
reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
|
||||
}
|
||||
|
||||
} // namespace webrtc_jni
|
||||
|
@ -50,7 +50,11 @@
|
||||
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
|
||||
],
|
||||
'sources': [
|
||||
'app/webrtc/java/jni/peerconnection_jni.cc'
|
||||
'app/webrtc/java/jni/classreferenceholder.cc',
|
||||
'app/webrtc/java/jni/classreferenceholder.h',
|
||||
'app/webrtc/java/jni/jni_helpers.cc',
|
||||
'app/webrtc/java/jni/jni_helpers.h',
|
||||
'app/webrtc/java/jni/peerconnection_jni.cc',
|
||||
],
|
||||
'include_dirs': [
|
||||
'<(DEPTH)/third_party/libyuv/include',
|
||||
@ -71,6 +75,12 @@
|
||||
],
|
||||
},
|
||||
}],
|
||||
['OS=="android"', {
|
||||
'sources': [
|
||||
'app/webrtc/java/jni/androidvideocapturer_jni.cc',
|
||||
'app/webrtc/java/jni/androidvideocapturer_jni.h',
|
||||
]
|
||||
}],
|
||||
],
|
||||
},
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user