1 /*
2  * libjingle
3  * Copyright 2013 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 
29 package org.webrtc;
30 
31 import java.util.Collections;
32 import java.util.LinkedList;
33 import java.util.List;
34 
35 /**
36  * Java-land version of the PeerConnection APIs; wraps the C++ API
37  * http://www.webrtc.org/reference/native-apis, which in turn is inspired by the
38  * JS APIs: http://dev.w3.org/2011/webrtc/editor/webrtc.html and
39  * http://www.w3.org/TR/mediacapture-streams/
40  */
41 public class PeerConnection {
42   static {
43     System.loadLibrary("jingle_peerconnection_so");
44   }
45 
46   /** Tracks PeerConnectionInterface::IceGatheringState */
47   public enum IceGatheringState { NEW, GATHERING, COMPLETE };
48 
49 
50   /** Tracks PeerConnectionInterface::IceConnectionState */
51   public enum IceConnectionState {
52     NEW, CHECKING, CONNECTED, COMPLETED, FAILED, DISCONNECTED, CLOSED
53   };
54 
55   /** Tracks PeerConnectionInterface::SignalingState */
56   public enum SignalingState {
57     STABLE, HAVE_LOCAL_OFFER, HAVE_LOCAL_PRANSWER, HAVE_REMOTE_OFFER,
58     HAVE_REMOTE_PRANSWER, CLOSED
59   };
60 
61   /** Java version of PeerConnectionObserver. */
62   public static interface Observer {
63     /** Triggered when the SignalingState changes. */
onSignalingChange(SignalingState newState)64     public void onSignalingChange(SignalingState newState);
65 
66     /** Triggered when the IceConnectionState changes. */
onIceConnectionChange(IceConnectionState newState)67     public void onIceConnectionChange(IceConnectionState newState);
68 
69     /** Triggered when the ICE connection receiving status changes. */
onIceConnectionReceivingChange(boolean receiving)70     public void onIceConnectionReceivingChange(boolean receiving);
71 
72     /** Triggered when the IceGatheringState changes. */
onIceGatheringChange(IceGatheringState newState)73     public void onIceGatheringChange(IceGatheringState newState);
74 
75     /** Triggered when a new ICE candidate has been found. */
onIceCandidate(IceCandidate candidate)76     public void onIceCandidate(IceCandidate candidate);
77 
78     /** Triggered when media is received on a new stream from remote peer. */
onAddStream(MediaStream stream)79     public void onAddStream(MediaStream stream);
80 
81     /** Triggered when a remote peer close a stream. */
onRemoveStream(MediaStream stream)82     public void onRemoveStream(MediaStream stream);
83 
84     /** Triggered when a remote peer opens a DataChannel. */
onDataChannel(DataChannel dataChannel)85     public void onDataChannel(DataChannel dataChannel);
86 
87     /** Triggered when renegotiation is necessary. */
onRenegotiationNeeded()88     public void onRenegotiationNeeded();
89   }
90 
91   /** Java version of PeerConnectionInterface.IceServer. */
92   public static class IceServer {
93     public final String uri;
94     public final String username;
95     public final String password;
96 
97     /** Convenience constructor for STUN servers. */
IceServer(String uri)98     public IceServer(String uri) {
99       this(uri, "", "");
100     }
101 
IceServer(String uri, String username, String password)102     public IceServer(String uri, String username, String password) {
103       this.uri = uri;
104       this.username = username;
105       this.password = password;
106     }
107 
toString()108     public String toString() {
109       return uri + "[" + username + ":" + password + "]";
110     }
111   }
112 
113   /** Java version of PeerConnectionInterface.IceTransportsType */
114   public enum IceTransportsType {
115     NONE, RELAY, NOHOST, ALL
116   };
117 
118   /** Java version of PeerConnectionInterface.BundlePolicy */
119   public enum BundlePolicy {
120     BALANCED, MAXBUNDLE, MAXCOMPAT
121   };
122 
123   /** Java version of PeerConnectionInterface.RtcpMuxPolicy */
124   public enum RtcpMuxPolicy {
125     NEGOTIATE, REQUIRE
126   };
127 
128   /** Java version of PeerConnectionInterface.TcpCandidatePolicy */
129   public enum TcpCandidatePolicy {
130     ENABLED, DISABLED
131   };
132 
133   /** Java version of rtc::KeyType */
134   public enum KeyType {
135     RSA, ECDSA
136   }
137 
138   /** Java version of PeerConnectionInterface.ContinualGatheringPolicy */
139   public enum ContinualGatheringPolicy {
140     GATHER_ONCE, GATHER_CONTINUALLY
141   }
142 
143   /** Java version of PeerConnectionInterface.RTCConfiguration */
144   public static class RTCConfiguration {
145     public IceTransportsType iceTransportsType;
146     public List<IceServer> iceServers;
147     public BundlePolicy bundlePolicy;
148     public RtcpMuxPolicy rtcpMuxPolicy;
149     public TcpCandidatePolicy tcpCandidatePolicy;
150     public int audioJitterBufferMaxPackets;
151     public boolean audioJitterBufferFastAccelerate;
152     public int iceConnectionReceivingTimeout;
153     public int iceBackupCandidatePairPingInterval;
154     public KeyType keyType;
155     public ContinualGatheringPolicy continualGatheringPolicy;
156 
RTCConfiguration(List<IceServer> iceServers)157     public RTCConfiguration(List<IceServer> iceServers) {
158       iceTransportsType = IceTransportsType.ALL;
159       bundlePolicy = BundlePolicy.BALANCED;
160       rtcpMuxPolicy = RtcpMuxPolicy.NEGOTIATE;
161       tcpCandidatePolicy = TcpCandidatePolicy.ENABLED;
162       this.iceServers = iceServers;
163       audioJitterBufferMaxPackets = 50;
164       audioJitterBufferFastAccelerate = false;
165       iceConnectionReceivingTimeout = -1;
166       iceBackupCandidatePairPingInterval = -1;
167       keyType = KeyType.ECDSA;
168       continualGatheringPolicy = ContinualGatheringPolicy.GATHER_ONCE;
169     }
170   };
171 
172   private final List<MediaStream> localStreams;
173   private final long nativePeerConnection;
174   private final long nativeObserver;
175   private List<RtpSender> senders;
176   private List<RtpReceiver> receivers;
177 
PeerConnection(long nativePeerConnection, long nativeObserver)178   PeerConnection(long nativePeerConnection, long nativeObserver) {
179     this.nativePeerConnection = nativePeerConnection;
180     this.nativeObserver = nativeObserver;
181     localStreams = new LinkedList<MediaStream>();
182     senders = new LinkedList<RtpSender>();
183     receivers = new LinkedList<RtpReceiver>();
184   }
185 
186   // JsepInterface.
getLocalDescription()187   public native SessionDescription getLocalDescription();
188 
getRemoteDescription()189   public native SessionDescription getRemoteDescription();
190 
createDataChannel( String label, DataChannel.Init init)191   public native DataChannel createDataChannel(
192       String label, DataChannel.Init init);
193 
createOffer( SdpObserver observer, MediaConstraints constraints)194   public native void createOffer(
195       SdpObserver observer, MediaConstraints constraints);
196 
createAnswer( SdpObserver observer, MediaConstraints constraints)197   public native void createAnswer(
198       SdpObserver observer, MediaConstraints constraints);
199 
setLocalDescription( SdpObserver observer, SessionDescription sdp)200   public native void setLocalDescription(
201       SdpObserver observer, SessionDescription sdp);
202 
setRemoteDescription( SdpObserver observer, SessionDescription sdp)203   public native void setRemoteDescription(
204       SdpObserver observer, SessionDescription sdp);
205 
setConfiguration(RTCConfiguration config)206   public native boolean setConfiguration(RTCConfiguration config);
207 
addIceCandidate(IceCandidate candidate)208   public boolean addIceCandidate(IceCandidate candidate) {
209     return nativeAddIceCandidate(
210         candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp);
211   }
212 
addStream(MediaStream stream)213   public boolean addStream(MediaStream stream) {
214     boolean ret = nativeAddLocalStream(stream.nativeStream);
215     if (!ret) {
216       return false;
217     }
218     localStreams.add(stream);
219     return true;
220   }
221 
removeStream(MediaStream stream)222   public void removeStream(MediaStream stream) {
223     nativeRemoveLocalStream(stream.nativeStream);
224     localStreams.remove(stream);
225   }
226 
createSender(String kind, String stream_id)227   public RtpSender createSender(String kind, String stream_id) {
228     RtpSender new_sender = nativeCreateSender(kind, stream_id);
229     if (new_sender != null) {
230       senders.add(new_sender);
231     }
232     return new_sender;
233   }
234 
235   // Note that calling getSenders will dispose of the senders previously
236   // returned (and same goes for getReceivers).
getSenders()237   public List<RtpSender> getSenders() {
238     for (RtpSender sender : senders) {
239       sender.dispose();
240     }
241     senders = nativeGetSenders();
242     return Collections.unmodifiableList(senders);
243   }
244 
getReceivers()245   public List<RtpReceiver> getReceivers() {
246     for (RtpReceiver receiver : receivers) {
247       receiver.dispose();
248     }
249     receivers = nativeGetReceivers();
250     return Collections.unmodifiableList(receivers);
251   }
252 
getStats(StatsObserver observer, MediaStreamTrack track)253   public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
254     return nativeGetStats(observer, (track == null) ? 0 : track.nativeTrack);
255   }
256 
257   // TODO(fischman): add support for DTMF-related methods once that API
258   // stabilizes.
signalingState()259   public native SignalingState signalingState();
260 
iceConnectionState()261   public native IceConnectionState iceConnectionState();
262 
iceGatheringState()263   public native IceGatheringState iceGatheringState();
264 
close()265   public native void close();
266 
dispose()267   public void dispose() {
268     close();
269     for (MediaStream stream : localStreams) {
270       nativeRemoveLocalStream(stream.nativeStream);
271       stream.dispose();
272     }
273     localStreams.clear();
274     for (RtpSender sender : senders) {
275       sender.dispose();
276     }
277     senders.clear();
278     for (RtpReceiver receiver : receivers) {
279       receiver.dispose();
280     }
281     receivers.clear();
282     freePeerConnection(nativePeerConnection);
283     freeObserver(nativeObserver);
284   }
285 
freePeerConnection(long nativePeerConnection)286   private static native void freePeerConnection(long nativePeerConnection);
287 
freeObserver(long nativeObserver)288   private static native void freeObserver(long nativeObserver);
289 
nativeAddIceCandidate( String sdpMid, int sdpMLineIndex, String iceCandidateSdp)290   private native boolean nativeAddIceCandidate(
291       String sdpMid, int sdpMLineIndex, String iceCandidateSdp);
292 
nativeAddLocalStream(long nativeStream)293   private native boolean nativeAddLocalStream(long nativeStream);
294 
nativeRemoveLocalStream(long nativeStream)295   private native void nativeRemoveLocalStream(long nativeStream);
296 
nativeGetStats( StatsObserver observer, long nativeTrack)297   private native boolean nativeGetStats(
298       StatsObserver observer, long nativeTrack);
299 
nativeCreateSender(String kind, String stream_id)300   private native RtpSender nativeCreateSender(String kind, String stream_id);
301 
nativeGetSenders()302   private native List<RtpSender> nativeGetSenders();
303 
nativeGetReceivers()304   private native List<RtpReceiver> nativeGetReceivers();
305 }
306