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

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: Addressing comments 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] = jni()->NewGlobalRef(j_stream);
AlexG 2015/08/26 17:18:07 nit: use NewGlobalRef(jni, j_stream) and remove or
321 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef"; 333 CHECK_EXCEPTION(jni()) << "error during NewWeakGlobalRef";
322 334
323 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream", 335 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onAddStream",
324 "(Lorg/webrtc/MediaStream;)V"); 336 "(Lorg/webrtc/MediaStream;)V");
325 jni()->CallVoidMethod(*j_observer_global_, m, j_stream); 337 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
326 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 338 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
327 } 339 }
328 340
329 void OnRemoveStream(MediaStreamInterface* stream) override { 341 void OnRemoveStream(MediaStreamInterface* stream) override {
330 ScopedLocalRefFrame local_ref_frame(jni()); 342 ScopedLocalRefFrame local_ref_frame(jni());
331 NativeToJavaStreamsMap::iterator it = streams_.find(stream); 343 NativeToJavaStreamsMap::iterator it = remote_streams_.find(stream);
332 CHECK(it != streams_.end()) << "unexpected stream: " << std::hex << stream; 344 CHECK(it != remote_streams_.end()) << "unexpected stream: " << std::hex
333 345 << stream;
334 WeakRef s(jni(), it->second); 346 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", 347 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onRemoveStream",
340 "(Lorg/webrtc/MediaStream;)V"); 348 "(Lorg/webrtc/MediaStream;)V");
341 jni()->CallVoidMethod(*j_observer_global_, m, s.obj()); 349 jni()->CallVoidMethod(*j_observer_global_, m, j_stream);
342 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod"; 350 CHECK_EXCEPTION(jni()) << "error during CallVoidMethod";
351 DisposeRemoteStream(it);
343 } 352 }
344 353
345 void OnDataChannel(DataChannelInterface* channel) override { 354 void OnDataChannel(DataChannelInterface* channel) override {
346 ScopedLocalRefFrame local_ref_frame(jni()); 355 ScopedLocalRefFrame local_ref_frame(jni());
347 jobject j_channel = jni()->NewObject( 356 jobject j_channel = jni()->NewObject(
348 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel); 357 *j_data_channel_class_, j_data_channel_ctor_, (jlong)channel);
349 CHECK_EXCEPTION(jni()) << "error during NewObject"; 358 CHECK_EXCEPTION(jni()) << "error during NewObject";
350 359
351 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel", 360 jmethodID m = GetMethodID(jni(), *j_observer_class_, "onDataChannel",
352 "(Lorg/webrtc/DataChannel;)V"); 361 "(Lorg/webrtc/DataChannel;)V");
(...skipping 18 matching lines...) Expand all
371 } 380 }
372 381
373 void SetConstraints(ConstraintsWrapper* constraints) { 382 void SetConstraints(ConstraintsWrapper* constraints) {
374 CHECK(!constraints_.get()) << "constraints already set!"; 383 CHECK(!constraints_.get()) << "constraints already set!";
375 constraints_.reset(constraints); 384 constraints_.reset(constraints);
376 } 385 }
377 386
378 const ConstraintsWrapper* constraints() { return constraints_.get(); } 387 const ConstraintsWrapper* constraints() { return constraints_.get(); }
379 388
380 private: 389 private:
390 typedef std::map<MediaStreamInterface*, jobject> NativeToJavaStreamsMap;
391
392 void DisposeRemoteStream(const NativeToJavaStreamsMap::iterator& it) {
393 jobject j_stream = it->second;
394 remote_streams_.erase(it);
395 jni()->CallVoidMethod(
396 j_stream, GetMethodID(jni(), *j_media_stream_class_, "dispose", "()V"));
397 CHECK_EXCEPTION(jni()) << "error during MediaStream.dispose()";
398 DeleteGlobalRef(jni(), j_stream);
399 }
400
381 JNIEnv* jni() { 401 JNIEnv* jni() {
382 return AttachCurrentThreadIfNeeded(); 402 return AttachCurrentThreadIfNeeded();
383 } 403 }
384 404
385 const ScopedGlobalRef<jobject> j_observer_global_; 405 const ScopedGlobalRef<jobject> j_observer_global_;
386 const ScopedGlobalRef<jclass> j_observer_class_; 406 const ScopedGlobalRef<jclass> j_observer_class_;
387 const ScopedGlobalRef<jclass> j_media_stream_class_; 407 const ScopedGlobalRef<jclass> j_media_stream_class_;
388 const jmethodID j_media_stream_ctor_; 408 const jmethodID j_media_stream_ctor_;
389 const ScopedGlobalRef<jclass> j_audio_track_class_; 409 const ScopedGlobalRef<jclass> j_audio_track_class_;
390 const jmethodID j_audio_track_ctor_; 410 const jmethodID j_audio_track_ctor_;
391 const ScopedGlobalRef<jclass> j_video_track_class_; 411 const ScopedGlobalRef<jclass> j_video_track_class_;
392 const jmethodID j_video_track_ctor_; 412 const jmethodID j_video_track_ctor_;
393 const ScopedGlobalRef<jclass> j_data_channel_class_; 413 const ScopedGlobalRef<jclass> j_data_channel_class_;
394 const jmethodID j_data_channel_ctor_; 414 const jmethodID j_data_channel_ctor_;
395 typedef std::map<void*, jweak> NativeToJavaStreamsMap; 415 // C++ -> Java remote streams. The stored jobects are global refs and must be
396 NativeToJavaStreamsMap streams_; // C++ -> Java streams. 416 // manually deleted upon removal. Use DisposeRemoteStream().
417 NativeToJavaStreamsMap remote_streams_;
397 scoped_ptr<ConstraintsWrapper> constraints_; 418 scoped_ptr<ConstraintsWrapper> constraints_;
398 }; 419 };
399 420
400 // Wrapper for a Java MediaConstraints object. Copies all needed data so when 421 // Wrapper for a Java MediaConstraints object. Copies all needed data so when
401 // the constructor returns the Java object is no longer needed. 422 // the constructor returns the Java object is no longer needed.
402 class ConstraintsWrapper : public MediaConstraintsInterface { 423 class ConstraintsWrapper : public MediaConstraintsInterface {
403 public: 424 public:
404 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) { 425 ConstraintsWrapper(JNIEnv* jni, jobject j_constraints) {
405 PopulateConstraintsFromJavaPairList( 426 PopulateConstraintsFromJavaPairList(
406 jni, j_constraints, "mandatory", &mandatory_); 427 jni, j_constraints, "mandatory", &mandatory_);
(...skipping 1270 matching lines...) Expand 10 before | Expand all | Expand 10 after
1677 } 1698 }
1678 1699
1679 JOW(void, VideoTrack_nativeRemoveRenderer)( 1700 JOW(void, VideoTrack_nativeRemoveRenderer)(
1680 JNIEnv* jni, jclass, 1701 JNIEnv* jni, jclass,
1681 jlong j_video_track_pointer, jlong j_renderer_pointer) { 1702 jlong j_video_track_pointer, jlong j_renderer_pointer) {
1682 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer( 1703 reinterpret_cast<VideoTrackInterface*>(j_video_track_pointer)->RemoveRenderer(
1683 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer)); 1704 reinterpret_cast<VideoRendererInterface*>(j_renderer_pointer));
1684 } 1705 }
1685 1706
1686 } // namespace webrtc_jni 1707 } // 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