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 |