Source: node_modules/kurento-client-elements/lib/WebRtcEndpoint.js

/* Autogenerated with Kurento Idl */

/*
 * (C) Copyright 2013-2015 Kurento (https://kurento.openvidu.io/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var inherits = require('inherits');

var kurentoClient = require('kurento-client');

var disguise = kurentoClient.disguise;

var checkType      = kurentoClient.checkType;
var ChecktypeError = checkType.ChecktypeError;


var Transaction = kurentoClient.TransactionsManager.Transaction;

var BaseRtpEndpoint = require('kurento-client-core').abstracts.BaseRtpEndpoint;


function noop(error, result) {
  if (error) console.trace(error);

  return result
};


/**
 * Builder for the {@link WebRtcEndpoint}
 *
 * @classdesc
 *  Endpoint that provides bidirectional WebRTC capabilities for Kurento.
 *  <p>
 *    This endpoint is one side of a peer-to-peer WebRTC communication, where 
 *    the
 *    other peer is either of a WebRTC capable browser (using the
 *    <em>RTCPeerConnection</em> API), a native WebRTC app, or even another 
 *    Kurento
 *    Media Server instance.
 *  </p>
 *  <p>
 *    In order to establish WebRTC communications, peers first engage in an SDP
 *    Offer/Answer negotiation process, where one of the peers (the offerer) 
 *    sends
 *    an SDP Offer, while the other peer (the answerer) responds with an SDP 
 *    Answer.
 *    This endpoint can work in both roles.
 *  </p>
 *  <ul>
 *    <li>
 *      <b>As offerer</b>: The negotiation process is initiated by the media 
 *      server.
 *      <ul>
 *        <li>
 *          Kurento generates the SDP Offer through the
 *          <code>generateOffer()</code> method. This offer must then be sent to
 *          remote peer (the answerer) through the signaling channel.
 *        </li>
 *        <li>
 *          The remote peer process the SDP Offer, and generates an SDP Answer. 
 *          This
 *          answer is then sent back to the media server.
 *        </li>
 *        <li>
 *          Upon receiving the SDP Answer, this endpoint must process it with 
 *          the
 *          <code>processAnswer()</code> method.
 *        </li>
 *      </ul>
 *    </li>
 *    <li>
 *      <b>As answerer</b>: The negotiation process is initiated by the remote 
 *      peer.
 *      <ul>
 *        <li>
 *          The remote peer, acting as offerer, generates an SDP Offer and sends
 *          to this endpoint.
 *        </li>
 *        <li>
 *          This endpoint processes the SDP Offer with the
 *          <code>processOffer()</code> method. The result of this method will 
 *          be a
 *          string, containing an SDP Answer.
 *        </li>
 *        <li>
 *          The SDP Answer must then be sent back to the offerer, so it can be
 *          processed by it.
 *        </li>
 *      </ul>
 *    </li>
 *  </ul>
 *  <h2>ICE candidates and connectivity checks</h2>
 *  <p>
 *    SDPs are sent without ICE candidates, following the Trickle ICE 
 *    optimization.
 *    Once the SDP negotiation is completed, both peers proceed with the ICE
 *    discovery process, intended to set up a bidirectional media connection. 
 *    During
 *    this process, each peer...
 *  </p>
 *  <ul>
 *    <li>
 *      Discovers ICE candidates for itself, containing pairs of IPs and ports.
 *    </li>
 *    <li>
 *      ICE candidates are sent via the signaling channel as they are 
 *      discovered, to
 *      the remote peer for probing.
 *    </li>
 *    <li>
 *      ICE connectivity checks are run as soon as the new candidate 
 *      description,
 *      from the remote peer, is available.
 *    </li>
 *  </ul>
 *  <p>
 *    Once a suitable pair of candidates (one for each peer) is discovered, the
 *    media session can start. The harvesting process in Kurento, begins with 
 *    the
 *    invocation of the <code>gatherCandidates()</code> method. Since the whole
 *    Trickle ICE purpose is to speed-up connectivity, candidates are generated
 *    asynchronously. Therefore, in order to capture the candidates, the user 
 *    must
 *    subscribe to the event <code>IceCandidateFound</code>. It is important 
 *    that
 *    the event listener is bound before invoking 
 *    <code>gatherCandidates()</code>,
 *    otherwise a suitable candidate might be lost, and connection might not be
 *    established.
 *  </p>
 *  <p>
 *    It is important to keep in mind that WebRTC connection is an asynchronous
 *    process, when designing interactions between different MediaElements. For
 *    example, it would be pointless to start recording before media is flowing.
 *    order to be notified of state changes, the application can subscribe to 
 *    events
 *    generated by the WebRtcEndpoint. Following is a full list of events 
 *    generated
 *    by WebRtcEndpoint:
 *  </p>
 *  <ul>
 *    <li>
 *      <code>IceComponentStateChanged</code>: This event informs only about 
 *      changes
 *      in the ICE connection state. Possible values are:
 *      <ul>
 *        <li><code>DISCONNECTED</code>: No activity scheduled</li>
 *        <li><code>GATHERING</code>: Gathering local candidates</li>
 *        <li><code>CONNECTING</code>: Establishing connectivity</li>
 *        <li><code>CONNECTED</code>: At least one working candidate pair</li>
 *        <li>
 *          <code>READY</code>: ICE concluded, candidate pair selection is now 
 *          final
 *        </li>
 *        <li>
 *          <code>FAILED</code>: Connectivity checks have been completed, but 
 *          media
 *          connection was not established
 *        </li>
 *      </ul>
 *      The transitions between states are covered in RFC5245. It could be said 
 *      that
 *      it is network-only, as it only takes into account the state of the 
 *      network
 *      connection, ignoring other higher level stuff, like DTLS handshake, RTCP
 *      flow, etc. This implies that, while the component state is
 *      <code>CONNECTED</code>, there might be no media flowing between the 
 *      peers.
 *      This makes this event useful only to receive low-level information about
 *      connection between peers. Even more, while other events might leave a
 *      graceful period of time before firing, this event fires immediately 
 *      after
 *      the state change is detected.
 *    </li>
 *    <li>
 *      <code>IceCandidateFound</code>: Raised when a new candidate is 
 *      discovered.
 *      ICE candidates must be sent to the remote peer of the connection. 
 *      Failing to
 *      do so for some or all of the candidates might render the connection
 *      unusable.
 *    </li>
 *    <li>
 *      <code>IceGatheringDone</code>: Raised when the ICE gathering process is
 *      completed. This means that all candidates have already been discovered.
 *    </li>
 *    <li>
 *      <code>NewCandidatePairSelected</code>: Raised when a new ICE candidate 
 *      pair
 *      gets selected. The pair contains both local and remote candidates being 
 *      used
 *      for a component. This event can be raised during a media session, if a 
 *      new
 *      pair of candidates with higher priority in the link are found.
 *    </li>
 *    <li><code>DataChannelOpened</code>: Raised when a data channel is 
 *    open.</li>
 *    <li><code>DataChannelClosed</code>: Raised when a data channel is 
 *    closed.</li>
 *  </ul>
 *  <p>
 *    Registering to any of above events requires the application to provide a
 *    callback function. Each event provides different information, so it is
 *    recommended to consult the signature of the event listeners.
 *  </p>
 *  <h2>Bitrate management and network congestion control</h2>
 *  <p>
 *    Congestion control is one of the most important features of WebRTC. WebRTC
 *    connections start with the lowest bandwidth configured and slowly ramps up
 *    the maximum available bandwidth, or to the higher limit of the allowed 
 *    range
 *    in case no bandwidth limitation is detected.
 *  </p>
 *  <p>
 *    Notice that WebRtcEndpoints in Kurento are designed in a way that
 *    <strong>
 *      multiple WebRTC connections fed by the same stream, share the same 
 *      bitrate
 *      limits.
 *    </strong>
 *    When a new connection is added, as it requires to start with low 
 *    bandwidth, it
 *    will cause the rest of connections to experience a transient period of
 *    degraded quality, until it stabilizes its bitrate. This doesn't apply when
 *    transcoding is involved; transcoders will adjust their output bitrate 
 *    based in
 *    the receiver requirements, but it won't affect the original stream.
 *  </p>
 *  <p>
 *    If an incoming WebRTC stream needs to be transcoded, for whatever reason, 
 *    all
 *    WebRtcEndpoints fed from the transcoder output will share a separate 
 *    quality
 *    than the ones connected directly to the original stream.
 *  </p>
 *  <p>
 *    <strong>
 *      Note that the default <em>MaxVideoSendBandwidth</em> is a VERY 
 *      conservative
 *      value, and leads to a low maximum video quality. Most applications will
 *      probably want to increase this to higher values such as 2000 kbps (2 
 *      Mbps).
 *    </strong>
 *    Check the documentation of {@link BaseRtpEndpoint} and
 *    :rom:cls:`RembParams` for detailed information about bitrate management.
 *  </p>
 *  <h3>Keyframe requests (PLI/FIR)</h3>
 *  <p>
 *    WebRTC allows receivers to emit keyframe requests for the senders, by 
 *    means of
 *    RTCP Feedback messages called PLI (Picture Loss Indication) and/or FIR 
 *    (Full
 *    Intra-frame Request). Kurento supports this mechanism: PLI and FIR 
 *    requests
 *    that are emitted by a receiver will be forwarded to the sender. This way, 
 *    the
 *    encoder of the video (e.g. a web browser) can decide if a new keyframe 
 *    should
 *    be generated. Sometimes Kurento itself acts as encoder when transcoding is
 *    enabled, so in this case it is Kurento itself the one generating 
 *    keyframes.
 *  </p>
 *  <p>
 *    On top of this, a common technique used for streaming is to forcefully 
 *    request
 *    new keyframes. Either in fixed intervals, or explicitly by the 
 *    application.
 *    Kurento doesn't support the former, but the latter is possible by calling
 *    <code>requestKeyframe()</code> from a subscribing element (i.e. an 
 *    endpoint
 *    that sends data out from the Kurento Pipeline).
 *  </p>
 *  <h2>WebRTC Data Channels</h2>
 *  <p>
 *    DataChannels allow other media elements that make use of the DataPad, to 
 *    send
 *    arbitrary data. For instance, if there is a filter that publishes event
 *    information, it will be sent to the remote peer through the channel. There
 *    no API available for programmers to make use of this feature in the
 *    WebRtcElement. DataChannels can be configured to provide the following:
 *  </p>
 *  <ul>
 *    <li>Reliable or partially reliable delivery of sent messages</li>
 *    <li>In-order or out-of-order delivery of sent messages</li>
 *  </ul>
 *  <p>
 *    Unreliable, out-of-order delivery is equivalent to raw UDP semantics. The
 *    message may make it, or it may not, and order is not important. However, 
 *    the
 *    channel can be configured to be <i>partially reliable</i> by specifying 
 *    the
 *    maximum number of retransmissions or setting a time limit for 
 *    retransmissions:
 *    the WebRTC stack will handle the acknowledgments and timeouts.
 *  </p>
 *  <p>
 *    The possibility to create DataChannels in a WebRtcEndpoint must be 
 *    explicitly
 *    enabled when creating the endpoint, as this feature is disabled by 
 *    default. If
 *    this is the case, they can be created invoking the createDataChannel 
 *    method.
 *    The arguments for this method, all of them optional, provide the necessary
 *    configuration:
 *  </p>
 *  <ul>
 *    <li>
 *      <code>label</code>: assigns a label to the DataChannel. This can help
 *      identify each possible channel separately.
 *    </li>
 *    <li>
 *      <code>ordered</code>: specifies if the DataChannel guarantees order, 
 *      which
 *      is the default mode. If maxPacketLifetime and maxRetransmits have not 
 *      been
 *      set, this enables reliable mode.
 *    </li>
 *    <li>
 *      <code>maxPacketLifeTime</code>: The time window in milliseconds, during
 *      which transmissions and retransmissions may take place in unreliable 
 *      mode.
 *      This forces unreliable mode, even if <code>ordered</code> has been
 *      activated.
 *    </li>
 *    <li>
 *      <code>maxRetransmits</code>: maximum number of retransmissions that are
 *      attempted in unreliable mode. This forces unreliable mode, even if
 *      <code>ordered</code> has been activated.
 *    </li>
 *    <li>
 *      <code>Protocol</code>: Name of the subprotocol used for data 
 *      communication.
 *    </li>
 *  </ul>
 *
 * @extends module:core/abstracts.BaseRtpEndpoint
 *
 * @constructor module:elements.WebRtcEndpoint
 *
 * @fires {@link module:elements#event:DataChannelClosed DataChannelClosed}
 * @fires {@link module:elements#event:DataChannelOpened DataChannelOpened}
 * @fires {@link module:elements#event:IceCandidateFound IceCandidateFound}
 * @fires {@link module:elements#event:IceComponentStateChanged IceComponentStateChanged}
 * @fires {@link module:elements#event:IceGatheringDone IceGatheringDone}
 * @fires {@link module:elements#event:NewCandidatePairSelected NewCandidatePairSelected}
 */
