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 package org.webrtc; 12 13 import java.util.ArrayList; 14 import java.util.Iterator; 15 import java.util.List; 16 17 /** Java wrapper for a C++ MediaStreamInterface. */ 18 public class MediaStream { 19 private static final String TAG = "MediaStream"; 20 21 public final List<AudioTrack> audioTracks = new ArrayList<>(); 22 public final List<VideoTrack> videoTracks = new ArrayList<>(); 23 public final List<VideoTrack> preservedVideoTracks = new ArrayList<>(); 24 private long nativeStream; 25 26 @CalledByNative MediaStream(long nativeStream)27 public MediaStream(long nativeStream) { 28 this.nativeStream = nativeStream; 29 } 30 addTrack(AudioTrack track)31 public boolean addTrack(AudioTrack track) { 32 checkMediaStreamExists(); 33 if (nativeAddAudioTrackToNativeStream(nativeStream, track.getNativeAudioTrack())) { 34 audioTracks.add(track); 35 return true; 36 } 37 return false; 38 } 39 addTrack(VideoTrack track)40 public boolean addTrack(VideoTrack track) { 41 checkMediaStreamExists(); 42 if (nativeAddVideoTrackToNativeStream(nativeStream, track.getNativeVideoTrack())) { 43 videoTracks.add(track); 44 return true; 45 } 46 return false; 47 } 48 49 // Tracks added in addTrack() call will be auto released once MediaStream.dispose() 50 // is called. If video track need to be preserved after MediaStream is destroyed it 51 // should be added to MediaStream using addPreservedTrack() call. addPreservedTrack(VideoTrack track)52 public boolean addPreservedTrack(VideoTrack track) { 53 checkMediaStreamExists(); 54 if (nativeAddVideoTrackToNativeStream(nativeStream, track.getNativeVideoTrack())) { 55 preservedVideoTracks.add(track); 56 return true; 57 } 58 return false; 59 } 60 removeTrack(AudioTrack track)61 public boolean removeTrack(AudioTrack track) { 62 checkMediaStreamExists(); 63 audioTracks.remove(track); 64 return nativeRemoveAudioTrack(nativeStream, track.getNativeAudioTrack()); 65 } 66 removeTrack(VideoTrack track)67 public boolean removeTrack(VideoTrack track) { 68 checkMediaStreamExists(); 69 videoTracks.remove(track); 70 preservedVideoTracks.remove(track); 71 return nativeRemoveVideoTrack(nativeStream, track.getNativeVideoTrack()); 72 } 73 74 @CalledByNative dispose()75 public void dispose() { 76 checkMediaStreamExists(); 77 // Remove and release previously added audio and video tracks. 78 while (!audioTracks.isEmpty()) { 79 AudioTrack track = audioTracks.get(0 /* index */); 80 removeTrack(track); 81 track.dispose(); 82 } 83 while (!videoTracks.isEmpty()) { 84 VideoTrack track = videoTracks.get(0 /* index */); 85 removeTrack(track); 86 track.dispose(); 87 } 88 // Remove, but do not release preserved video tracks. 89 while (!preservedVideoTracks.isEmpty()) { 90 removeTrack(preservedVideoTracks.get(0 /* index */)); 91 } 92 JniCommon.nativeReleaseRef(nativeStream); 93 nativeStream = 0; 94 } 95 getId()96 public String getId() { 97 checkMediaStreamExists(); 98 return nativeGetId(nativeStream); 99 } 100 101 @Override toString()102 public String toString() { 103 return "[" + getId() + ":A=" + audioTracks.size() + ":V=" + videoTracks.size() + "]"; 104 } 105 106 @CalledByNative addNativeAudioTrack(long nativeTrack)107 void addNativeAudioTrack(long nativeTrack) { 108 audioTracks.add(new AudioTrack(nativeTrack)); 109 } 110 111 @CalledByNative addNativeVideoTrack(long nativeTrack)112 void addNativeVideoTrack(long nativeTrack) { 113 videoTracks.add(new VideoTrack(nativeTrack)); 114 } 115 116 @CalledByNative removeAudioTrack(long nativeTrack)117 void removeAudioTrack(long nativeTrack) { 118 removeMediaStreamTrack(audioTracks, nativeTrack); 119 } 120 121 @CalledByNative removeVideoTrack(long nativeTrack)122 void removeVideoTrack(long nativeTrack) { 123 removeMediaStreamTrack(videoTracks, nativeTrack); 124 } 125 126 /** Returns a pointer to webrtc::MediaStreamInterface. */ getNativeMediaStream()127 long getNativeMediaStream() { 128 checkMediaStreamExists(); 129 return nativeStream; 130 } 131 checkMediaStreamExists()132 private void checkMediaStreamExists() { 133 if (nativeStream == 0) { 134 throw new IllegalStateException("MediaStream has been disposed."); 135 } 136 } 137 removeMediaStreamTrack( List<? extends MediaStreamTrack> tracks, long nativeTrack)138 private static void removeMediaStreamTrack( 139 List<? extends MediaStreamTrack> tracks, long nativeTrack) { 140 final Iterator<? extends MediaStreamTrack> it = tracks.iterator(); 141 while (it.hasNext()) { 142 MediaStreamTrack track = it.next(); 143 if (track.getNativeMediaStreamTrack() == nativeTrack) { 144 track.dispose(); 145 it.remove(); 146 return; 147 } 148 } 149 Logging.e(TAG, "Couldn't not find track"); 150 } 151 nativeAddAudioTrackToNativeStream( long stream, long nativeAudioTrack)152 private static native boolean nativeAddAudioTrackToNativeStream( 153 long stream, long nativeAudioTrack); nativeAddVideoTrackToNativeStream( long stream, long nativeVideoTrack)154 private static native boolean nativeAddVideoTrackToNativeStream( 155 long stream, long nativeVideoTrack); nativeRemoveAudioTrack(long stream, long nativeAudioTrack)156 private static native boolean nativeRemoveAudioTrack(long stream, long nativeAudioTrack); nativeRemoveVideoTrack(long stream, long nativeVideoTrack)157 private static native boolean nativeRemoveVideoTrack(long stream, long nativeVideoTrack); nativeGetId(long stream)158 private static native String nativeGetId(long stream); 159 } 160