PeerConnection(java): replace ScopedLocalRef with ScopedLocalRefFrame and fix a local reference leak in OnMessage.

Hopefully the approach of pushing/popping frames will be easier to avoid messing up than remembering to annotate every single local reference with a ScopedLocalRef.

BUG=2761
R=wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/6729004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5355 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
fischman@webrtc.org 2014-01-09 00:31:17 +00:00
parent 1794693ec8
commit 4177615e87

View File

@ -376,22 +376,20 @@ class WeakRef {
jobject const obj_; jobject const obj_;
}; };
// Given a local ref, take ownership of it and delete the ref when this goes out // Scope Java local references to the lifetime of this object. Use in all C++
// of scope. // callbacks (i.e. entry points that don't originate in a Java callstack
template<class T> // T is jclass, jobject, jintArray, etc. // through a "native" method call).
class ScopedLocalRef { class ScopedLocalRefFrame {
public: public:
ScopedLocalRef(JNIEnv* jni, T obj) explicit ScopedLocalRefFrame(JNIEnv* jni) : jni_(jni) {
: jni_(jni), obj_(obj) {} CHECK(!jni_->PushLocalFrame(0), "Failed to PushLocalFrame");
~ScopedLocalRef() {
jni_->DeleteLocalRef(obj_);
} }
T operator*() const { ~ScopedLocalRefFrame() {
return obj_; jni_->PopLocalFrame(NULL);
} }
private: private:
JNIEnv* jni_; JNIEnv* jni_;
T obj_;
}; };
// Scoped holder for global Java refs. // Scoped holder for global Java refs.
@ -418,11 +416,10 @@ jobject JavaEnumFromIndex(
jclass state_class = FindClass(jni, state_class_name.c_str()); jclass state_class = FindClass(jni, state_class_name.c_str());
jmethodID state_values_id = GetStaticMethodID( jmethodID state_values_id = GetStaticMethodID(
jni, state_class, "values", ("()[L" + state_class_name + ";").c_str()); jni, state_class, "values", ("()[L" + state_class_name + ";").c_str());
ScopedLocalRef<jobjectArray> state_values( jobjectArray state_values = static_cast<jobjectArray>(
jni, jni->CallStaticObjectMethod(state_class, state_values_id));
(jobjectArray)jni->CallStaticObjectMethod(state_class, state_values_id));
CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod"); CHECK_EXCEPTION(jni, "error during CallStaticObjectMethod");
jobject ret = jni->GetObjectArrayElement(*state_values, index); jobject ret = jni->GetObjectArrayElement(state_values, index);
CHECK_EXCEPTION(jni, "error during GetObjectArrayElement"); CHECK_EXCEPTION(jni, "error during GetObjectArrayElement");
return ret; return ret;
} }
@ -500,20 +497,20 @@ class PCOJava : public PeerConnectionObserver {
virtual ~PCOJava() {} virtual ~PCOJava() {}
virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE { virtual void OnIceCandidate(const IceCandidateInterface* candidate) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
std::string sdp; std::string sdp;
CHECK(candidate->ToString(&sdp), "got so far: " << sdp); CHECK(candidate->ToString(&sdp), "got so far: " << sdp);
jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate"); jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
jmethodID ctor = GetMethodID(jni(), candidate_class, jmethodID ctor = GetMethodID(jni(), candidate_class,
"<init>", "(Ljava/lang/String;ILjava/lang/String;)V"); "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
ScopedLocalRef<jstring> j_mid( jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
jni(), JavaStringFromStdString(jni(), candidate->sdp_mid())); jstring j_sdp = JavaStringFromStdString(jni(), sdp);
ScopedLocalRef<jstring> j_sdp(jni(), JavaStringFromStdString(jni(), sdp)); jobject j_candidate = jni()->NewObject(
ScopedLocalRef<jobject> j_candidate(jni(), jni()->NewObject( candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp);
candidate_class, ctor, *j_mid, candidate->sdp_mline_index(), *j_sdp));
CHECK_EXCEPTION(jni(), "error during NewObject"); CHECK_EXCEPTION(jni(), "error during NewObject");
jmethodID m = GetMethodID(jni(), *j_observer_class_, jmethodID m = GetMethodID(jni(), *j_observer_class_,
"onIceCandidate", "(Lorg/webrtc/IceCandidate;)V"); "onIceCandidate", "(Lorg/webrtc/IceCandidate;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_candidate); jni()->CallVoidMethod(*j_observer_global_, m, j_candidate);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
@ -525,59 +522,63 @@ class PCOJava : public PeerConnectionObserver {
virtual void OnSignalingChange( virtual void OnSignalingChange(
PeerConnectionInterface::SignalingState new_state) OVERRIDE { PeerConnectionInterface::SignalingState new_state) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jmethodID m = GetMethodID( jmethodID m = GetMethodID(
jni(), *j_observer_class_, "onSignalingChange", jni(), *j_observer_class_, "onSignalingChange",
"(Lorg/webrtc/PeerConnection$SignalingState;)V"); "(Lorg/webrtc/PeerConnection$SignalingState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex( jobject new_state_enum =
jni(), "PeerConnection$SignalingState", new_state)); JavaEnumFromIndex(jni(), "PeerConnection$SignalingState", new_state);
jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum); jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
virtual void OnIceConnectionChange( virtual void OnIceConnectionChange(
PeerConnectionInterface::IceConnectionState new_state) OVERRIDE { PeerConnectionInterface::IceConnectionState new_state) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jmethodID m = GetMethodID( jmethodID m = GetMethodID(
jni(), *j_observer_class_, "onIceConnectionChange", jni(), *j_observer_class_, "onIceConnectionChange",
"(Lorg/webrtc/PeerConnection$IceConnectionState;)V"); "(Lorg/webrtc/PeerConnection$IceConnectionState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex( jobject new_state_enum = JavaEnumFromIndex(
jni(), "PeerConnection$IceConnectionState", new_state)); jni(), "PeerConnection$IceConnectionState", new_state);
jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum); jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
virtual void OnIceGatheringChange( virtual void OnIceGatheringChange(
PeerConnectionInterface::IceGatheringState new_state) OVERRIDE { PeerConnectionInterface::IceGatheringState new_state) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jmethodID m = GetMethodID( jmethodID m = GetMethodID(
jni(), *j_observer_class_, "onIceGatheringChange", jni(), *j_observer_class_, "onIceGatheringChange",
"(Lorg/webrtc/PeerConnection$IceGatheringState;)V"); "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
ScopedLocalRef<jobject> new_state_enum(jni(), JavaEnumFromIndex( jobject new_state_enum = JavaEnumFromIndex(
jni(), "PeerConnection$IceGatheringState", new_state)); jni(), "PeerConnection$IceGatheringState", new_state);
jni()->CallVoidMethod(*j_observer_global_, m, *new_state_enum); jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE { virtual void OnAddStream(MediaStreamInterface* stream) OVERRIDE {
ScopedLocalRef<jobject> j_stream(jni(), jni()->NewObject( ScopedLocalRefFrame local_ref_frame(jni());
*j_media_stream_class_, j_media_stream_ctor_, (jlong)stream)); jobject j_stream = jni()->NewObject(
*j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
CHECK_EXCEPTION(jni(), "error during NewObject"); CHECK_EXCEPTION(jni(), "error during NewObject");
AudioTrackVector audio_tracks = stream->GetAudioTracks(); AudioTrackVector audio_tracks = stream->GetAudioTracks();
for (size_t i = 0; i < audio_tracks.size(); ++i) { for (size_t i = 0; i < audio_tracks.size(); ++i) {
AudioTrackInterface* track = audio_tracks[i]; AudioTrackInterface* track = audio_tracks[i];
ScopedLocalRef<jstring> id( jstring id = JavaStringFromStdString(jni(), track->id());
jni(), JavaStringFromStdString(jni(), track->id())); jobject j_track = jni()->NewObject(
ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject( *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
*j_audio_track_class_, j_audio_track_ctor_, (jlong)track, *id));
CHECK_EXCEPTION(jni(), "error during NewObject"); CHECK_EXCEPTION(jni(), "error during NewObject");
jfieldID audio_tracks_id = GetFieldID(jni(), jfieldID audio_tracks_id = GetFieldID(jni(),
*j_media_stream_class_, *j_media_stream_class_,
"audioTracks", "audioTracks",
"Ljava/util/LinkedList;"); "Ljava/util/LinkedList;");
ScopedLocalRef<jobject> audio_tracks(jni(), GetObjectField( jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
jni(), *j_stream, audio_tracks_id));
jmethodID add = GetMethodID(jni(), jmethodID add = GetMethodID(jni(),
GetObjectClass(jni(), *audio_tracks), "add", "(Ljava/lang/Object;)Z"); GetObjectClass(jni(), audio_tracks),
jboolean added = jni()->CallBooleanMethod(*audio_tracks, add, *j_track); "add",
"(Ljava/lang/Object;)Z");
jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
CHECK_EXCEPTION(jni(), "error during CallBooleanMethod"); CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
CHECK(added, ""); CHECK(added, "");
} }
@ -585,33 +586,34 @@ class PCOJava : public PeerConnectionObserver {
VideoTrackVector video_tracks = stream->GetVideoTracks(); VideoTrackVector video_tracks = stream->GetVideoTracks();
for (size_t i = 0; i < video_tracks.size(); ++i) { for (size_t i = 0; i < video_tracks.size(); ++i) {
VideoTrackInterface* track = video_tracks[i]; VideoTrackInterface* track = video_tracks[i];
ScopedLocalRef<jstring> id( jstring id = JavaStringFromStdString(jni(), track->id());
jni(), JavaStringFromStdString(jni(), track->id())); jobject j_track = jni()->NewObject(
ScopedLocalRef<jobject> j_track(jni(), jni()->NewObject( *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
*j_video_track_class_, j_video_track_ctor_, (jlong)track, *id));
CHECK_EXCEPTION(jni(), "error during NewObject"); CHECK_EXCEPTION(jni(), "error during NewObject");
jfieldID video_tracks_id = GetFieldID(jni(), jfieldID video_tracks_id = GetFieldID(jni(),
*j_media_stream_class_, *j_media_stream_class_,
"videoTracks", "videoTracks",
"Ljava/util/LinkedList;"); "Ljava/util/LinkedList;");
ScopedLocalRef<jobject> video_tracks(jni(), GetObjectField( jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
jni(), *j_stream, video_tracks_id));
jmethodID add = GetMethodID(jni(), jmethodID add = GetMethodID(jni(),
GetObjectClass(jni(), *video_tracks), "add", "(Ljava/lang/Object;)Z"); GetObjectClass(jni(), video_tracks),
jboolean added = jni()->CallBooleanMethod(*video_tracks, add, *j_track); "add",
"(Ljava/lang/Object;)Z");
jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
CHECK_EXCEPTION(jni(), "error during CallBooleanMethod"); CHECK_EXCEPTION(jni(), "error during CallBooleanMethod");
CHECK(added, ""); CHECK(added, "");
} }
streams_[stream] = jni()->NewWeakGlobalRef(*j_stream); streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef"); CHECK_EXCEPTION(jni(), "error during NewWeakGlobalRef");
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
"(Lorg/webrtc/MediaStream;)V"); "(Lorg/webrtc/MediaStream;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_stream); jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE { virtual void OnRemoveStream(MediaStreamInterface* stream) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
NativeToJavaStreamsMap::iterator it = streams_.find(stream); NativeToJavaStreamsMap::iterator it = streams_.find(stream);
CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream); CHECK(it != streams_.end(), "unexpected stream: " << std::hex << stream);
@ -627,13 +629,14 @@ class PCOJava : public PeerConnectionObserver {
} }
virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE { virtual void OnDataChannel(DataChannelInterface* channel) OVERRIDE {
ScopedLocalRef<jobject> j_channel(jni(), jni()->NewObject( ScopedLocalRefFrame local_ref_frame(jni());
*j_data_channel_class_, j_data_channel_ctor_, (jlong)channel)); jobject j_channel = jni()->NewObject(
*j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
CHECK_EXCEPTION(jni(), "error during NewObject"); CHECK_EXCEPTION(jni(), "error during NewObject");
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
"(Lorg/webrtc/DataChannel;)V"); "(Lorg/webrtc/DataChannel;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_channel); jni()->CallVoidMethod(*j_observer_global_, m, j_channel);
// Channel is now owned by Java object, and will be freed from // Channel is now owned by Java object, and will be freed from
// DataChannel.dispose(). Important that this be done _after_ the // DataChannel.dispose(). Important that this be done _after_ the
@ -738,17 +741,16 @@ static jobject JavaSdpFromNativeSdp(
JNIEnv* jni, const SessionDescriptionInterface* desc) { JNIEnv* jni, const SessionDescriptionInterface* desc) {
std::string sdp; std::string sdp;
CHECK(desc->ToString(&sdp), "got so far: " << sdp); CHECK(desc->ToString(&sdp), "got so far: " << sdp);
ScopedLocalRef<jstring> j_description(jni, JavaStringFromStdString(jni, sdp)); jstring j_description = JavaStringFromStdString(jni, sdp);
jclass j_type_class = FindClass( jclass j_type_class = FindClass(
jni, "org/webrtc/SessionDescription$Type"); jni, "org/webrtc/SessionDescription$Type");
jmethodID j_type_from_canonical = GetStaticMethodID( jmethodID j_type_from_canonical = GetStaticMethodID(
jni, j_type_class, "fromCanonicalForm", jni, j_type_class, "fromCanonicalForm",
"(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;"); "(Ljava/lang/String;)Lorg/webrtc/SessionDescription$Type;");
ScopedLocalRef<jstring> j_type_string( jstring j_type_string = JavaStringFromStdString(jni, desc->type());
jni, JavaStringFromStdString(jni, desc->type()));
jobject j_type = jni->CallStaticObjectMethod( jobject j_type = jni->CallStaticObjectMethod(
j_type_class, j_type_from_canonical, *j_type_string); j_type_class, j_type_from_canonical, j_type_string);
CHECK_EXCEPTION(jni, "error during CallObjectMethod"); CHECK_EXCEPTION(jni, "error during CallObjectMethod");
jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription"); jclass j_sdp_class = FindClass(jni, "org/webrtc/SessionDescription");
@ -756,7 +758,7 @@ static jobject JavaSdpFromNativeSdp(
jni, j_sdp_class, "<init>", jni, j_sdp_class, "<init>",
"(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V"); "(Lorg/webrtc/SessionDescription$Type;Ljava/lang/String;)V");
jobject j_sdp = jni->NewObject( jobject j_sdp = jni->NewObject(
j_sdp_class, j_sdp_ctor, j_type, *j_description); j_sdp_class, j_sdp_ctor, j_type, j_description);
CHECK_EXCEPTION(jni, "error during NewObject"); CHECK_EXCEPTION(jni, "error during NewObject");
return j_sdp; return j_sdp;
} }
@ -775,6 +777,7 @@ class SdpObserverWrapper : public T {
// Can't mark OVERRIDE because of templating. // Can't mark OVERRIDE because of templating.
virtual void OnSuccess() { virtual void OnSuccess() {
ScopedLocalRefFrame local_ref_frame(jni());
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V"); jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSetSuccess", "()V");
jni()->CallVoidMethod(*j_observer_global_, m); jni()->CallVoidMethod(*j_observer_global_, m);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
@ -782,11 +785,12 @@ class SdpObserverWrapper : public T {
// Can't mark OVERRIDE because of templating. // Can't mark OVERRIDE because of templating.
virtual void OnSuccess(SessionDescriptionInterface* desc) { virtual void OnSuccess(SessionDescriptionInterface* desc) {
ScopedLocalRefFrame local_ref_frame(jni());
jmethodID m = GetMethodID( jmethodID m = GetMethodID(
jni(), *j_observer_class_, "onCreateSuccess", jni(), *j_observer_class_, "onCreateSuccess",
"(Lorg/webrtc/SessionDescription;)V"); "(Lorg/webrtc/SessionDescription;)V");
ScopedLocalRef<jobject> j_sdp(jni(), JavaSdpFromNativeSdp(jni(), desc)); jobject j_sdp = JavaSdpFromNativeSdp(jni(), desc);
jni()->CallVoidMethod(*j_observer_global_, m, *j_sdp); jni()->CallVoidMethod(*j_observer_global_, m, j_sdp);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
@ -796,17 +800,16 @@ class SdpObserverWrapper : public T {
void OnFailure(const std::string& op, const std::string& error) { void OnFailure(const std::string& op, const std::string& error) {
jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure", jmethodID m = GetMethodID(jni(), *j_observer_class_, "on" + op + "Failure",
"(Ljava/lang/String;)V"); "(Ljava/lang/String;)V");
ScopedLocalRef<jstring> j_error_string( jstring j_error_string = JavaStringFromStdString(jni(), error);
jni(), JavaStringFromStdString(jni(), error)); jni()->CallVoidMethod(*j_observer_global_, m, j_error_string);
jni()->CallVoidMethod(*j_observer_global_, m, *j_error_string);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
private:
JNIEnv* jni() { JNIEnv* jni() {
return AttachCurrentThreadIfNeeded(); return AttachCurrentThreadIfNeeded();
} }
private:
talk_base::scoped_ptr<ConstraintsWrapper> constraints_; talk_base::scoped_ptr<ConstraintsWrapper> constraints_;
const ScopedGlobalRef<jobject> j_observer_global_; const ScopedGlobalRef<jobject> j_observer_global_;
const ScopedGlobalRef<jclass> j_observer_class_; const ScopedGlobalRef<jclass> j_observer_class_;
@ -820,6 +823,7 @@ class CreateSdpObserverWrapper
: SdpObserverWrapper(jni, j_observer, constraints) {} : SdpObserverWrapper(jni, j_observer, constraints) {}
virtual void OnFailure(const std::string& error) OVERRIDE { virtual void OnFailure(const std::string& error) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
SdpObserverWrapper::OnFailure(std::string("Create"), error); SdpObserverWrapper::OnFailure(std::string("Create"), error);
} }
}; };
@ -832,6 +836,7 @@ class SetSdpObserverWrapper
: SdpObserverWrapper(jni, j_observer, constraints) {} : SdpObserverWrapper(jni, j_observer, constraints) {}
virtual void OnFailure(const std::string& error) OVERRIDE { virtual void OnFailure(const std::string& error) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
SdpObserverWrapper::OnFailure(std::string("Set"), error); SdpObserverWrapper::OnFailure(std::string("Set"), error);
} }
}; };
@ -855,11 +860,13 @@ class DataChannelObserverWrapper : public DataChannelObserver {
virtual ~DataChannelObserverWrapper() {} virtual ~DataChannelObserverWrapper() {}
virtual void OnStateChange() OVERRIDE { virtual void OnStateChange() OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_); jni()->CallVoidMethod(*j_observer_global_, j_on_state_change_mid_);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
virtual void OnMessage(const DataBuffer& buffer) OVERRIDE { virtual void OnMessage(const DataBuffer& buffer) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jobject byte_buffer = jobject byte_buffer =
jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()), jni()->NewDirectByteBuffer(const_cast<char*>(buffer.data.data()),
buffer.data.length()); buffer.data.length());
@ -904,11 +911,11 @@ class StatsObserverWrapper : public StatsObserver {
virtual ~StatsObserverWrapper() {} virtual ~StatsObserverWrapper() {}
virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE { virtual void OnComplete(const std::vector<StatsReport>& reports) OVERRIDE {
ScopedLocalRef<jobjectArray> j_reports(jni(), ScopedLocalRefFrame local_ref_frame(jni());
ReportsToJava(jni(), reports)); jobjectArray j_reports = ReportsToJava(jni(), reports);
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete", jmethodID m = GetMethodID(jni(), *j_observer_class_, "onComplete",
"([Lorg/webrtc/StatsReport;)V"); "([Lorg/webrtc/StatsReport;)V");
jni()->CallVoidMethod(*j_observer_global_, m, *j_reports); jni()->CallVoidMethod(*j_observer_global_, m, j_reports);
CHECK_EXCEPTION(jni(), "error during CallVoidMethod"); CHECK_EXCEPTION(jni(), "error during CallVoidMethod");
} }
@ -918,17 +925,18 @@ class StatsObserverWrapper : public StatsObserver {
jobjectArray reports_array = jni->NewObjectArray( jobjectArray reports_array = jni->NewObjectArray(
reports.size(), *j_stats_report_class_, NULL); reports.size(), *j_stats_report_class_, NULL);
for (int i = 0; i < reports.size(); ++i) { for (int i = 0; i < reports.size(); ++i) {
ScopedLocalRefFrame local_ref_frame(jni);
const StatsReport& report = reports[i]; const StatsReport& report = reports[i];
ScopedLocalRef<jstring> j_id( jstring j_id = JavaStringFromStdString(jni, report.id);
jni, JavaStringFromStdString(jni, report.id)); jstring j_type = JavaStringFromStdString(jni, report.type);
ScopedLocalRef<jstring> j_type( jobjectArray j_values = ValuesToJava(jni, report.values);
jni, JavaStringFromStdString(jni, report.type)); jobject j_report = jni->NewObject(*j_stats_report_class_,
ScopedLocalRef<jobjectArray> j_values( j_stats_report_ctor_,
jni, ValuesToJava(jni, report.values)); j_id,
ScopedLocalRef<jobject> j_report(jni, jni->NewObject( j_type,
*j_stats_report_class_, j_stats_report_ctor_, *j_id, *j_type, report.timestamp,
report.timestamp, *j_values)); j_values);
jni->SetObjectArrayElement(reports_array, i, *j_report); jni->SetObjectArrayElement(reports_array, i, j_report);
} }
return reports_array; return reports_array;
} }
@ -937,14 +945,13 @@ class StatsObserverWrapper : public StatsObserver {
jobjectArray j_values = jni->NewObjectArray( jobjectArray j_values = jni->NewObjectArray(
values.size(), *j_value_class_, NULL); values.size(), *j_value_class_, NULL);
for (int i = 0; i < values.size(); ++i) { for (int i = 0; i < values.size(); ++i) {
ScopedLocalRefFrame local_ref_frame(jni);
const StatsReport::Value& value = values[i]; const StatsReport::Value& value = values[i];
ScopedLocalRef<jstring> j_name( jstring j_name = JavaStringFromStdString(jni, value.name);
jni, JavaStringFromStdString(jni, value.name)); jstring j_value = JavaStringFromStdString(jni, value.value);
ScopedLocalRef<jstring> j_value( jobject j_element_value =
jni, JavaStringFromStdString(jni, value.value)); jni->NewObject(*j_value_class_, j_value_ctor_, j_name, j_value);
ScopedLocalRef<jobject> j_element_value(jni, jni->NewObject( jni->SetObjectArrayElement(j_values, i, j_element_value);
*j_value_class_, j_value_ctor_, *j_name, *j_value));
jni->SetObjectArrayElement(j_values, i, *j_element_value);
} }
return j_values; return j_values;
} }
@ -974,11 +981,13 @@ class VideoRendererWrapper : public VideoRendererInterface {
virtual ~VideoRendererWrapper() {} virtual ~VideoRendererWrapper() {}
virtual void SetSize(int width, int height) OVERRIDE { virtual void SetSize(int width, int height) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
const bool kNotReserved = false; // What does this param mean?? const bool kNotReserved = false; // What does this param mean??
renderer_->SetSize(width, height, kNotReserved); renderer_->SetSize(width, height, kNotReserved);
} }
virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE { virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(AttachCurrentThreadIfNeeded());
renderer_->RenderFrame(frame); renderer_->RenderFrame(frame);
} }
@ -1011,40 +1020,41 @@ class JavaVideoRendererWrapper : public VideoRendererInterface {
virtual ~JavaVideoRendererWrapper() {} virtual ~JavaVideoRendererWrapper() {}
virtual void SetSize(int width, int height) OVERRIDE { virtual void SetSize(int width, int height) OVERRIDE {
ScopedLocalRefFrame local_ref_frame(jni());
jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height); jni()->CallVoidMethod(*j_callbacks_, j_set_size_id_, width, height);
CHECK_EXCEPTION(jni(), ""); CHECK_EXCEPTION(jni(), "");
} }
virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE { virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE {
ScopedLocalRef<jobject> j_frame(jni(), CricketToJavaFrame(frame)); ScopedLocalRefFrame local_ref_frame(jni());
jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, *j_frame); jobject j_frame = CricketToJavaFrame(frame);
jni()->CallVoidMethod(*j_callbacks_, j_render_frame_id_, j_frame);
CHECK_EXCEPTION(jni(), ""); CHECK_EXCEPTION(jni(), "");
} }
private: private:
// Return a VideoRenderer.I420Frame referring to the data in |frame|. // Return a VideoRenderer.I420Frame referring to the data in |frame|.
jobject CricketToJavaFrame(const cricket::VideoFrame* frame) { jobject CricketToJavaFrame(const cricket::VideoFrame* frame) {
ScopedLocalRef<jintArray> strides(jni(), jni()->NewIntArray(3)); jintArray strides = jni()->NewIntArray(3);
jint* strides_array = jni()->GetIntArrayElements(*strides, NULL); jint* strides_array = jni()->GetIntArrayElements(strides, NULL);
strides_array[0] = frame->GetYPitch(); strides_array[0] = frame->GetYPitch();
strides_array[1] = frame->GetUPitch(); strides_array[1] = frame->GetUPitch();
strides_array[2] = frame->GetVPitch(); strides_array[2] = frame->GetVPitch();
jni()->ReleaseIntArrayElements(*strides, strides_array, 0); jni()->ReleaseIntArrayElements(strides, strides_array, 0);
ScopedLocalRef<jobjectArray> planes( jobjectArray planes = jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL);
jni(), jni()->NewObjectArray(3, *j_byte_buffer_class_, NULL)); jobject y_buffer = jni()->NewDirectByteBuffer(
ScopedLocalRef<jobject> y_buffer(jni(), jni()->NewDirectByteBuffer(
const_cast<uint8*>(frame->GetYPlane()), const_cast<uint8*>(frame->GetYPlane()),
frame->GetYPitch() * frame->GetHeight())); frame->GetYPitch() * frame->GetHeight());
ScopedLocalRef<jobject> u_buffer(jni(), jni()->NewDirectByteBuffer( jobject u_buffer = jni()->NewDirectByteBuffer(
const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize())); const_cast<uint8*>(frame->GetUPlane()), frame->GetChromaSize());
ScopedLocalRef<jobject> v_buffer(jni(), jni()->NewDirectByteBuffer( jobject v_buffer = jni()->NewDirectByteBuffer(
const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize())); const_cast<uint8*>(frame->GetVPlane()), frame->GetChromaSize());
jni()->SetObjectArrayElement(*planes, 0, *y_buffer); jni()->SetObjectArrayElement(planes, 0, y_buffer);
jni()->SetObjectArrayElement(*planes, 1, *u_buffer); jni()->SetObjectArrayElement(planes, 1, u_buffer);
jni()->SetObjectArrayElement(*planes, 2, *v_buffer); jni()->SetObjectArrayElement(planes, 2, v_buffer);
return jni()->NewObject( return jni()->NewObject(
*j_frame_class_, j_frame_ctor_id_, *j_frame_class_, j_frame_ctor_id_,
frame->GetWidth(), frame->GetHeight(), *strides, *planes); frame->GetWidth(), frame->GetHeight(), strides, planes);
} }
JNIEnv* jni() { JNIEnv* jni() {