function WebRtcEndpoint(){
  WebRtcEndpoint.super_.call(this);
};
inherits(WebRtcEndpoint, BaseRtpEndpoint);


//
// Public properties
//

/**
 * External IPv4 address of the media server.
 * <p>
 *   Forces all local IPv4 ICE candidates to have the given address. This is 
 *   really
 *   nothing more than a hack, but it's very effective to force a public IP 
 *   address
 *   when one is known in advance for the media server. In doing so, KMS will 
 *   not
 *   need a STUN or TURN server, but remote peers will still be able to contact 
 *   it.
 * </p>
 * <p>
 *   You can try using this setting if KMS is deployed on a publicly accessible
 *   server, without NAT, and with a static public IP address. But if it doesn't
 *   work for you, just go back to configuring a STUN or TURN server for ICE.
 * </p>
 * <p>
 *   Only set this parameter if you know what you're doing, and you understand 
 *   100%
 *   WHY you need it. For the majority of cases, you should just prefer to
 *   configure a STUN or TURN server.
 * </p>
 * <p><code>externalIPv4</code> is a single IPv4 address.</p>
 * <p>Example:</p>
 * <ul>
 *   <li><code>externalIPv4=198.51.100.1</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#getExternalIPv4
 *
 * @param {module:elements.WebRtcEndpoint~getExternalIPv4Callback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getExternalIPv4 = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getExternalIPv4', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getExternalIPv4Callback
 * @param {external:Error} error
 * @param {external:String} result
 */

