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