OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2017 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include "webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.h" |
| 12 |
| 13 #include <string> |
| 14 |
| 15 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" |
| 16 #include "webrtc/sdk/android/src/jni/pc/java_native_conversion.h" |
| 17 |
| 18 namespace webrtc_jni { |
| 19 |
| 20 // Convenience, used since callbacks occur on the signaling thread, which may |
| 21 // be a non-Java thread. |
| 22 static JNIEnv* jni() { |
| 23 return AttachCurrentThreadIfNeeded(); |
| 24 } |
| 25 |
| 26 PeerConnectionObserverJni::PeerConnectionObserverJni(JNIEnv* jni, |
| 27 jobject j_observer) |
| 28 : j_observer_global_(jni, j_observer), |
| 29 j_observer_class_(jni, GetObjectClass(jni, *j_observer_global_)), |
| 30 j_media_stream_class_(jni, FindClass(jni, "org/webrtc/MediaStream")), |
| 31 j_media_stream_ctor_( |
| 32 GetMethodID(jni, *j_media_stream_class_, "<init>", "(J)V")), |
| 33 j_audio_track_class_(jni, FindClass(jni, "org/webrtc/AudioTrack")), |
| 34 j_audio_track_ctor_( |
| 35 GetMethodID(jni, *j_audio_track_class_, "<init>", "(J)V")), |
| 36 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")), |
| 37 j_video_track_ctor_( |
| 38 GetMethodID(jni, *j_video_track_class_, "<init>", "(J)V")), |
| 39 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")), |
| 40 j_data_channel_ctor_( |
| 41 GetMethodID(jni, *j_data_channel_class_, "<init>", "(J)V")), |
| 42 j_rtp_receiver_class_(jni, FindClass(jni, "org/webrtc/RtpReceiver")), |
| 43 j_rtp_receiver_ctor_( |
| 44 GetMethodID(jni, *j_rtp_receiver_class_, "<init>", "(J)V")) {} |
| 45 |
| 46 PeerConnectionObserverJni::~PeerConnectionObserverJni() { |
| 47 ScopedLocalRefFrame local_ref_frame(jni()); |
| 48 while (!remote_streams_.empty()) |
| 49 DisposeRemoteStream(remote_streams_.begin()); |
| 50 while (!rtp_receivers_.empty()) |
| 51 DisposeRtpReceiver(rtp_receivers_.begin()); |
| 52 } |
| 53 |
| 54 void PeerConnectionObserverJni::OnIceCandidate( |
| 55 const webrtc::IceCandidateInterface* candidate) { |
| 56 ScopedLocalRefFrame local_ref_frame(jni()); |
| 57 std::string sdp; |
| 58 RTC_CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp; |
| 59 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate"); |
| 60 jmethodID ctor = |
| 61 GetMethodID(jni(), candidate_class, "<init>", |
| 62 "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V"); |
| 63 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid()); |
| 64 jstring j_sdp = JavaStringFromStdString(jni(), sdp); |
| 65 jstring j_url = JavaStringFromStdString(jni(), candidate->candidate().url()); |
| 66 jobject j_candidate = jni()->NewObject( |
| 67 candidate_class, ctor, j_mid, candidate->sdp_mline_index(), j_sdp, j_url); |
| 68 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 69 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidate", |
| 70 "(Lorg/webrtc/IceCandidate;)V"); |
| 71 jni()->CallVoidMethod(*j_observer_global_, m, j_candidate); |
| 72 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 73 } |
| 74 |
| 75 void PeerConnectionObserverJni::OnIceCandidatesRemoved( |
| 76 const std::vector<cricket::Candidate>& candidates) { |
| 77 ScopedLocalRefFrame local_ref_frame(jni()); |
| 78 jobjectArray candidates_array = NativeToJavaCandidateArray(jni(), candidates); |
| 79 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceCandidatesRemoved", |
| 80 "([Lorg/webrtc/IceCandidate;)V"); |
| 81 jni()->CallVoidMethod(*j_observer_global_, m, candidates_array); |
| 82 CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
| 83 } |
| 84 |
| 85 void PeerConnectionObserverJni::OnSignalingChange( |
| 86 webrtc::PeerConnectionInterface::SignalingState new_state) { |
| 87 ScopedLocalRefFrame local_ref_frame(jni()); |
| 88 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onSignalingChange", |
| 89 "(Lorg/webrtc/PeerConnection$SignalingState;)V"); |
| 90 jobject new_state_enum = JavaEnumFromIndexAndClassName( |
| 91 jni(), "PeerConnection$SignalingState", new_state); |
| 92 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
| 93 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 94 } |
| 95 |
| 96 void PeerConnectionObserverJni::OnIceConnectionChange( |
| 97 webrtc::PeerConnectionInterface::IceConnectionState new_state) { |
| 98 ScopedLocalRefFrame local_ref_frame(jni()); |
| 99 jmethodID m = |
| 100 GetMethodID(jni(), *j_observer_class_, "onIceConnectionChange", |
| 101 "(Lorg/webrtc/PeerConnection$IceConnectionState;)V"); |
| 102 jobject new_state_enum = JavaEnumFromIndexAndClassName( |
| 103 jni(), "PeerConnection$IceConnectionState", new_state); |
| 104 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
| 105 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 106 } |
| 107 |
| 108 void PeerConnectionObserverJni::OnIceConnectionReceivingChange(bool receiving) { |
| 109 ScopedLocalRefFrame local_ref_frame(jni()); |
| 110 jmethodID m = GetMethodID(jni(), *j_observer_class_, |
| 111 "onIceConnectionReceivingChange", "(Z)V"); |
| 112 jni()->CallVoidMethod(*j_observer_global_, m, receiving); |
| 113 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 114 } |
| 115 |
| 116 void PeerConnectionObserverJni::OnIceGatheringChange( |
| 117 webrtc::PeerConnectionInterface::IceGatheringState new_state) { |
| 118 ScopedLocalRefFrame local_ref_frame(jni()); |
| 119 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onIceGatheringChange", |
| 120 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V"); |
| 121 jobject new_state_enum = JavaEnumFromIndexAndClassName( |
| 122 jni(), "PeerConnection$IceGatheringState", new_state); |
| 123 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); |
| 124 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 125 } |
| 126 |
| 127 void PeerConnectionObserverJni::OnAddStream( |
| 128 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
| 129 ScopedLocalRefFrame local_ref_frame(jni()); |
| 130 // The stream could be added into the remote_streams_ map when calling |
| 131 // OnAddTrack. |
| 132 jobject j_stream = GetOrCreateJavaStream(stream); |
| 133 |
| 134 for (const auto& track : stream->GetAudioTracks()) { |
| 135 jstring id = JavaStringFromStdString(jni(), track->id()); |
| 136 // Java AudioTrack holds one reference. Corresponding Release() is in |
| 137 // MediaStreamTrack_free, triggered by AudioTrack.dispose(). |
| 138 track->AddRef(); |
| 139 jobject j_track = |
| 140 jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_, |
| 141 reinterpret_cast<jlong>(track.get()), id); |
| 142 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 143 jfieldID audio_tracks_id = GetFieldID( |
| 144 jni(), *j_media_stream_class_, "audioTracks", "Ljava/util/LinkedList;"); |
| 145 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); |
| 146 jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), audio_tracks), |
| 147 "add", "(Ljava/lang/Object;)Z"); |
| 148 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track); |
| 149 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
| 150 RTC_CHECK(added); |
| 151 } |
| 152 |
| 153 for (const auto& track : stream->GetVideoTracks()) { |
| 154 jstring id = JavaStringFromStdString(jni(), track->id()); |
| 155 // Java VideoTrack holds one reference. Corresponding Release() is in |
| 156 // MediaStreamTrack_free, triggered by VideoTrack.dispose(). |
| 157 track->AddRef(); |
| 158 jobject j_track = |
| 159 jni()->NewObject(*j_video_track_class_, j_video_track_ctor_, |
| 160 reinterpret_cast<jlong>(track.get()), id); |
| 161 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 162 jfieldID video_tracks_id = GetFieldID( |
| 163 jni(), *j_media_stream_class_, "videoTracks", "Ljava/util/LinkedList;"); |
| 164 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); |
| 165 jmethodID add = GetMethodID(jni(), GetObjectClass(jni(), video_tracks), |
| 166 "add", "(Ljava/lang/Object;)Z"); |
| 167 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track); |
| 168 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; |
| 169 RTC_CHECK(added); |
| 170 } |
| 171 |
| 172 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", |
| 173 "(Lorg/webrtc/MediaStream;)V"); |
| 174 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); |
| 175 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 176 } |
| 177 |
| 178 void PeerConnectionObserverJni::OnRemoveStream( |
| 179 rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) { |
| 180 ScopedLocalRefFrame local_ref_frame(jni()); |
| 181 NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream); |
| 182 RTC_CHECK(it != remote_streams_.end()) |
| 183 << "unexpected stream: " << std::hex << stream; |
| 184 jobject j_stream = it->second; |
| 185 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream", |
| 186 "(Lorg/webrtc/MediaStream;)V"); |
| 187 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); |
| 188 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 189 // Release the refptr reference so that DisposeRemoteStream can assert |
| 190 // it removes the final reference. |
| 191 stream = nullptr; |
| 192 DisposeRemoteStream(it); |
| 193 } |
| 194 |
| 195 void PeerConnectionObserverJni::OnDataChannel( |
| 196 rtc::scoped_refptr<webrtc::DataChannelInterface> channel) { |
| 197 ScopedLocalRefFrame local_ref_frame(jni()); |
| 198 jobject j_channel = |
| 199 jni()->NewObject(*j_data_channel_class_, j_data_channel_ctor_, |
| 200 jlongFromPointer(channel.get())); |
| 201 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 202 |
| 203 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", |
| 204 "(Lorg/webrtc/DataChannel;)V"); |
| 205 jni()->CallVoidMethod(*j_observer_global_, m, j_channel); |
| 206 |
| 207 // Channel is now owned by Java object, and will be freed from |
| 208 // DataChannel.dispose(). Important that this be done _after_ the |
| 209 // CallVoidMethod above as Java code might call back into native code and be |
| 210 // surprised to see a refcount of 2. |
| 211 int bumped_count = channel->AddRef(); |
| 212 RTC_CHECK(bumped_count == 2) << "Unexpected refcount OnDataChannel"; |
| 213 |
| 214 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 215 } |
| 216 |
| 217 void PeerConnectionObserverJni::OnRenegotiationNeeded() { |
| 218 ScopedLocalRefFrame local_ref_frame(jni()); |
| 219 jmethodID m = |
| 220 GetMethodID(jni(), *j_observer_class_, "onRenegotiationNeeded", "()V"); |
| 221 jni()->CallVoidMethod(*j_observer_global_, m); |
| 222 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; |
| 223 } |
| 224 |
| 225 void PeerConnectionObserverJni::OnAddTrack( |
| 226 rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver, |
| 227 const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& |
| 228 streams) { |
| 229 ScopedLocalRefFrame local_ref_frame(jni()); |
| 230 jobject j_rtp_receiver = |
| 231 jni()->NewObject(*j_rtp_receiver_class_, j_rtp_receiver_ctor_, |
| 232 jlongFromPointer(receiver.get())); |
| 233 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 234 receiver->AddRef(); |
| 235 rtp_receivers_[receiver] = NewGlobalRef(jni(), j_rtp_receiver); |
| 236 |
| 237 jobjectArray j_stream_array = NativeToJavaMediaStreamArray(jni(), streams); |
| 238 jmethodID m = |
| 239 GetMethodID(jni(), *j_observer_class_, "onAddTrack", |
| 240 "(Lorg/webrtc/RtpReceiver;[Lorg/webrtc/MediaStream;)V"); |
| 241 jni()->CallVoidMethod(*j_observer_global_, m, j_rtp_receiver, j_stream_array); |
| 242 CHECK_EXCEPTION(jni()) << "Error during CallVoidMethod"; |
| 243 } |
| 244 |
| 245 void PeerConnectionObserverJni::SetConstraints( |
| 246 MediaConstraintsJni* constraints) { |
| 247 RTC_CHECK(!constraints_.get()) << "constraints already set!"; |
| 248 constraints_.reset(constraints); |
| 249 } |
| 250 |
| 251 void PeerConnectionObserverJni::DisposeRemoteStream( |
| 252 const NativeToJavaStreamsMap::iterator& it) { |
| 253 jobject j_stream = it->second; |
| 254 remote_streams_.erase(it); |
| 255 jni()->CallVoidMethod( |
| 256 j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V")); |
| 257 CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()"; |
| 258 DeleteGlobalRef(jni(), j_stream); |
| 259 } |
| 260 |
| 261 void PeerConnectionObserverJni::DisposeRtpReceiver( |
| 262 const NativeToJavaRtpReceiverMap::iterator& it) { |
| 263 jobject j_rtp_receiver = it->second; |
| 264 rtp_receivers_.erase(it); |
| 265 jni()->CallVoidMethod( |
| 266 j_rtp_receiver, |
| 267 GetMethodID(jni(), *j_rtp_receiver_class_, "dispose", "()V")); |
| 268 CHECK_EXCEPTION(jni()) << "error during RtpReceiver.dispose()"; |
| 269 DeleteGlobalRef(jni(), j_rtp_receiver); |
| 270 } |
| 271 |
| 272 // If the NativeToJavaStreamsMap contains the stream, return it. |
| 273 // Otherwise, create a new Java MediaStream. |
| 274 jobject PeerConnectionObserverJni::GetOrCreateJavaStream( |
| 275 const rtc::scoped_refptr<webrtc::MediaStreamInterface>& stream) { |
| 276 NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream); |
| 277 if (it != remote_streams_.end()) { |
| 278 return it->second; |
| 279 } |
| 280 |
| 281 // Java MediaStream holds one reference. Corresponding Release() is in |
| 282 // MediaStream_free, triggered by MediaStream.dispose(). |
| 283 stream->AddRef(); |
| 284 jobject j_stream = |
| 285 jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_, |
| 286 reinterpret_cast<jlong>(stream.get())); |
| 287 CHECK_EXCEPTION(jni()) << "error during NewObject"; |
| 288 |
| 289 remote_streams_[stream] = NewGlobalRef(jni(), j_stream); |
| 290 return j_stream; |
| 291 } |
| 292 |
| 293 jobjectArray PeerConnectionObserverJni::NativeToJavaMediaStreamArray( |
| 294 JNIEnv* jni, |
| 295 const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>& |
| 296 streams) { |
| 297 jobjectArray java_streams = |
| 298 jni->NewObjectArray(streams.size(), *j_media_stream_class_, nullptr); |
| 299 CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
| 300 for (size_t i = 0; i < streams.size(); ++i) { |
| 301 jobject j_stream = GetOrCreateJavaStream(streams[i]); |
| 302 jni->SetObjectArrayElement(java_streams, i, j_stream); |
| 303 } |
| 304 return java_streams; |
| 305 } |
| 306 |
| 307 } // namespace webrtc_jni |
OLD | NEW |