/**
 * External IPv4 address of the media server.
 * <p>
 *   Forces all local IPv4 ICE candidates to have the given address. This is 
 *   really
 *   nothing more than a hack, but it's very effective to force a public IP 
 *   address
 *   when one is known in advance for the media server. In doing so, KMS will 
 *   not
 *   need a STUN or TURN server, but remote peers will still be able to contact 
 *   it.
 * </p>
 * <p>
 *   You can try using this setting if KMS is deployed on a publicly accessible
 *   server, without NAT, and with a static public IP address. But if it doesn't
 *   work for you, just go back to configuring a STUN or TURN server for ICE.
 * </p>
 * <p>
 *   Only set this parameter if you know what you're doing, and you understand 
 *   100%
 *   WHY you need it. For the majority of cases, you should just prefer to
 *   configure a STUN or TURN server.
 * </p>
 * <p><code>externalIPv4</code> is a single IPv4 address.</p>
 * <p>Example:</p>
 * <ul>
 *   <li><code>externalIPv4=198.51.100.1</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#setExternalIPv4
 *
 * @param {external:String} externalIPv4
 * @param {module:elements.WebRtcEndpoint~setExternalIPv4Callback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setExternalIPv4 = function(externalIPv4, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('String', 'externalIPv4', externalIPv4, {required: true});
  //  

  var params = {
    externalIPv4: externalIPv4
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setExternalIPv4', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setExternalIPv4Callback
 * @param {external:Error} error
 */

