Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(244)

Side by Side Diff: talk/app/webrtc/java/jni/peerconnection_jni.cc

Issue 1308733004: Android: Fix memory leak for remote MediaStream (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: use helper NewGlobalRef function instead Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * libjingle 2 * libjingle
3 * Copyright 2013 Google Inc. 3 * Copyright 2013 Google Inc.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * 7 *
8 * 1. Redistributions of source code must retain the above copyright notice, 8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer. 9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * 2. Redistributions in binary form must reproduce the above copyright notice,
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 j_audio_track_ctor_(GetMethodID( 199 j_audio_track_ctor_(GetMethodID(
200 jni, *j_audio_track_class_, "<init>", "(J)V")), 200 jni, *j_audio_track_class_, "<init>", "(J)V")),
201 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")), 201 j_video_track_class_(jni, FindClass(jni, "org/webrtc/VideoTrack")),
202 j_video_track_ctor_(GetMethodID( 202 j_video_track_ctor_(GetMethodID(
203 jni, *j_video_track_class_, "<init>", "(J)V")), 203 jni, *j_video_track_class_, "<init>", "(J)V")),
204 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")), 204 j_data_channel_class_(jni, FindClass(jni, "org/webrtc/DataChannel")),
205 j_data_channel_ctor_(GetMethodID( 205 j_data_channel_ctor_(GetMethodID(
206 jni, *j_data_channel_class_, "<init>", "(J)V")) { 206 jni, *j_data_channel_class_, "<init>", "(J)V")) {
207 } 207 }
208 208
209 virtual ~PCOJava() {} 209 virtual ~PCOJava() {
210 ScopedLocalRefFrame local_ref_frame(jni());
211 while (!remote_streams_.empty())
212 DisposeRemoteStream(remote_streams_.begin());
213 }
210 214
211 void OnIceCandidate(const IceCandidateInterface* candidate) override { 215 void OnIceCandidate(const IceCandidateInterface* candidate) override {
212 ScopedLocalRefFrame local_ref_frame(jni()); 216 ScopedLocalRefFrame local_ref_frame(jni());
213 std::string sdp; 217 std::string sdp;
214 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp; 218 CHECK(candidate->ToString(&sdp)) << "got so far: " << sdp;
215 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate"); 219 jclass candidate_class = FindClass(jni(), "org/webrtc/IceCandidate");
216 jmethodID ctor = GetMethodID(jni(), candidate_class, 220 jmethodID ctor = GetMethodID(jni(), candidate_class,
217 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V"); 221 "<init>", "(Ljava/lang/String;ILjava/lang/String;)V");
218 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid()); 222 jstring j_mid = JavaStringFromStdString(jni(), candidate->sdp_mid());
219 jstring j_sdp = JavaStringFromStdString(jni(), sdp); 223 jstring j_sdp = JavaStringFromStdString(jni(), sdp);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 jni(), *j_observer_class_, "onIceGatheringChange", 269 jni(), *j_observer_class_, "onIceGatheringChange",
266 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V"); 270 "(Lorg/webrtc/PeerConnection$IceGatheringState;)V");
267 jobject new_state_enum = JavaEnumFromIndex( 271 jobject new_state_enum = JavaEnumFromIndex(
268 jni(), "PeerConnection$IceGatheringState", new_state); 272 jni(), "PeerConnection$IceGatheringState", new_state);
269 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum); 273 jni()->CallVoidMethod(*j_observer_global_, m, new_state_enum);
270 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 274 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
271 } 275 }
272 276
273 void OnAddStream(MediaStreamInterface* stream) override { 277 void OnAddStream(MediaStreamInterface* stream) override {
274 ScopedLocalRefFrame local_ref_frame(jni()); 278 ScopedLocalRefFrame local_ref_frame(jni());
275 jobject j_stream = jni()->NewObject( 279 // Java MediaStream holds one reference. Corresponding Release() is in
276 *j_media_stream_class_, j_media_stream_ctor_, (jlong)stream); 280 // MediaStream_free, triggered by MediaStream.dispose().
281 stream->AddRef();
282 jobject j_stream =
283 jni()->NewObject(*j_media_stream_class_, j_media_stream_ctor_,
284 reinterpret_cast<jlong>(stream));
277 CHECK_EXCEPTION(jni()) << "error during NewObject"; 285 CHECK_EXCEPTION(jni()) << "error during NewObject";
278 286
279 AudioTrackVector audio_tracks = stream->GetAudioTracks(); 287 for (const auto& track : stream->GetAudioTracks()) {
280 for (size_t i = 0; i < audio_tracks.size(); ++i) {
281 AudioTrackInterface* track = audio_tracks[i];
282 jstring id = JavaStringFromStdString(jni(), track->id()); 288 jstring id = JavaStringFromStdString(jni(), track->id());
283 jobject j_track = jni()->NewObject( 289 // Java AudioTrack holds one reference. Corresponding Release() is in
284 *j_audio_track_class_, j_audio_track_ctor_, (jlong)track, id); 290 // MediaStreamTrack_free, triggered by AudioTrack.dispose().
291 track->AddRef();
292 jobject j_track =
293 jni()->NewObject(*j_audio_track_class_, j_audio_track_ctor_,
294 reinterpret_cast<jlong>(track.get()), id);
285 CHECK_EXCEPTION(jni()) << "error during NewObject"; 295 CHECK_EXCEPTION(jni()) << "error during NewObject";
286 jfieldID audio_tracks_id = GetFieldID(jni(), 296 jfieldID audio_tracks_id = GetFieldID(jni(),
287 *j_media_stream_class_, 297 *j_media_stream_class_,
288 "audioTracks", 298 "audioTracks",
289 "Ljava/util/LinkedList;"); 299 "Ljava/util/LinkedList;");
290 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id); 300 jobject audio_tracks = GetObjectField(jni(), j_stream, audio_tracks_id);
291 jmethodID add = GetMethodID(jni(), 301 jmethodID add = GetMethodID(jni(),
292 GetObjectClass(jni(), audio_tracks), 302 GetObjectClass(jni(), audio_tracks),
293 "add", 303 "add",
294 "(Ljava/lang/Object;)Z"); 304 "(Ljava/lang/Object;)Z");
295 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track); 305 jboolean added = jni()->CallBooleanMethod(audio_tracks, add, j_track);
296 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; 306 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
297 CHECK(added); 307 CHECK(added);
298 } 308 }
299 309
300 VideoTrackVector video_tracks = stream->GetVideoTracks(); 310 for (const auto& track : stream->GetVideoTracks()) {
301 for (size_t i = 0; i < video_tracks.size(); ++i) {
302 VideoTrackInterface* track = video_tracks[i];
303 jstring id = JavaStringFromStdString(jni(), track->id()); 311 jstring id = JavaStringFromStdString(jni(), track->id());
304 jobject j_track = jni()->NewObject( 312 // Java VideoTrack holds one reference. Corresponding Release() is in
305 *j_video_track_class_, j_video_track_ctor_, (jlong)track, id); 313 // MediaStreamTrack_free, triggered by VideoTrack.dispose().
314 track->AddRef();
315 jobject j_track =
316 jni()->NewObject(*j_video_track_class_, j_video_track_ctor_,
317 reinterpret_cast<jlong>(track.get()), id);
306 CHECK_EXCEPTION(jni()) << "error during NewObject"; 318 CHECK_EXCEPTION(jni()) << "error during NewObject";
307 jfieldID video_tracks_id = GetFieldID(jni(), 319 jfieldID video_tracks_id = GetFieldID(jni(),
308 *j_media_stream_class_, 320 *j_media_stream_class_,
309 "videoTracks", 321 "videoTracks",
310 "Ljava/util/LinkedList;"); 322 "Ljava/util/LinkedList;");
311 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id); 323 jobject video_tracks = GetObjectField(jni(), j_stream, video_tracks_id);
312 jmethodID add = GetMethodID(jni(), 324 jmethodID add = GetMethodID(jni(),
313 GetObjectClass(jni(), video_tracks), 325 GetObjectClass(jni(), video_tracks),
314 "add", 326 "add",
315 "(Ljava/lang/Object;)Z"); 327 "(Ljava/lang/Object;)Z");
316 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track); 328 jboolean added = jni()->CallBooleanMethod(video_tracks, add, j_track);
317 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod"; 329 CHECK_EXCEPTION(jni()) << "error during CallBooleanMethod";
318 CHECK(added); 330 CHECK(added);
319 } 331 }
320 streams_[stream] = jni()->NewWeakGlobalRef(j_stream); 332 remote_streams_[stream] = NewGlobalRef(jni(), j_stream);
321 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
322 333
323 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", 334 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
324 "(Lorg/webrtc/MediaStream;)V"); 335 "(Lorg/webrtc/MediaStream;)V");
325 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); 336 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
326 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 337 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
327 } 338 }
328 339
329 void OnRemoveStream(MediaStreamInterface* stream) override { 340 void OnRemoveStream(MediaStreamInterface* stream) override {
330 ScopedLocalRefFrame local_ref_frame(jni()); 341 ScopedLocalRefFrame local_ref_frame(jni());
331 NativeToJavaStreamsMap::iterator it = streams_.find(stream); 342 NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
332 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream; 343 CHECK(it != remote_streams_.end()) << "unexpected stream: " << std::hex
333 344 << stream;
334 WeakRef s(jni(), it->second); 345 jobject j_stream = it->second;
335 streams_.erase(it);
336 if (!s.obj())
337 return;
338
339 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream", 346 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
340 "(Lorg/webrtc/MediaStream;)V"); 347 "(Lorg/webrtc/MediaStream;)V");
341 jni()->CallVoidMethod(*j_observer_global_, m, s.obj()); 348 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
342 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 349 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
350 DisposeRemoteStream(it);
343 } 351 }
344 352
345 void OnDataChannel(DataChannelInterface* channel) override { 353 void OnDataChannel(DataChannelInterface* channel) override {
346 ScopedLocalRefFrame local_ref_frame(jni()); 354 ScopedLocalRefFrame local_ref_frame(jni());
347 jobject j_channel = jni()->NewObject( 355 jobject j_channel = jni()->NewObject(
348 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel); 356 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
349 CHECK_EXCEPTION(jni()) << "error during NewObject"; 357 CHECK_EXCEPTION(jni()) << "error during NewObject";
350 358
351 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", 359 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
352 "(Lorg/webrtc/DataChannel;)V"); 360 "(Lorg/webrtc/DataChannel;)V");
(...skipping 18 matching lines...) Expand all
371 } 379 }
372 380
373 void SetConstraints(ConstraintsWrapper* constraints) { 381 void SetConstraints(ConstraintsWrapper* constraints) {
374 CHECK(!constraints_.get()) << "constraints already set!"; 382 CHECK(!constraints_.get()) << "constraints already set!";
375 constraints_.reset(constraints); 383 constraints_.reset(constraints);
376 } 384 }
377 385
378 const ConstraintsWrapper* constraints() { return constraints_.get(); } 386 const ConstraintsWrapper* constraints() { return constraints_.get(); }
379 387
380 private: 388 private:
389 typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap;
390
391 void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it) {
392 jobject j_stream = it->second;
393 remote_streams_.erase(it);
394 jni()->CallVoidMethod(
395 j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V"));
396 CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()";
397 DeleteGlobalRef(jni(), j_stream);
398 }
399
381 JNIEnv* jni() { 400 JNIEnv* jni() {
382 return AttachCurrentThreadIfNeeded(); 401 return AttachCurrentThreadIfNeeded();
383 } 402 }
384 403
385 const ScopedGlobalRef<jobject> j_observer_global_; 404 const ScopedGlobalRef<jobject> j_observer_global_;
386 const ScopedGlobalRef<jclass> j_observer_class_; 405 const ScopedGlobalRef<jclass> j_observer_class_;
387 const ScopedGlobalRef<jclass> j_media_stream_class_; 406 const ScopedGlobalRef<jclass> j_media_stream_class_;
388 const jmethodID j_media_stream_ctor_; 407 const jmethodID j_media_stream_ctor_;
389 const ScopedGlobalRef<jclass> j_audio_track_class_; 408 const ScopedGlobalRef<jclass> j_audio_track_class_;
390 const jmethodID j_audio_track_ctor_; 409 const jmethodID j_audio_track_ctor_;
391 const ScopedGlobalRef<jclass> j_video_track_class_; 410 const ScopedGlobalRef<jclass> j_video_track_class_;
392 const jmethodID j_video_track_ctor_; 411 const jmethodID j_video_track_ctor_;
393 const ScopedGlobalRef<jclass> j_data_channel_class_; 412 const ScopedGlobalRef<jclass> j_data_channel_class_;
394 const jmethodID j_data_channel_ctor_; 413 const jmethodID j_data_channel_ctor_;
395 typedef std::map<void*, jweak> NativeToJavaStreamsMap; 414 // C++ -> Java remote streams. The stored jobects are global refs and must be
396 NativeToJavaStreamsMap streams_; // C++ -> Java streams. 415 // manually deleted upon removal. Use DisposeRemoteStream().
416 NativeToJavaStreamsMap remote_streams_;
397 scoped_ptr<ConstraintsWrapper> constraints_; 417 scoped_ptr<ConstraintsWrapper> constraints_;
398 }; 418 };
399 419
400 // Wrapper for a Java MediaConstraints object. Copies all needed data so when 420 // Wrapper for a Java MediaConstraints object. Copies all needed data so when
401 // the constructor returns the Java object is no longer needed. 421 // the constructor returns the Java object is no longer needed.
402 class ConstraintsWrapper : public MediaConstraintsInterface { 422 class ConstraintsWrapper : public MediaConstraintsInterface {
403 public: 423 public:
404 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) { 424 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
405 PopulateConstraintsFromJavaPairList( 425 PopulateConstraintsFromJavaPairList(
406 jni, j_constraints, "mandatory", &mandatory_); 426 jni, j_constraints, "mandatory", &mandatory_);
(...skipping 1270 matching lines...) Expand 10 before | Expand all | Expand 10 after
1677 } 1697 }
1678 1698
1679 JOW(void, VideoTrack_nativeRemoveRenderer)( 1699 JOW(void, VideoTrack_nativeRemoveRenderer)(
1680 JNIEnv* jni, jclass, 1700 JNIEnv* jni, jclass,
1681 jlong j_video_track_pointer, jlong j_renderer_pointer) { 1701 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1682 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer( 1702 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
1683 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer)); 1703 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1684 } 1704 }
1685 1705
1686 } // namespace webrtc_jni 1706 } // namespace webrtc_jni
OLDNEW
« no previous file with comments | « talk/app/webrtc/java/jni/jni_helpers.cc ('k') | webrtc/examples/androidapp/src/org/appspot/apprtc/PeerConnectionClient.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698