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 |
new file mode 100644 |
index 0000000000000000000000000000000000000000..18767925933ffb6006845d83b1fd2d3edb0954f5 |
--- /dev/null |
+++ b/webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.cc |
@@ -0,0 +1,307 @@ |
+/* |
+ * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.h" |
+ |
+#include <string> |
+ |
+#include "webrtc/sdk/android/src/jni/classreferenceholder.h" |
+#include "webrtc/sdk/android/src/jni/pc/java_native_conversion.h" |
+ |
+namespace webrtc_jni { |
+ |
+// Convenience, used since callbacks occur on the signaling thread, which may |
+// be a non-Java thread. |
+static JNIEnv* jni() { |
+ return AttachCurrentThreadIfNeeded(); |
+} |
+ |
+PeerConnectionObserverJni::PeerConnectionObserverJni(JNIEnv* jni, |
+ jobject j_observer) |
+ : j_observer_global_(jni, j_observer), |
+ j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)), |
+ j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")), |
+ j_media_stream_ctor_( |
+ GetMethodID(jni, *j_media_stream_class_, "<init>", "(J)V")), |
+ j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")), |
+ j_audio_track_ctor_( |
+ GetMethodID(jni, *j_audio_track_class_, "<init>", "(J)V")), |
+ j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")), |
+ j_video_track_ctor_( |
+ 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")) {} |
+ |
+PeerConnectionObserverJni::~PeerConnectionObserverJni() { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ while (!remote_streams_.empty()) |
+ DisposeRemoteStream(remote_streams_.begin()); |
+ while (!rtp_receivers_.empty()) |
+ DisposeRtpReceiver(rtp_receivers_.begin()); |
+} |
+ |
+void PeerConnectionObserverJni::OnIceCandidate( |
+ const webrtc::IceCandidateInterface* candidate) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ std::string sdp; |
+ RTC_CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp; |
+ jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate"); |
+ jmethodID ctor = |
+ GetMethodID(jni(), candidate_class, "<init>", |
+ "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"); |
+ jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid()); |
+ jstring j_sdp = JavaStringFromStdString(jni(), sdp); |
+ jstring j_url = JavaStringFromStdString(jni(), candidate->candidate().url()); |
+ jobject j_candidate = jni()->NewObject( |
+ candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp, j_url); |
+ CHECK_EXCEPTION(jni()) << "error during NewObject"; |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidate", |
+ "(Lorg/webrtc/IceCandidate;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_candidate); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnIceCandidatesRemoved( |
+ const std::vector<cricket::Candidate>& candidates) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jobjectArray candidates_array = NativeToJavaCandidateArray(jni(), candidates); |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidatesRemoved", |
+ "([Lorg/webrtc/IceCandidate;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, candidates_array); |
+ CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnSignalingChange( |
+ webrtc::PeerConnectionInterface::SignalingState new_state) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSignalingChange", |
+ "(Lorg/webrtc/PeerConnection$SignalingState;)V"); |
+ jobject new_state_enum = JavaEnumFromIndexAndClassName( |
+ jni(), "PeerConnection$SignalingState", new_state); |
+ jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnIceConnectionChange( |
+ webrtc::PeerConnectionInterface::IceConnectionState new_state) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onIceConnectionChange", |
+ "(Lorg/webrtc/PeerConnection$IceConnectionState;)V"); |
+ jobject new_state_enum = JavaEnumFromIndexAndClassName( |
+ jni(), "PeerConnection$IceConnectionState", new_state); |
+ jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, |
+ "onIceConnectionReceivingChange", "(Z)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, receiving); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnIceGatheringChange( |
+ webrtc::PeerConnectionInterface::IceGatheringState new_state) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceGatheringChange", |
+ "(Lorg/webrtc/PeerConnection$IceGatheringState;)V"); |
+ jobject new_state_enum = JavaEnumFromIndexAndClassName( |
+ jni(), "PeerConnection$IceGatheringState", new_state); |
+ jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnAddStream( |
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ // The stream could be added into the remote_streams_ map when calling |
+ // OnAddTrack. |
+ 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); |
+ } |
+ |
+ 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); |
+ } |
+ |
+ 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"; |
+} |
+ |
+void PeerConnectionObserverJni::OnRemoveStream( |
+ rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream); |
+ RTC_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, j_stream); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+ // Release the refptr reference so that DisposeRemoteStream can assert |
+ // it removes the final reference. |
+ stream = nullptr; |
+ DisposeRemoteStream(it); |
+} |
+ |
+void PeerConnectionObserverJni::OnDataChannel( |
+ rtc::scoped_refptr<webrtc::DataChannelInterface> channel) { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jobject j_channel = |
+ jni()->NewObject(*j_data_channel_class_, j_data_channel_ctor_, |
+ jlongFromPointer(channel.get())); |
+ CHECK_EXCEPTION(jni()) << "error during NewObject"; |
+ |
+ jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", |
+ "(Lorg/webrtc/DataChannel;)V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m, j_channel); |
+ |
+ // Channel is now owned by Java object, and will be freed from |
+ // DataChannel.dispose(). Important that this be done _after_ the |
+ // CallVoidMethod above as Java code might call back into native code and be |
+ // surprised to see a refcount of 2. |
+ int bumped_count = channel->AddRef(); |
+ RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel"; |
+ |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+void PeerConnectionObserverJni::OnRenegotiationNeeded() { |
+ ScopedLocalRefFrame local_ref_frame(jni()); |
+ jmethodID m = |
+ GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V"); |
+ jni()->CallVoidMethod(*j_observer_global_, m); |
+ CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
+} |
+ |
+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"; |
+} |
+ |
+void PeerConnectionObserverJni::SetConstraints( |
+ MediaConstraintsJni* constraints) { |
+ RTC_CHECK(!constraints_.get()) << "constraints already set!"; |
+ constraints_.reset(constraints); |
+} |
+ |
+void PeerConnectionObserverJni::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); |
+} |
+ |
+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); |
+} |
+ |
+// If the NativeToJavaStreamsMap contains the stream, return it. |
+// Otherwise, create a new Java MediaStream. |
+jobject PeerConnectionObserverJni::GetOrCreateJavaStream( |
+ const rtc::scoped_refptr<webrtc::MediaStreamInterface>& stream) { |
+ NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream); |
+ 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(); |
+ jobject j_stream = |
+ jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_, |
+ reinterpret_cast<jlong>(stream.get())); |
+ CHECK_EXCEPTION(jni()) << "error during NewObject"; |
+ |
+ remote_streams_[stream] = NewGlobalRef(jni(), j_stream); |
+ return j_stream; |
+} |
+ |
+jobjectArray PeerConnectionObserverJni::NativeToJavaMediaStreamArray( |
+ JNIEnv* jni, |
+ const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& |
+ streams) { |
+ jobjectArray java_streams = |
+ jni->NewObjectArray(streams.size(), *j_media_stream_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < streams.size(); ++i) { |
+ jobject j_stream = GetOrCreateJavaStream(streams[i]); |
+ jni->SetObjectArrayElement(java_streams, i, j_stream); |
+ } |
+ return java_streams; |
+} |
+ |
+} // namespace webrtc_jni |