/**
 * External IPv6 address of the media server.
 * <p>
 *   Forces all local IPv6 ICE candidates to have the given address. This is 
 *   really
 *   nothing more than a hack, but it's very effective to force a public IP 
 *   address
 *   when one is known in advance for the media server. In doing so, KMS will 
 *   not
 *   need a STUN or TURN server, but remote peers will still be able to contact 
 *   it.
 * </p>
 * <p>
 *   You can try using this setting if KMS is deployed on a publicly accessible
 *   server, without NAT, and with a static public IP address. But if it doesn't
 *   work for you, just go back to configuring a STUN or TURN server for ICE.
 * </p>
 * <p>
 *   Only set this parameter if you know what you're doing, and you understand 
 *   100%
 *   WHY you need it. For the majority of cases, you should just prefer to
 *   configure a STUN or TURN server.
 * </p>
 * <p><code>externalIPv6</code> is a single IPv6 address.</p>
 * <p>Example:</p>
 * <ul>
 *   <li><code>externalIPv6=2001:0db8:85a3:0000:0000:8a2e:0370:7334</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#getExternalIPv6
 *
 * @param {module:elements.WebRtcEndpoint~getExternalIPv6Callback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getExternalIPv6 = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getExternalIPv6', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getExternalIPv6Callback
 * @param {external:Error} error
 * @param {external:String} result
 */

/**
 * External IPv6 address of the media server.
 * <p>
 *   Forces all local IPv6 ICE candidates to have the given address. This is 
 *   really
 *   nothing more than a hack, but it's very effective to force a public IP 
 *   address
 *   when one is known in advance for the media server. In doing so, KMS will 
 *   not
 *   need a STUN or TURN server, but remote peers will still be able to contact 
 *   it.
 * </p>
 * <p>
 *   You can try using this setting if KMS is deployed on a publicly accessible
 *   server, without NAT, and with a static public IP address. But if it doesn't
 *   work for you, just go back to configuring a STUN or TURN server for ICE.
 * </p>
 * <p>
 *   Only set this parameter if you know what you're doing, and you understand 
 *   100%
 *   WHY you need it. For the majority of cases, you should just prefer to
 *   configure a STUN or TURN server.
 * </p>
 * <p><code>externalIPv6</code> is a single IPv6 address.</p>
 * <p>Example:</p>
 * <ul>
 *   <li><code>externalIPv6=2001:0db8:85a3:0000:0000:8a2e:0370:7334</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#setExternalIPv6
 *
 * @param {external:String} externalIPv6
 * @param {module:elements.WebRtcEndpoint~setExternalIPv6Callback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setExternalIPv6 = function(externalIPv6, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('String', 'externalIPv6', externalIPv6, {required: true});
  //  

  var params = {
    externalIPv6: externalIPv6
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setExternalIPv6', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setExternalIPv6Callback
 * @param {external:Error} error
 */

/**
 * the ICE candidate pair (local and remote candidates) used by the ICE library 
 * for each stream.
 *
 * @alias module:elements.WebRtcEndpoint#getICECandidatePairs
 *
 * @param {module:elements.WebRtcEndpoint~getICECandidatePairsCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getICECandidatePairs = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getICECandidatePairs', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getICECandidatePairsCallback
 * @param {external:Error} error
 * @param {module:elements/complexTypes.IceCandidatePair} result
 */

/**
 * the ICE connection state for all the connections.
 *
 * @alias module:elements.WebRtcEndpoint#getIceConnectionState
 *
 * @param {module:elements.WebRtcEndpoint~getIceConnectionStateCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getIceConnectionState = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getIceConnectionState', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getIceConnectionStateCallback
 * @param {external:Error} error
 * @param {module:elements/complexTypes.IceConnection} result
 */

