OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2013 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 // Lifecycle notes: objects are owned where they will be called; in other words | |
12 // FooObservers are owned by C++-land, and user-callable objects (e.g. | |
13 // PeerConnection and VideoTrack) are owned by Java-land. | |
14 // When this file (or other files in this directory) allocates C++ | |
15 // RefCountInterfaces it AddRef()s an artificial ref simulating the jlong held | |
16 // in Java-land, and then Release()s the ref in the respective free call. | |
17 // Sometimes this AddRef is implicit in the construction of a scoped_refptr<> | |
18 // which is then .release()d. Any persistent (non-local) references from C++ to | |
19 // Java must be global or weak (in which case they must be checked before use)! | |
20 // | |
21 // Exception notes: pretty much all JNI calls can throw Java exceptions, so each | |
22 // call through a JNIEnv* pointer needs to be followed by an ExceptionCheck() | |
23 // call. In this file this is done in CHECK_EXCEPTION, making for much easier | |
24 // debugging in case of failure (the alternative is to wait for control to | |
25 // return to the Java frame that called code in this file, at which point it's | |
26 // impossible to tell which JNI call broke). | |
27 | |
28 #include <limits> | |
29 #include <memory> | |
30 #include <utility> | |
31 | |
32 #include "webrtc/api/mediaconstraintsinterface.h" | |
33 #include "webrtc/api/peerconnectioninterface.h" | |
34 #include "webrtc/api/rtpreceiverinterface.h" | |
35 #include "webrtc/api/rtpsenderinterface.h" | |
36 #include "webrtc/rtc_base/checks.h" | |
37 #include "webrtc/rtc_base/logging.h" | |
38 #include "webrtc/sdk/android/src/jni/classreferenceholder.h" | |
39 #include "webrtc/sdk/android/src/jni/jni_helpers.h" | |
40 #include "webrtc/sdk/android/src/jni/pc/java_native_conversion.h" | |
41 #include "webrtc/sdk/android/src/jni/pc/mediaconstraints_jni.h" | |
42 #include "webrtc/sdk/android/src/jni/pc/peerconnectionobserver_jni.h" | |
43 #include "webrtc/sdk/android/src/jni/pc/rtcstatscollectorcallbackwrapper.h" | |
44 #include "webrtc/sdk/android/src/jni/pc/sdpobserver_jni.h" | |
45 #include "webrtc/sdk/android/src/jni/pc/statsobserver_jni.h" | |
46 #include "webrtc/system_wrappers/include/trace.h" | |
47 | |
48 namespace webrtc_jni { | |
49 | |
50 static rtc::scoped_refptr<webrtc::PeerConnectionInterface> ExtractNativePC( | |
51 JNIEnv* jni, | |
52 jobject j_pc) { | |
53 jfieldID native_pc_id = | |
54 GetFieldID(jni, GetObjectClass(jni, j_pc), "nativePeerConnection", "J"); | |
55 jlong j_p = GetLongField(jni, j_pc, native_pc_id); | |
56 return rtc::scoped_refptr<webrtc::PeerConnectionInterface>( | |
57 reinterpret_cast<webrtc::PeerConnectionInterface*>(j_p)); | |
58 } | |
59 | |
60 JOW(void, PeerConnection_freePeerConnection)(JNIEnv*, jclass, jlong j_p) { | |
61 CHECK_RELEASE(reinterpret_cast<webrtc::PeerConnectionInterface*>(j_p)); | |
62 } | |
63 | |
64 JOW(void, PeerConnection_freeObserver)(JNIEnv*, jclass, jlong j_p) { | |
65 PeerConnectionObserverJni* p = | |
66 reinterpret_cast<PeerConnectionObserverJni*>(j_p); | |
67 delete p; | |
68 } | |
69 | |
70 JOW(jobject, PeerConnection_getLocalDescription)(JNIEnv* jni, jobject j_pc) { | |
71 const webrtc::SessionDescriptionInterface* sdp = | |
72 ExtractNativePC(jni, j_pc)->local_description(); | |
73 return sdp ? NativeToJavaSessionDescription(jni, sdp) : NULL; | |
74 } | |
75 | |
76 JOW(jobject, PeerConnection_getRemoteDescription)(JNIEnv* jni, jobject j_pc) { | |
77 const webrtc::SessionDescriptionInterface* sdp = | |
78 ExtractNativePC(jni, j_pc)->remote_description(); | |
79 return sdp ? NativeToJavaSessionDescription(jni, sdp) : NULL; | |
80 } | |
81 | |
82 JOW(jobject, PeerConnection_createDataChannel) | |
83 (JNIEnv* jni, jobject j_pc, jstring j_label, jobject j_init) { | |
84 webrtc::DataChannelInit init = JavaToNativeDataChannelInit(jni, j_init); | |
85 rtc::scoped_refptr<webrtc::DataChannelInterface> channel( | |
86 ExtractNativePC(jni, j_pc)->CreateDataChannel( | |
87 JavaToStdString(jni, j_label), &init)); | |
88 // Mustn't pass channel.get() directly through NewObject to avoid reading its | |
89 // vararg parameter as 64-bit and reading memory that doesn't belong to the | |
90 // 32-bit parameter. | |
91 jlong nativeChannelPtr = jlongFromPointer(channel.get()); | |
92 if (!nativeChannelPtr) { | |
93 LOG(LS_ERROR) << "Failed to create DataChannel"; | |
94 return nullptr; | |
95 } | |
96 jclass j_data_channel_class = FindClass(jni, "org/webrtc/DataChannel"); | |
97 jmethodID j_data_channel_ctor = | |
98 GetMethodID(jni, j_data_channel_class, "<init>", "(J)V"); | |
99 jobject j_channel = jni->NewObject(j_data_channel_class, j_data_channel_ctor, | |
100 nativeChannelPtr); | |
101 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
102 // Channel is now owned by Java object, and will be freed from there. | |
103 int bumped_count = channel->AddRef(); | |
104 RTC_CHECK(bumped_count == 2) << "Unexpected refcount"; | |
105 return j_channel; | |
106 } | |
107 | |
108 JOW(void, PeerConnection_createOffer) | |
109 (JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) { | |
110 MediaConstraintsJni* constraints = | |
111 new MediaConstraintsJni(jni, j_constraints); | |
112 rtc::scoped_refptr<CreateSdpObserverJni> observer( | |
113 new rtc::RefCountedObject<CreateSdpObserverJni>(jni, j_observer, | |
114 constraints)); | |
115 ExtractNativePC(jni, j_pc)->CreateOffer(observer, constraints); | |
116 } | |
117 | |
118 JOW(void, PeerConnection_createAnswer) | |
119 (JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_constraints) { | |
120 MediaConstraintsJni* constraints = | |
121 new MediaConstraintsJni(jni, j_constraints); | |
122 rtc::scoped_refptr<CreateSdpObserverJni> observer( | |
123 new rtc::RefCountedObject<CreateSdpObserverJni>(jni, j_observer, | |
124 constraints)); | |
125 ExtractNativePC(jni, j_pc)->CreateAnswer(observer, constraints); | |
126 } | |
127 | |
128 JOW(void, PeerConnection_setLocalDescription) | |
129 (JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_sdp) { | |
130 rtc::scoped_refptr<SetSdpObserverJni> observer( | |
131 new rtc::RefCountedObject<SetSdpObserverJni>(jni, j_observer, nullptr)); | |
132 ExtractNativePC(jni, j_pc)->SetLocalDescription( | |
133 observer, JavaToNativeSessionDescription(jni, j_sdp)); | |
134 } | |
135 | |
136 JOW(void, PeerConnection_setRemoteDescription) | |
137 (JNIEnv* jni, jobject j_pc, jobject j_observer, jobject j_sdp) { | |
138 rtc::scoped_refptr<SetSdpObserverJni> observer( | |
139 new rtc::RefCountedObject<SetSdpObserverJni>(jni, j_observer, nullptr)); | |
140 ExtractNativePC(jni, j_pc)->SetRemoteDescription( | |
141 observer, JavaToNativeSessionDescription(jni, j_sdp)); | |
142 } | |
143 | |
144 JOW(jboolean, PeerConnection_nativeSetConfiguration) | |
145 (JNIEnv* jni, jobject j_pc, jobject j_rtc_config, jlong native_observer) { | |
146 // Need to merge constraints into RTCConfiguration again, which are stored | |
147 // in the observer object. | |
148 PeerConnectionObserverJni* observer = | |
149 reinterpret_cast<PeerConnectionObserverJni*>(native_observer); | |
150 webrtc::PeerConnectionInterface::RTCConfiguration rtc_config( | |
151 webrtc::PeerConnectionInterface::RTCConfigurationType::kAggressive); | |
152 JavaToNativeRTCConfiguration(jni, j_rtc_config, &rtc_config); | |
153 CopyConstraintsIntoRtcConfiguration(observer->constraints(), &rtc_config); | |
154 return ExtractNativePC(jni, j_pc)->SetConfiguration(rtc_config); | |
155 } | |
156 | |
157 JOW(jboolean, PeerConnection_nativeAddIceCandidate) | |
158 (JNIEnv* jni, | |
159 jobject j_pc, | |
160 jstring j_sdp_mid, | |
161 jint j_sdp_mline_index, | |
162 jstring j_candidate_sdp) { | |
163 std::string sdp_mid = JavaToStdString(jni, j_sdp_mid); | |
164 std::string sdp = JavaToStdString(jni, j_candidate_sdp); | |
165 std::unique_ptr<webrtc::IceCandidateInterface> candidate( | |
166 webrtc::CreateIceCandidate(sdp_mid, j_sdp_mline_index, sdp, nullptr)); | |
167 return ExtractNativePC(jni, j_pc)->AddIceCandidate(candidate.get()); | |
168 } | |
169 | |
170 JOW(jboolean, PeerConnection_nativeRemoveIceCandidates) | |
171 (JNIEnv* jni, jobject j_pc, jobjectArray j_candidates) { | |
172 std::vector<cricket::Candidate> candidates; | |
173 size_t num_candidates = jni->GetArrayLength(j_candidates); | |
174 for (size_t i = 0; i < num_candidates; ++i) { | |
175 jobject j_candidate = jni->GetObjectArrayElement(j_candidates, i); | |
176 candidates.push_back(JavaToNativeCandidate(jni, j_candidate)); | |
177 } | |
178 return ExtractNativePC(jni, j_pc)->RemoveIceCandidates(candidates); | |
179 } | |
180 | |
181 JOW(jboolean, PeerConnection_nativeAddLocalStream) | |
182 (JNIEnv* jni, jobject j_pc, jlong native_stream) { | |
183 return ExtractNativePC(jni, j_pc)->AddStream( | |
184 reinterpret_cast<webrtc::MediaStreamInterface*>(native_stream)); | |
185 } | |
186 | |
187 JOW(void, PeerConnection_nativeRemoveLocalStream) | |
188 (JNIEnv* jni, jobject j_pc, jlong native_stream) { | |
189 ExtractNativePC(jni, j_pc)->RemoveStream( | |
190 reinterpret_cast<webrtc::MediaStreamInterface*>(native_stream)); | |
191 } | |
192 | |
193 JOW(jobject, PeerConnection_nativeCreateSender) | |
194 (JNIEnv* jni, jobject j_pc, jstring j_kind, jstring j_stream_id) { | |
195 jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender"); | |
196 jmethodID j_rtp_sender_ctor = | |
197 GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V"); | |
198 | |
199 std::string kind = JavaToStdString(jni, j_kind); | |
200 std::string stream_id = JavaToStdString(jni, j_stream_id); | |
201 rtc::scoped_refptr<webrtc::RtpSenderInterface> sender = | |
202 ExtractNativePC(jni, j_pc)->CreateSender(kind, stream_id); | |
203 if (!sender.get()) { | |
204 return nullptr; | |
205 } | |
206 jlong nativeSenderPtr = jlongFromPointer(sender.get()); | |
207 jobject j_sender = | |
208 jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); | |
209 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
210 // Sender is now owned by the Java object, and will be freed from | |
211 // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). | |
212 sender->AddRef(); | |
213 return j_sender; | |
214 } | |
215 | |
216 JOW(jobject, PeerConnection_nativeGetSenders)(JNIEnv* jni, jobject j_pc) { | |
217 jclass j_array_list_class = FindClass(jni, "java/util/ArrayList"); | |
218 jmethodID j_array_list_ctor = | |
219 GetMethodID(jni, j_array_list_class, "<init>", "()V"); | |
220 jmethodID j_array_list_add = | |
221 GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z"); | |
222 jobject j_senders = jni->NewObject(j_array_list_class, j_array_list_ctor); | |
223 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
224 | |
225 jclass j_rtp_sender_class = FindClass(jni, "org/webrtc/RtpSender"); | |
226 jmethodID j_rtp_sender_ctor = | |
227 GetMethodID(jni, j_rtp_sender_class, "<init>", "(J)V"); | |
228 | |
229 auto senders = ExtractNativePC(jni, j_pc)->GetSenders(); | |
230 for (const auto& sender : senders) { | |
231 jlong nativeSenderPtr = jlongFromPointer(sender.get()); | |
232 jobject j_sender = | |
233 jni->NewObject(j_rtp_sender_class, j_rtp_sender_ctor, nativeSenderPtr); | |
234 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
235 // Sender is now owned by the Java object, and will be freed from | |
236 // RtpSender.dispose(), called by PeerConnection.dispose() or getSenders(). | |
237 sender->AddRef(); | |
238 jni->CallBooleanMethod(j_senders, j_array_list_add, j_sender); | |
239 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; | |
240 } | |
241 return j_senders; | |
242 } | |
243 | |
244 JOW(jobject, PeerConnection_nativeGetReceivers)(JNIEnv* jni, jobject j_pc) { | |
245 jclass j_array_list_class = FindClass(jni, "java/util/ArrayList"); | |
246 jmethodID j_array_list_ctor = | |
247 GetMethodID(jni, j_array_list_class, "<init>", "()V"); | |
248 jmethodID j_array_list_add = | |
249 GetMethodID(jni, j_array_list_class, "add", "(Ljava/lang/Object;)Z"); | |
250 jobject j_receivers = jni->NewObject(j_array_list_class, j_array_list_ctor); | |
251 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
252 | |
253 jclass j_rtp_receiver_class = FindClass(jni, "org/webrtc/RtpReceiver"); | |
254 jmethodID j_rtp_receiver_ctor = | |
255 GetMethodID(jni, j_rtp_receiver_class, "<init>", "(J)V"); | |
256 | |
257 auto receivers = ExtractNativePC(jni, j_pc)->GetReceivers(); | |
258 for (const auto& receiver : receivers) { | |
259 jlong nativeReceiverPtr = jlongFromPointer(receiver.get()); | |
260 jobject j_receiver = jni->NewObject(j_rtp_receiver_class, | |
261 j_rtp_receiver_ctor, nativeReceiverPtr); | |
262 CHECK_EXCEPTION(jni) << "error during NewObject"; | |
263 // Receiver is now owned by Java object, and will be freed from there. | |
264 receiver->AddRef(); | |
265 jni->CallBooleanMethod(j_receivers, j_array_list_add, j_receiver); | |
266 CHECK_EXCEPTION(jni) << "error during CallBooleanMethod"; | |
267 } | |
268 return j_receivers; | |
269 } | |
270 | |
271 JOW(bool, PeerConnection_nativeOldGetStats) | |
272 (JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) { | |
273 rtc::scoped_refptr<StatsObserverJni> observer( | |
274 new rtc::RefCountedObject<StatsObserverJni>(jni, j_observer)); | |
275 return ExtractNativePC(jni, j_pc)->GetStats( | |
276 observer, | |
277 reinterpret_cast<webrtc::MediaStreamTrackInterface*>(native_track), | |
278 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); | |
279 } | |
280 | |
281 JOW(void, PeerConnection_nativeNewGetStats) | |
282 (JNIEnv* jni, jobject j_pc, jobject j_callback) { | |
283 rtc::scoped_refptr<RTCStatsCollectorCallbackWrapper> callback( | |
284 new rtc::RefCountedObject<RTCStatsCollectorCallbackWrapper>(jni, | |
285 j_callback)); | |
286 ExtractNativePC(jni, j_pc)->GetStats(callback); | |
287 } | |
288 | |
289 JOW(bool, PeerConnection_nativeStartRtcEventLog) | |
290 (JNIEnv* jni, jobject j_pc, int file_descriptor, int max_size_bytes) { | |
291 return ExtractNativePC(jni, j_pc)->StartRtcEventLog(file_descriptor, | |
292 max_size_bytes); | |
293 } | |
294 | |
295 JOW(void, PeerConnection_nativeStopRtcEventLog)(JNIEnv* jni, jobject j_pc) { | |
296 ExtractNativePC(jni, j_pc)->StopRtcEventLog(); | |
297 } | |
298 | |
299 JOW(jobject, PeerConnection_signalingState)(JNIEnv* jni, jobject j_pc) { | |
300 webrtc::PeerConnectionInterface::SignalingState state = | |
301 ExtractNativePC(jni, j_pc)->signaling_state(); | |
302 return JavaEnumFromIndexAndClassName(jni, "PeerConnection$SignalingState", | |
303 state); | |
304 } | |
305 | |
306 JOW(jobject, PeerConnection_iceConnectionState)(JNIEnv* jni, jobject j_pc) { | |
307 webrtc::PeerConnectionInterface::IceConnectionState state = | |
308 ExtractNativePC(jni, j_pc)->ice_connection_state(); | |
309 return JavaEnumFromIndexAndClassName(jni, "PeerConnection$IceConnectionState", | |
310 state); | |
311 } | |
312 | |
313 JOW(jobject, PeerConnection_iceGatheringState)(JNIEnv* jni, jobject j_pc) { | |
314 webrtc::PeerConnectionInterface::IceGatheringState state = | |
315 ExtractNativePC(jni, j_pc)->ice_gathering_state(); | |
316 return JavaEnumFromIndexAndClassName(jni, "PeerConnection$IceGatheringState", | |
317 state); | |
318 } | |
319 | |
320 JOW(void, PeerConnection_close)(JNIEnv* jni, jobject j_pc) { | |
321 ExtractNativePC(jni, j_pc)->Close(); | |
322 return; | |
323 } | |
324 | |
325 } // namespace webrtc_jni | |
OLD | NEW |