Index: webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc |
diff --git a/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc b/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc |
index 18767925933ffb6006845d83b1fd2d3edb0954f5..e48fa41d3bf9ceab8fc06109f164c2e482465dd3 100644 |
--- a/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc |
+++ b/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc |
@@ -10,6 +10,7 @@ |
#include "webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.h" |
+#include <webrtc/pc/mediastreamobserver.h> |
#include <string> |
#include "webrtc/sdk/android/src/jni/classreferenceholder.h" |
@@ -38,17 +39,18 @@ PeerConnectionObserverJni::PeerConnectionObserverJni(JNIEnv* jni, |
GetMethodID(jni, *j_video_track_class_, "<init>", "(J)V")), |
j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")), |
j_data_channel_ctor_( |
- GetMethodID(jni, *j_data_channel_class_, "<init>", "(J)V")), |
- j_rtp_receiver_class_(jni, FindClass(jni, "org/webrtc/RtpReceiver")), |
- j_rtp_receiver_ctor_( |
- GetMethodID(jni, *j_rtp_receiver_class_, "<init>", "(J)V")) {} |
+ GetMethodID(jni, *j_data_channel_class_, "<init>", "(J)V")) {} |
PeerConnectionObserverJni::~PeerConnectionObserverJni() { |
ScopedLocalRefFrame local_ref_frame(jni()); |
+ stream_observers_.clear(); |
+ while (!remote_tracks_.empty()) { |
+ NativeToJavaMediaTrackMap::iterator it = remote_tracks_.begin(); |
+ DeleteGlobalRef(jni(), it->second); |
+ remote_tracks_.erase(it); |
+ } |
while (!remote_streams_.empty()) |
DisposeRemoteStream(remote_streams_.begin()); |
- while (!rtp_receivers_.empty()) |
- DisposeRtpReceiver(rtp_receivers_.begin()); |
} |
void PeerConnectionObserverJni::OnIceCandidate( |
@@ -132,47 +134,155 @@ void PeerConnectionObserverJni::OnAddStream( |
jobject j_stream = GetOrCreateJavaStream(stream); |
for (const auto& track : stream->GetAudioTracks()) { |
- jstring id = JavaStringFromStdString(jni(), 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_, "audioTracks", "Ljava/util/LinkedList;"); |
- jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); |
- jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), audio_tracks), |
- "add", "(Ljava/lang/Object;)Z"); |
- jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track); |
- CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
- RTC_CHECK(added); |
+ OnAudioTrackAdded(track, stream); |
} |
for (const auto& track : stream->GetVideoTracks()) { |
- jstring id = JavaStringFromStdString(jni(), 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_, "videoTracks", "Ljava/util/LinkedList;"); |
- jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); |
- jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), video_tracks), |
- "add", "(Ljava/lang/Object;)Z"); |
- jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track); |
- CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
- RTC_CHECK(added); |
+ OnVideoTrackAdded(track, stream); |
} |
jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", |
"(Lorg/webrtc/MediaStream;)V"); |
jni()->CallVoidMethod(*j_observer_global_, m, j_stream); |
CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+ |
+ webrtc::MediaStreamObserver* observer = |
+ new webrtc::MediaStreamObserver(stream); |
+ observer->SignalVideoTrackAdded.connect( |
+ this, &PeerConnectionObserverJni::OnVideoTrackAdded); |
+ observer->SignalAudioTrackAdded.connect( |
+ this, &PeerConnectionObserverJni::OnAudioTrackAdded); |
+ observer->SignalAudioTrackRemoved.connect( |
+ this, &PeerConnectionObserverJni::OnAudioTrackRemoved); |
+ observer->SignalVideoTrackRemoved.connect( |
+ this, &PeerConnectionObserverJni::OnVideoTrackRemoved); |
+ stream_observers_.push_back( |
+ std::unique_ptr<webrtc::MediaStreamObserver>(observer)); |
+} |
+ |
+void PeerConnectionObserverJni::OnAudioTrackAdded( |
+ webrtc::AudioTrackInterface* track, |
+ webrtc::MediaStreamInterface* stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jstring id = JavaStringFromStdString(jni(), track->id()); |
+ jobject j_stream = GetOrCreateJavaStream(stream); |
+ // 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), id); |
+ CHECK_EXCEPTION(jni()) << "error during NewObject"; |
+ remote_tracks_[track] = NewGlobalRef(jni(), j_track); |
+ jfieldID audio_tracks_id = GetFieldID( |
+ jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/LinkedList;"); |
+ jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); |
+ jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), audio_tracks), "add", |
+ "(Ljava/lang/Object;)Z"); |
+ jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track); |
+ CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
+ RTC_CHECK(added); |
+ |
+ std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> streams; |
+ streams.push_back(rtc::scoped_refptr<webrtc::MediaStreamInterface>(stream)); |
+ jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onAddTrack", |
+ "(Lorg/webrtc/MediaStreamTrack;[Lorg/webrtc/MediaStream;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_track, j_stream_array); |
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnVideoTrackAdded( |
+ webrtc::VideoTrackInterface* track, |
+ webrtc::MediaStreamInterface* stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jobject j_stream = GetOrCreateJavaStream(stream); |
+ |
+ jstring id = JavaStringFromStdString(jni(), 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), id); |
+ CHECK_EXCEPTION(jni()) << "error during NewObject"; |
+ remote_tracks_[track] = NewGlobalRef(jni(), j_track); |
+ jfieldID video_tracks_id = GetFieldID( |
+ jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/LinkedList;"); |
+ jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); |
+ jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), video_tracks), "add", |
+ "(Ljava/lang/Object;)Z"); |
+ jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track); |
+ CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
+ RTC_CHECK(added); |
+ |
+ std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> streams; |
+ streams.push_back(rtc::scoped_refptr<webrtc::MediaStreamInterface>(stream)); |
+ jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onAddTrack", |
+ "(Lorg/webrtc/MediaStreamTrack;[Lorg/webrtc/MediaStream;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_track, j_stream_array); |
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnAudioTrackRemoved( |
+ webrtc::AudioTrackInterface* track, |
+ webrtc::MediaStreamInterface* stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jobject j_stream = GetOrCreateJavaStream(stream); |
+ NativeToJavaMediaTrackMap::iterator track_it = remote_tracks_.find(track); |
+ RTC_CHECK(track_it != remote_tracks_.end()); |
+ jobject j_track = track_it->second; |
+ |
+ jfieldID audio_tracks_id = GetFieldID( |
+ jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/LinkedList;"); |
+ jobject video_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); |
+ jmethodID remove = GetMethodID(jni(), GetObjectClass(jni(), video_tracks), |
+ "remove", "(Ljava/lang/Object;)Z"); |
+ jboolean removed = jni()->CallBooleanMethod(video_tracks, remove, j_track); |
+ CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
+ RTC_CHECK(removed); |
+ |
+ std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> streams; |
+ streams.push_back(rtc::scoped_refptr<webrtc::MediaStreamInterface>(stream)); |
+ jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onRemoveTrack", |
+ "(Lorg/webrtc/MediaStreamTrack;[Lorg/webrtc/MediaStream;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_track, j_stream_array); |
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+ |
+ DisposeRemoteTrack(track_it); |
+} |
+ |
+void PeerConnectionObserverJni::OnVideoTrackRemoved( |
+ webrtc::VideoTrackInterface* track, |
+ webrtc::MediaStreamInterface* stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jobject j_stream = GetOrCreateJavaStream(stream); |
+ NativeToJavaMediaTrackMap::iterator track_it = remote_tracks_.find(track); |
+ RTC_CHECK(track_it != remote_tracks_.end()); |
+ jobject j_track = track_it->second; |
+ |
+ jfieldID video_tracks_id = GetFieldID( |
+ jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/LinkedList;"); |
+ jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); |
+ jmethodID remove = GetMethodID(jni(), GetObjectClass(jni(), video_tracks), |
+ "remove", "(Ljava/lang/Object;)Z"); |
+ jboolean removed = jni()->CallBooleanMethod(video_tracks, remove, j_track); |
+ CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
+ RTC_CHECK(removed); |
+ |
+ std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> streams; |
+ streams.push_back(rtc::scoped_refptr<webrtc::MediaStreamInterface>(stream)); |
+ jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onRemoveTrack", |
+ "(Lorg/webrtc/MediaStreamTrack;[Lorg/webrtc/MediaStream;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_track, j_stream_array); |
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+ |
+ DisposeRemoteTrack(track_it); |
} |
void PeerConnectionObserverJni::OnRemoveStream( |
@@ -186,6 +296,16 @@ void PeerConnectionObserverJni::OnRemoveStream( |
"(Lorg/webrtc/MediaStream;)V"); |
jni()->CallVoidMethod(*j_observer_global_, m, j_stream); |
CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+ |
+ stream_observers_.erase( |
+ std::remove_if( |
+ stream_observers_.begin(), stream_observers_.end(), |
+ [stream]( |
+ const std::unique_ptr<webrtc::MediaStreamObserver>& observer) { |
+ return observer->stream() == stream; |
+ }), |
+ stream_observers_.end()); |
+ |
// Release the refptr reference so that DisposeRemoteStream can assert |
// it removes the final reference. |
stream = nullptr; |
@@ -226,20 +346,9 @@ void PeerConnectionObserverJni::OnAddTrack( |
rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, |
const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& |
streams) { |
- ScopedLocalRefFrame local_ref_frame(jni()); |
- jobject j_rtp_receiver = |
- jni()->NewObject(*j_rtp_receiver_class_, j_rtp_receiver_ctor_, |
- jlongFromPointer(receiver.get())); |
- CHECK_EXCEPTION(jni()) << "error during NewObject"; |
- receiver->AddRef(); |
- rtp_receivers_[receiver] = NewGlobalRef(jni(), j_rtp_receiver); |
- |
- jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
- jmethodID m = |
- GetMethodID(jni(), *j_observer_class_, "onAddTrack", |
- "(Lorg/webrtc/RtpReceiver;[Lorg/webrtc/MediaStream;)V"); |
- jni()->CallVoidMethod(*j_observer_global_, m, j_rtp_receiver, j_stream_array); |
- CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+ // PCO::onAddTrack is broken and called only one time when the MediaStream |
+ // is added to PC. Android sdk observes MediaStream's tracks modification |
+ // with MediaStreamObserver - see PeerConnectionObserverJni::OnAddStream |
Taylor Brandstetter
2017/08/29 19:48:09
Can you explain the issue more? Can this be fixed,
korniltsev
2017/08/30 21:47:47
It was not actually broken, I was wrong when I wro
|
} |
void PeerConnectionObserverJni::SetConstraints( |
@@ -258,15 +367,21 @@ void PeerConnectionObserverJni::DisposeRemoteStream( |
DeleteGlobalRef(jni(), j_stream); |
} |
-void PeerConnectionObserverJni::DisposeRtpReceiver( |
- const NativeToJavaRtpReceiverMap::iterator& it) { |
- jobject j_rtp_receiver = it->second; |
- rtp_receivers_.erase(it); |
- jni()->CallVoidMethod( |
- j_rtp_receiver, |
- GetMethodID(jni(), *j_rtp_receiver_class_, "dispose", "()V")); |
- CHECK_EXCEPTION(jni()) << "error during RtpReceiver.dispose()"; |
- DeleteGlobalRef(jni(), j_rtp_receiver); |
+void PeerConnectionObserverJni::DisposeRemoteTrack( |
+ const NativeToJavaMediaTrackMap::iterator& it) { |
+ RTC_CHECK(it != remote_tracks_.end()); |
+ webrtc::MediaStreamTrackInterface* track = it->first; |
+ jobject j_track = it->second; |
+ remote_tracks_.erase(it); |
+ jmethodID dispose; |
+ if (track->kind() == webrtc::MediaStreamTrackInterface::kVideoKind) { |
+ dispose = GetMethodID(jni(), *j_video_track_class_, "dispose", "()V"); |
+ } else { |
+ dispose = GetMethodID(jni(), *j_audio_track_class_, "dispose", "()V"); |
+ } |
+ jni()->CallVoidMethod(j_track, dispose); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+ DeleteGlobalRef(jni(), j_track); |
} |
// If the NativeToJavaStreamsMap contains the stream, return it. |
@@ -277,7 +392,6 @@ jobject PeerConnectionObserverJni::GetOrCreateJavaStream( |
if (it != remote_streams_.end()) { |
return it->second; |
} |
- |
// Java MediaStream holds one reference. Corresponding Release() is in |
// MediaStream_free, triggered by MediaStream.dispose(). |
stream->AddRef(); |