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
29package org.webrtc;
30
31import java.util.LinkedList;
32import java.util.List;
33
34/**
35 * Java-land version of the PeerConnection APIs; wraps the C++ API
36 * http://www.webrtc.org/reference/native-apis, which in turn is inspired by the
37 * JS APIs: http://dev.w3.org/2011/webrtc/editor/webrtc.html and
38 * http://www.w3.org/TR/mediacapture-streams/
39 */
40public class PeerConnection {
41  static {
42    System.loadLibrary("jingle_peerconnection_so");
43  }
44
45  /** Tracks PeerConnectionInterface::IceGatheringState */
46  public enum IceGatheringState { NEW, GATHERING, COMPLETE };
47
48
49  /** Tracks PeerConnectionInterface::IceConnectionState */
50  public enum IceConnectionState {
51    NEW, CHECKING, CONNECTED, COMPLETED, FAILED, DISCONNECTED, CLOSED
52  };
53
54  /** Tracks PeerConnectionInterface::SignalingState */
55  public enum SignalingState {
56    STABLE, HAVE_LOCAL_OFFER, HAVE_LOCAL_PRANSWER, HAVE_REMOTE_OFFER,
57    HAVE_REMOTE_PRANSWER, CLOSED
58  };
59
60  /** Java version of PeerConnectionObserver. */
61  public static interface Observer {
62    /** Triggered when the SignalingState changes. */
63    public void onSignalingChange(SignalingState newState);
64
65    /** Triggered when the IceConnectionState changes. */
66    public void onIceConnectionChange(IceConnectionState newState);
67
68    /** Triggered when the IceGatheringState changes. */
69    public void onIceGatheringChange(IceGatheringState newState);
70
71    /** Triggered when a new ICE candidate has been found. */
72    public void onIceCandidate(IceCandidate candidate);
73
74    /** Triggered on any error. */
75    public void onError();
76
77    /** Triggered when media is received on a new stream from remote peer. */
78    public void onAddStream(MediaStream stream);
79
80    /** Triggered when a remote peer close a stream. */
81    public void onRemoveStream(MediaStream stream);
82
83    /** Triggered when a remote peer opens a DataChannel. */
84    public void onDataChannel(DataChannel dataChannel);
85
86    /** Triggered when renegotiation is necessary. */
87    public void onRenegotiationNeeded();
88  }
89
90  /** Java version of PeerConnectionInterface.IceServer. */
91  public static class IceServer {
92    public final String uri;
93    public final String username;
94    public final String password;
95
96    /** Convenience constructor for STUN servers. */
97    public IceServer(String uri) {
98      this(uri, "", "");
99    }
100
101    public IceServer(String uri, String username, String password) {
102      this.uri = uri;
103      this.username = username;
104      this.password = password;
105    }
106
107    public String toString() {
108      return uri + "[" + username + ":" + password + "]";
109    }
110  }
111
112  private final List<MediaStream> localStreams;
113  private final long nativePeerConnection;
114  private final long nativeObserver;
115
116  PeerConnection(long nativePeerConnection, long nativeObserver) {
117    this.nativePeerConnection = nativePeerConnection;
118    this.nativeObserver = nativeObserver;
119    localStreams = new LinkedList<MediaStream>();
120  }
121
122  // JsepInterface.
123  public native SessionDescription getLocalDescription();
124
125  public native SessionDescription getRemoteDescription();
126
127  public native DataChannel createDataChannel(
128      String label, DataChannel.Init init);
129
130  public native void createOffer(
131      SdpObserver observer, MediaConstraints constraints);
132
133  public native void createAnswer(
134      SdpObserver observer, MediaConstraints constraints);
135
136  public native void setLocalDescription(
137      SdpObserver observer, SessionDescription sdp);
138
139  public native void setRemoteDescription(
140      SdpObserver observer, SessionDescription sdp);
141
142  public native boolean updateIce(
143      List<IceServer> iceServers, MediaConstraints constraints);
144
145  public boolean addIceCandidate(IceCandidate candidate) {
146    return nativeAddIceCandidate(
147        candidate.sdpMid, candidate.sdpMLineIndex, candidate.sdp);
148  }
149
150  public boolean addStream(
151      MediaStream stream, MediaConstraints constraints) {
152    boolean ret = nativeAddLocalStream(stream.nativeStream, constraints);
153    if (!ret) {
154      return false;
155    }
156    localStreams.add(stream);
157    return true;
158  }
159
160  public void removeStream(MediaStream stream) {
161    nativeRemoveLocalStream(stream.nativeStream);
162    localStreams.remove(stream);
163  }
164
165  public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
166    return nativeGetStats(observer, (track == null) ? 0 : track.nativeTrack);
167  }
168
169  // TODO(fischman): add support for DTMF-related methods once that API
170  // stabilizes.
171  public native SignalingState signalingState();
172
173  public native IceConnectionState iceConnectionState();
174
175  public native IceGatheringState iceGatheringState();
176
177  public native void close();
178
179  public void dispose() {
180    close();
181    for (MediaStream stream : localStreams) {
182      nativeRemoveLocalStream(stream.nativeStream);
183      stream.dispose();
184    }
185    localStreams.clear();
186    freePeerConnection(nativePeerConnection);
187    freeObserver(nativeObserver);
188  }
189
190  private static native void freePeerConnection(long nativePeerConnection);
191
192  private static native void freeObserver(long nativeObserver);
193
194  private native boolean nativeAddIceCandidate(
195      String sdpMid, int sdpMLineIndex, String iceCandidateSdp);
196
197  private native boolean nativeAddLocalStream(
198      long nativeStream, MediaConstraints constraints);
199
200  private native void nativeRemoveLocalStream(long nativeStream);
201
202  private native boolean nativeGetStats(
203      StatsObserver observer, long nativeTrack);
204}
205