/**
 * Enable ICE-TCP candidate gathering.
 * <p>
 *   This setting enables or disables using TCP for ICE candidate gathering in 
 *   the
 *   underlying libnice library:
 *   https://libnice.freedesktop.org/libnice/NiceAgent.html#NiceAgent--ice-tcp
 * </p>
 * <p>
 *   You might want to disable ICE-TCP to potentially speed up ICE gathering by
 *   avoiding TCP candidates in scenarios where they are not needed.
 * </p>
 * <p><code>iceTcp</code> is either 1 (ON) or 0 (OFF). Default: 1 (ON).</p>
 *
 * @alias module:elements.WebRtcEndpoint#getIceTcp
 *
 * @param {module:elements.WebRtcEndpoint~getIceTcpCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getIceTcp = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getIceTcp', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getIceTcpCallback
 * @param {external:Error} error
 * @param {external:Boolean} result
 */

/**
 * Enable ICE-TCP candidate gathering.
 * <p>
 *   This setting enables or disables using TCP for ICE candidate gathering in 
 *   the
 *   underlying libnice library:
 *   https://libnice.freedesktop.org/libnice/NiceAgent.html#NiceAgent--ice-tcp
 * </p>
 * <p>
 *   You might want to disable ICE-TCP to potentially speed up ICE gathering by
 *   avoiding TCP candidates in scenarios where they are not needed.
 * </p>
 * <p><code>iceTcp</code> is either 1 (ON) or 0 (OFF). Default: 1 (ON).</p>
 *
 * @alias module:elements.WebRtcEndpoint#setIceTcp
 *
 * @param {external:Boolean} iceTcp
 * @param {module:elements.WebRtcEndpoint~setIceTcpCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setIceTcp = function(iceTcp, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('boolean', 'iceTcp', iceTcp, {required: true});
  //  

  var params = {
    iceTcp: iceTcp
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setIceTcp', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setIceTcpCallback
 * @param {external:Error} error
 */

/**
 * Local network interfaces used for ICE gathering.
 * <p>
 *   If you know which network interfaces should be used to perform ICE (for 
 *   WebRTC
 *   connectivity), you can define them here. Doing so has several advantages:
 * </p>
 * <ul>
 *   <li>
 *     The WebRTC ICE gathering process will be much quicker. Normally, it needs
 *     gather local candidates for all of the network interfaces, but this step 
 *     can
 *     be made faster if you limit it to only the interface that you know will
 *     work.
 *   </li>
 *   <li>
 *     It will ensure that the media server always decides to use the correct
 *     network interface. With WebRTC ICE gathering it's possible that, under 
 *     some
 *     circumstances (in systems with virtual network interfaces such as
 *     <code>docker0</code>) the ICE process ends up choosing the wrong local 
 *     IP.
 *   </li>
 * </ul>
 * <p>
 *   <code>networkInterfaces</code> is a comma-separated list of network 
 *   interface
 *   names.
 * </p>
 * <p>Examples:</p>
 * <ul>
 *   <li><code>networkInterfaces=eth0</code></li>
 *   <li><code>networkInterfaces=eth0,enp0s25</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#getNetworkInterfaces
 *
 * @param {module:elements.WebRtcEndpoint~getNetworkInterfacesCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getNetworkInterfaces = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getNetworkInterfaces', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getNetworkInterfacesCallback
 * @param {external:Error} error
 * @param {external:String} result
 */

/**
 * Local network interfaces used for ICE gathering.
 * <p>
 *   If you know which network interfaces should be used to perform ICE (for 
 *   WebRTC
 *   connectivity), you can define them here. Doing so has several advantages:
 * </p>
 * <ul>
 *   <li>
 *     The WebRTC ICE gathering process will be much quicker. Normally, it needs
 *     gather local candidates for all of the network interfaces, but this step 
 *     can
 *     be made faster if you limit it to only the interface that you know will
 *     work.
 *   </li>
 *   <li>
 *     It will ensure that the media server always decides to use the correct
 *     network interface. With WebRTC ICE gathering it's possible that, under 
 *     some
 *     circumstances (in systems with virtual network interfaces such as
 *     <code>docker0</code>) the ICE process ends up choosing the wrong local 
 *     IP.
 *   </li>
 * </ul>
 * <p>
 *   <code>networkInterfaces</code> is a comma-separated list of network 
 *   interface
 *   names.
 * </p>
 * <p>Examples:</p>
 * <ul>
 *   <li><code>networkInterfaces=eth0</code></li>
 *   <li><code>networkInterfaces=eth0,enp0s25</code></li>
 * </ul>
 *
 * @alias module:elements.WebRtcEndpoint#setNetworkInterfaces
 *
 * @param {external:String} networkInterfaces
 * @param {module:elements.WebRtcEndpoint~setNetworkInterfacesCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setNetworkInterfaces = function(networkInterfaces, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('String', 'networkInterfaces', networkInterfaces, {required: true});
  //  

  var params = {
    networkInterfaces: networkInterfaces
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setNetworkInterfaces', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setNetworkInterfacesCallback
 * @param {external:Error} error
 */

