| Index: talk/app/webrtc/java/jni/peerconnection_jni.cc
|
| diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc
|
| index c326ccff6bede1e3e93e5605be72be86a672df7d..503a75ee88d35029c5c9a3664c3ffbcf7b3d817b 100644
|
| --- a/talk/app/webrtc/java/jni/peerconnection_jni.cc
|
| +++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc
|
| @@ -206,7 +206,11 @@ class PCOJava : public PeerConnectionObserver {
|
| jni, *j_data_channel_class_, "<init>", "(J)V")) {
|
| }
|
|
|
| - virtual ~PCOJava() {}
|
| + virtual ~PCOJava() {
|
| + ScopedLocalRefFrame local_ref_frame(jni());
|
| + while (!remote_streams_.empty())
|
| + DisposeRemoteStream(remote_streams_.begin());
|
| + }
|
|
|
| void OnIceCandidate(const IceCandidateInterface* candidate) override {
|
| ScopedLocalRefFrame local_ref_frame(jni());
|
| @@ -272,16 +276,22 @@ class PCOJava : public PeerConnectionObserver {
|
|
|
| void OnAddStream(MediaStreamInterface* stream) override {
|
| ScopedLocalRefFrame local_ref_frame(jni());
|
| - jobject j_stream = jni()->NewObject(
|
| - *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream);
|
| + // Java MediaStream holds one reference. Corresponding Release() is in
|
| + // MediaStream_free, triggered by MediaStream.dispose().
|
| + stream->AddRef();
|
| + jobject j_stream =
|
| + jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_,
|
| + reinterpret_cast<jlong>(stream));
|
| CHECK_EXCEPTION(jni()) << "error during NewObject";
|
|
|
| - AudioTrackVector audio_tracks = stream->GetAudioTracks();
|
| - for (size_t i = 0; i < audio_tracks.size(); ++i) {
|
| - AudioTrackInterface* track = audio_tracks[i];
|
| + for (const auto& track : stream->GetAudioTracks()) {
|
| jstring id = JavaStringFromStdString(jni(), track->id());
|
| - jobject j_track = jni()->NewObject(
|
| - *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id);
|
| + // Java AudioTrack holds one reference. Corresponding Release() is in
|
| + // MediaStreamTrack_free, triggered by AudioTrack.dispose().
|
| + track->AddRef();
|
| + jobject j_track =
|
| + jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_,
|
| + reinterpret_cast<jlong>(track.get()), id);
|
| CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| jfieldID audio_tracks_id = GetFieldID(jni(),
|
| *j_media_stream_class_,
|
| @@ -297,12 +307,14 @@ class PCOJava : public PeerConnectionObserver {
|
| CHECK(added);
|
| }
|
|
|
| - VideoTrackVector video_tracks = stream->GetVideoTracks();
|
| - for (size_t i = 0; i < video_tracks.size(); ++i) {
|
| - VideoTrackInterface* track = video_tracks[i];
|
| + for (const auto& track : stream->GetVideoTracks()) {
|
| jstring id = JavaStringFromStdString(jni(), track->id());
|
| - jobject j_track = jni()->NewObject(
|
| - *j_video_track_class_, j_video_track_ctor_, (jlong)track, id);
|
| + // Java VideoTrack holds one reference. Corresponding Release() is in
|
| + // MediaStreamTrack_free, triggered by VideoTrack.dispose().
|
| + track->AddRef();
|
| + jobject j_track =
|
| + jni()->NewObject(*j_video_track_class_, j_video_track_ctor_,
|
| + reinterpret_cast<jlong>(track.get()), id);
|
| CHECK_EXCEPTION(jni()) << "error during NewObject";
|
| jfieldID video_tracks_id = GetFieldID(jni(),
|
| *j_media_stream_class_,
|
| @@ -317,8 +329,7 @@ class PCOJava : public PeerConnectionObserver {
|
| CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
|
| CHECK(added);
|
| }
|
| - streams_[stream] = jni()->NewWeakGlobalRef(j_stream);
|
| - CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
|
| + remote_streams_[stream] = NewGlobalRef(jni(), j_stream);
|
|
|
| jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
|
| "(Lorg/webrtc/MediaStream;)V");
|
| @@ -328,18 +339,15 @@ class PCOJava : public PeerConnectionObserver {
|
|
|
| void OnRemoveStream(MediaStreamInterface* stream) override {
|
| ScopedLocalRefFrame local_ref_frame(jni());
|
| - NativeToJavaStreamsMap::iterator it = streams_.find(stream);
|
| - CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream;
|
| -
|
| - WeakRef s(jni(), it->second);
|
| - streams_.erase(it);
|
| - if (!s.obj())
|
| - return;
|
| -
|
| + NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
|
| + CHECK(it != remote_streams_.end()) << "unexpected stream: " << std::hex
|
| + << stream;
|
| + jobject j_stream = it->second;
|
| jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
|
| "(Lorg/webrtc/MediaStream;)V");
|
| - jni()->CallVoidMethod(*j_observer_global_, m, s.obj());
|
| + jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
|
| CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
|
| + DisposeRemoteStream(it);
|
| }
|
|
|
| void OnDataChannel(DataChannelInterface* channel) override {
|
| @@ -378,6 +386,17 @@ class PCOJava : public PeerConnectionObserver {
|
| const ConstraintsWrapper* constraints() { return constraints_.get(); }
|
|
|
| private:
|
| + typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap;
|
| +
|
| + void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it) {
|
| + jobject j_stream = it->second;
|
| + remote_streams_.erase(it);
|
| + jni()->CallVoidMethod(
|
| + j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V"));
|
| + CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()";
|
| + DeleteGlobalRef(jni(), j_stream);
|
| + }
|
| +
|
| JNIEnv* jni() {
|
| return AttachCurrentThreadIfNeeded();
|
| }
|
| @@ -392,8 +411,9 @@ class PCOJava : public PeerConnectionObserver {
|
| const jmethodID j_video_track_ctor_;
|
| const ScopedGlobalRef<jclass> j_data_channel_class_;
|
| const jmethodID j_data_channel_ctor_;
|
| - typedef std::map<void*, jweak> NativeToJavaStreamsMap;
|
| - NativeToJavaStreamsMap streams_; // C++ -> Java streams.
|
| + // C++ -> Java remote streams. The stored jobects are global refs and must be
|
| + // manually deleted upon removal. Use DisposeRemoteStream().
|
| + NativeToJavaStreamsMap remote_streams_;
|
| scoped_ptr<ConstraintsWrapper> constraints_;
|
| };
|
|
|
|
|