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. */ 64 public void onSignalingChange(SignalingState newState); 65 66 /** Triggered when the IceConnectionState changes. */ 67 public void onIceConnectionChange(IceConnectionState newState); 68 69 /** Triggered when the ICE connection receiving status changes. */ 70 public void onIceConnectionReceivingChange(boolean receiving); 71 72 /** Triggered when the IceGatheringState changes. */ 73 public void onIceGatheringChange(IceGatheringState newState); 74 75 /** Triggered when a new ICE candidate has been found. */ 76 public void onIceCandidate(IceCandidate candidate); 77 78 /** Triggered when media is received on a new stream from remote peer. */ 79 public void onAddStream(MediaStream stream); 80 81 /** Triggered when a remote peer close a stream. */ 82 public void onRemoveStream(MediaStream stream); 83 84 /** Triggered when a remote peer opens a DataChannel. */ 85 public void onDataChannel(DataChannel dataChannel); 86 87 /** Triggered when renegotiation is necessary. */ 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. */ 98 public IceServer(String uri) { 99 this(uri, "", ""); 100 } 101 102 public IceServer(String uri, String username, String password) { 103 this.uri = uri; 104 this.username = username; 105 this.password = password; 106 } 107 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 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 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. 187 public native SessionDescription getLocalDescription(); 188 189 public native SessionDescription getRemoteDescription(); 190 191 public native DataChannel createDataChannel( 192 String label, DataChannel.Init init); 193 194 public native void createOffer( 195 SdpObserver observer, MediaConstraints constraints); 196 197 public native void createAnswer( 198 SdpObserver observer, MediaConstraints constraints); 199 200 public native void setLocalDescription( 201 SdpObserver observer, SessionDescription sdp); 202 203 public native void setRemoteDescription( 204 SdpObserver observer, SessionDescription sdp); 205 206 public native boolean setConfiguration(RTCConfiguration config); 207 208 public boolean addIceCandidate(IceCandidate candidate) { 209 return nativeAddIceCandidate( 210 candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp); 211 } 212 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 222 public void removeStream(MediaStream stream) { 223 nativeRemoveLocalStream(stream.nativeStream); 224 localStreams.remove(stream); 225 } 226 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). 237 public List<RtpSender> getSenders() { 238 for (RtpSender sender : senders) { 239 sender.dispose(); 240 } 241 senders = nativeGetSenders(); 242 return Collections.unmodifiableList(senders); 243 } 244 245 public List<RtpReceiver> getReceivers() { 246 for (RtpReceiver receiver : receivers) { 247 receiver.dispose(); 248 } 249 receivers = nativeGetReceivers(); 250 return Collections.unmodifiableList(receivers); 251 } 252 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. 259 public native SignalingState signalingState(); 260 261 public native IceConnectionState iceConnectionState(); 262 263 public native IceGatheringState iceGatheringState(); 264 265 public native void close(); 266 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 286 private static native void freePeerConnection(long nativePeerConnection); 287 288 private static native void freeObserver(long nativeObserver); 289 290 private native boolean nativeAddIceCandidate( 291 String sdpMid, int sdpMLineIndex, String iceCandidateSdp); 292 293 private native boolean nativeAddLocalStream(long nativeStream); 294 295 private native void nativeRemoveLocalStream(long nativeStream); 296 297 private native boolean nativeGetStats( 298 StatsObserver observer, long nativeTrack); 299 300 private native RtpSender nativeCreateSender(String kind, String stream_id); 301 302 private native List<RtpSender> nativeGetSenders(); 303 304 private native List<RtpReceiver> nativeGetReceivers(); 305 } 306