/**
 * STUN server IP address.
 * <p>The ICE process uses STUN to punch holes through NAT firewalls.</p>
 * <p>
 *   <code>stunServerAddress</code> MUST be an IP address; domain names are NOT
 *   supported.
 * </p>
 * <p>
 *   You need to use a well-working STUN server. Use this to check if it 
 *   works:<br />
 *   https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/<br
 *   From that check, you should get at least one Server-Reflexive Candidate 
 *   (type
 *   <code>srflx</code>).
 * </p>
 *
 * @alias module:elements.WebRtcEndpoint#getStunServerAddress
 *
 * @param {module:elements.WebRtcEndpoint~getStunServerAddressCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getStunServerAddress = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getStunServerAddress', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getStunServerAddressCallback
 * @param {external:Error} error
 * @param {external:String} result
 */

/**
 * STUN server IP address.
 * <p>The ICE process uses STUN to punch holes through NAT firewalls.</p>
 * <p>
 *   <code>stunServerAddress</code> MUST be an IP address; domain names are NOT
 *   supported.
 * </p>
 * <p>
 *   You need to use a well-working STUN server. Use this to check if it 
 *   works:<br />
 *   https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/<br
 *   From that check, you should get at least one Server-Reflexive Candidate 
 *   (type
 *   <code>srflx</code>).
 * </p>
 *
 * @alias module:elements.WebRtcEndpoint#setStunServerAddress
 *
 * @param {external:String} stunServerAddress
 * @param {module:elements.WebRtcEndpoint~setStunServerAddressCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setStunServerAddress = function(stunServerAddress, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('String', 'stunServerAddress', stunServerAddress, {required: true});
  //  

  var params = {
    stunServerAddress: stunServerAddress
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setStunServerAddress', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setStunServerAddressCallback
 * @param {external:Error} error
 */

/**
 * Port of the STUN server
 *
 * @alias module:elements.WebRtcEndpoint#getStunServerPort
 *
 * @param {module:elements.WebRtcEndpoint~getStunServerPortCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getStunServerPort = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getStunServerPort', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getStunServerPortCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Port of the STUN server
 *
 * @alias module:elements.WebRtcEndpoint#setStunServerPort
 *
 * @param {external:Integer} stunServerPort
 * @param {module:elements.WebRtcEndpoint~setStunServerPortCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setStunServerPort = function(stunServerPort, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('int', 'stunServerPort', stunServerPort, {required: true});
  //  

  var params = {
    stunServerPort: stunServerPort
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setStunServerPort', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setStunServerPortCallback
 * @param {external:Error} error
 */

/**
 * TURN server URL.
 * <p>
 *   When STUN is not enough to open connections through some NAT firewalls, 
 *   using
 *   TURN is the remaining alternative.
 * </p>
 * <p>
 *   Note that TURN is a superset of STUN, so you don't need to configure STUN 
 *   if
 *   you are using TURN.
 * </p>
 * <p>The provided URL should follow one of these formats:</p>
 * <ul>
 *   <li><code>user:password@ipaddress:port</code></li>
 *   <li>
 *     <code>user:password@ipaddress:port?transport=[udp|tcp|tls]</code>
 *   </li>
 * </ul>
 * <p>
 *   <code>ipaddress</code> MUST be an IP address; domain names are NOT 
 *   supported.<br />
 *   <code>transport</code> is OPTIONAL. Possible values: udp, tcp, tls. 
 *   Default: udp.
 * </p>
 * <p>
 *   You need to use a well-working TURN server. Use this to check if it 
 *   works:<br />
 *   https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/<br
 *   From that check, you should get at least one Server-Reflexive Candidate 
 *   (type
 *   <code>srflx</code>) AND one Relay Candidate (type <code>relay</code>).
 * </p>
 *
 * @alias module:elements.WebRtcEndpoint#getTurnUrl
 *
 * @param {module:elements.WebRtcEndpoint~getTurnUrlCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.getTurnUrl = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'getTurnUrl', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~getTurnUrlCallback
 * @param {external:Error} error
 * @param {external:String} result
 */

/**
 * TURN server URL.
 * <p>
 *   When STUN is not enough to open connections through some NAT firewalls, 
 *   using
 *   TURN is the remaining alternative.
 * </p>
 * <p>
 *   Note that TURN is a superset of STUN, so you don't need to configure STUN 
 *   if
 *   you are using TURN.
 * </p>
 * <p>The provided URL should follow one of these formats:</p>
 * <ul>
 *   <li><code>user:password@ipaddress:port</code></li>
 *   <li>
 *     <code>user:password@ipaddress:port?transport=[udp|tcp|tls]</code>
 *   </li>
 * </ul>
 * <p>
 *   <code>ipaddress</code> MUST be an IP address; domain names are NOT 
 *   supported.<br />
 *   <code>transport</code> is OPTIONAL. Possible values: udp, tcp, tls. 
 *   Default: udp.
 * </p>
 * <p>
 *   You need to use a well-working TURN server. Use this to check if it 
 *   works:<br />
 *   https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/<br
 *   From that check, you should get at least one Server-Reflexive Candidate 
 *   (type
 *   <code>srflx</code>) AND one Relay Candidate (type <code>relay</code>).
 * </p>
 *
 * @alias module:elements.WebRtcEndpoint#setTurnUrl
 *
 * @param {external:String} turnUrl
 * @param {module:elements.WebRtcEndpoint~setTurnUrlCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.setTurnUrl = function(turnUrl, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('String', 'turnUrl', turnUrl, {required: true});
  //  

  var params = {
    turnUrl: turnUrl
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'setTurnUrl', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~setTurnUrlCallback
 * @param {external:Error} error
 */


//
// Public methods
//

/**
 * Process an ICE candidate sent by the remote peer of the connection.
 *
 * @alias module:elements.WebRtcEndpoint.addIceCandidate
 *
 * @param {module:elements/complexTypes.IceCandidate} candidate
 *  Remote ICE candidate
 *
 * @param {module:elements.WebRtcEndpoint~addIceCandidateCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.addIceCandidate = function(candidate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('IceCandidate', 'candidate', candidate, {required: true});
  //  

  var params = {
    candidate: candidate
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'addIceCandidate', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~addIceCandidateCallback
 * @param {external:Error} error
 */

/**
 * Closes an open data channel
 *
 * @alias module:elements.WebRtcEndpoint.closeDataChannel
 *
 * @param {external:Integer} channelId
 *  The channel identifier
 *
 * @param {module:elements.WebRtcEndpoint~closeDataChannelCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.closeDataChannel = function(channelId, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('int', 'channelId', channelId, {required: true});
  //  

  var params = {
    channelId: channelId
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'closeDataChannel', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~closeDataChannelCallback
 * @param {external:Error} error
 */

/**
 * Create a new data channel, if data channels are supported.
 * <p>
 *   Being supported means that the WebRtcEndpoint has been created with data
 *   channel support, the client also supports data channels, and they have been
 *   negotiated in the SDP exchange. Otherwise, the method throws an exception,
 *   indicating that the operation is not possible.
 * </p>
 * <p>
 *   Data channels can work in either unreliable mode (analogous to User 
 *   Datagram
 *   Protocol or UDP) or reliable mode (analogous to Transmission Control 
 *   Protocol
 *   or TCP). The two modes have a simple distinction:
 * </p>
 * <ul>
 *   <li>
 *     Reliable mode guarantees the transmission of messages and also the order 
 *     in
 *     which they are delivered. This takes extra overhead, thus potentially 
 *     making
 *     this mode slower.
 *   </li>
 *   <li>
 *     Unreliable mode does not guarantee every message will get to the other 
 *     side
 *     nor what order they get there. This removes the overhead, allowing this 
 *     mode
 *     to work much faster.
 *   </li>
 * </ul>
 * <p>If data channels are not supported, this method throws an exception.</p>
 *
 * @alias module:elements.WebRtcEndpoint.createDataChannel
 *
 * @param {external:String} [label]
 *  Channel's label
 *
 * @param {external:Boolean} [ordered]
 *  If the data channel should guarantee order or not. If true, and 
 *  maxPacketLifeTime and maxRetransmits have not been provided, reliable mode 
 *  is activated.
 *
 * @param {external:Integer} [maxPacketLifeTime]
 *  The time window (in milliseconds) during which transmissions and 
 *  retransmissions may take place in unreliable mode.
 *  Note that this forces unreliable mode, even if <code>ordered</code> has been
 *
 * @param {external:Integer} [maxRetransmits]
 *  maximum number of retransmissions that are attempted in unreliable mode.
 *  Note that this forces unreliable mode, even if <code>ordered</code> has been
 *
 * @param {external:String} [protocol]
 *  Name of the subprotocol used for data communication
 *
 * @param {module:elements.WebRtcEndpoint~createDataChannelCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.createDataChannel = function(label, ordered, maxPacketLifeTime, maxRetransmits, protocol, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  callback = arguments[arguments.length-1] instanceof Function
           ? Array.prototype.pop.call(arguments)
           : undefined;

  switch(arguments.length){
    case 0: label = undefined;
    case 1: ordered = undefined;
    case 2: maxPacketLifeTime = undefined;
    case 3: maxRetransmits = undefined;
    case 4: protocol = undefined;
    break;
    case 5: 
    break;

    default:
      var error = new RangeError('Number of params ('+arguments.length+') not in range [0-5]');
          error.length = arguments.length;
          error.min = 0;
          error.max = 5;

      throw error;
  }

  //  
  // checkType('String', 'label', label);
  //  
  // checkType('boolean', 'ordered', ordered);
  //  
  // checkType('int', 'maxPacketLifeTime', maxPacketLifeTime);
  //  
  // checkType('int', 'maxRetransmits', maxRetransmits);
  //  
  // checkType('String', 'protocol', protocol);
  //  

  var params = {
    label: label,
    ordered: ordered,
    maxPacketLifeTime: maxPacketLifeTime,
    maxRetransmits: maxRetransmits,
    protocol: protocol
  };

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'createDataChannel', params, callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~createDataChannelCallback
 * @param {external:Error} error
 */

/**
 * Start the ICE candidate gathering.
 * <p>
 *   This method triggers the asynchronous discovery of ICE candidates (as per 
 *   the
 *   Trickle ICE mechanism), and returns immediately. Every newly trickled
 *   candidate is reported to the application by means of an
 *   <code>IceCandidateFound</code> event. Finally, when all candidates have 
 *   been
 *   gathered, the <code>IceGatheringDone</code> event is emitted.
 * </p>
 * <p>
 *   Normally, you would call this method as soon as possible after calling
 *   <code>SdpEndpoint::generateOffer</code> or
 *   <code>SdpEndpoint::processOffer</code>, to quickly start discovering
 *   candidates and sending them to the remote peer.
 * </p>
 * <p>
 *   You can also call this method <em>before</em> calling
 *   <code>generateOffer</code> or <code>processOffer</code>. Doing so will 
 *   include
 *   any already gathered candidates into the resulting SDP. You can leverage 
 *   this
 *   behavior to implement fully traditional ICE (without Trickle): first call
 *   <code>gatherCandidates</code>, then only handle the SDP messages after the
 *   <code>IceGatheringDone</code> event has been received. This way, you're 
 *   making
 *   sure that all candidates have indeed been gathered, so the resulting SDP 
 *   will
 *   include all of them.
 * </p>
 *
 * @alias module:elements.WebRtcEndpoint.gatherCandidates
 *
 * @param {module:elements.WebRtcEndpoint~gatherCandidatesCallback} [callback]
 *
 * @return {external:Promise}
 */
WebRtcEndpoint.prototype.gatherCandidates = function(callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  var usePromise = false;
  
  if (callback == undefined) {
    usePromise = true;
  }
  
  if(!arguments.length) callback = undefined;

  callback = (callback || noop).bind(this)

  return disguise(this._invoke(transaction, 'gatherCandidates', callback), this)
};
/**
 * @callback module:elements.WebRtcEndpoint~gatherCandidatesCallback
 * @param {external:Error} error
 */


/**
 * @alias module:elements.WebRtcEndpoint.constructorParams
 *
 * @property {module:elements/complexTypes.CertificateKeyType} [certificateKeyType]
 *  Define the type of the certificate used in dtls
 *
 * @property {module:core.MediaPipeline} mediaPipeline
 *  the {@link MediaPipeline} to which the endpoint belongs
 *
 * @property {module:elements/complexTypes.DSCPValue} [qosDscp]
 *  DSCP value to be used in network traffic sent from this endpoint
 *                <p>
 *                If this parameter is present with a value different to 
 *                NO_VALUE, all traffic sent from this WebRTCEndpoint will be 
 *                marked with the correspondent
 *                DSCP value according to the DiffServ architecture. This may 
 *                provide better handling of network traffic according to its 
 *                characteristics associated to
 *                its DSCP value. This better handling includes priority in 
 *                forwarding traffic and probability of packet drop in case of 
 *                network congestion.
 *                <p>
 *                It must be taken into account that on Internet not all 
 *                intermediate routers are guaranteed to enforce those DSCP 
 *                values, even it is possible that
 *                certain routers just block traffic marked with specific DSCP 
 *                values, as discussed here 
 *                https://datatracker.ietf.org/doc/html/rfc8835#section-4.2.
 *                <p>
 *                So, this feature must be managed with care and is mostly 
 *                intended for private networks, where the network proprietor 
 *                can configure and guarantee
 *                DSCP management in all routers.
 *
 * @property {external:Boolean} [recvonly]
 *  Single direction, receive-only endpoint
 *
 * @property {external:Boolean} [sendonly]
 *  Single direction, send-only endpoint
 *
 * @property {external:Boolean} [useDataChannels]
 *  Activate data channels support
 */
WebRtcEndpoint.constructorParams = {
  certificateKeyType: {
    type: 'kurento.CertificateKeyType'  },
  mediaPipeline: {
    type: 'kurento.MediaPipeline',
    required: true
  },
  qosDscp: {
    type: 'kurento.DSCPValue'  },
  recvonly: {
    type: 'boolean'  },
  sendonly: {
    type: 'boolean'  },
  useDataChannels: {
    type: 'boolean'  }
};

/**
 * @alias module:elements.WebRtcEndpoint.events
 *
 * @extends module:core/abstracts.BaseRtpEndpoint.events
 */
WebRtcEndpoint.events = BaseRtpEndpoint.events.concat(['DataChannelClosed', 'DataChannelOpened', 'IceCandidateFound', 'IceComponentStateChanged', 'IceGatheringDone', 'NewCandidatePairSelected']);


/**
 * Checker for {@link module:elements.WebRtcEndpoint}
 *
 * @memberof module:elements
 *
 * @param {external:String} key
 * @param {module:elements.WebRtcEndpoint} value
 */
function checkWebRtcEndpoint(key, value)
{
  if(!(value instanceof WebRtcEndpoint))
    throw ChecktypeError(key, WebRtcEndpoint, value);
};


module.exports = WebRtcEndpoint;

WebRtcEndpoint.check = checkWebRtcEndpoint;