Source: node_modules/kurento-client-core/lib/abstracts/MediaElement.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 checkArray = checkType.checkArray;

var Transaction = kurentoClient.TransactionsManager.Transaction;

var each = require('async').each

var promiseCallback = require('promisecallback');

var MediaObject = require('./MediaObject');


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

  return result
};


/**
 * @classdesc
 *  The basic building block of the media server, that can be interconnected 
 *  inside a pipeline.
 *  <p>
 *    A {@link MediaElement} is a module that encapsulates a specific media
 *    capability, and that is able to exchange media with other MediaElements
 *    through an internal element called <b>pad</b>.
 *  </p>
 *  <p>
 *    A pad can be defined as an input or output interface. Input pads are 
 *    called
 *    sinks, and it's where the media elements receive media from other media
 *    elements. Output interfaces are called sources, and it's the pad used by 
 *    the
 *    media element to feed media to other media elements. There can be only one
 *    sink pad per media element. On the other hand, the number of source pads 
 *    is
 *    unconstrained. This means that a certain media element can receive media 
 *    only
 *    from one element at a time, while it can send media to many others. Pads 
 *    are
 *    created on demand, when the connect method is invoked. When two media 
 *    elements
 *    are connected, one media pad is created for each type of media connected. 
 *    For
 *    example, if you connect AUDIO and VIDEO between two media elements, each 
 *    one
 *    will need to create two new pads: one for AUDIO and one for VIDEO.
 *  </p>
 *  <p>
 *    When media elements are connected, it can be the case that the encoding
 *    required in both input and output pads is not the same, and thus it needs 
 *    to
 *    be transcoded. This is something that is handled transparently by the
 *    MediaElement internals, but such transcoding has a toll in the form of a
 *    higher CPU load, so connecting MediaElements that need media encoded in
 *    different formats is something to consider as a high load operation. The 
 *    event
 *    `MediaTranscodingStateChanged` allows to inform the client application of
 *    whether media transcoding is being enabled or not inside any MediaElement
 *    object.
 *  </p>
 *
 * @abstract
 * @extends module:core/abstracts.MediaObject
 *
 * @constructor module:core/abstracts.MediaElement
 *
 * @fires {@link module:core#event:ElementConnected ElementConnected}
 * @fires {@link module:core#event:ElementDisconnected ElementDisconnected}
 * @fires {@link module:core#event:MediaFlowInStateChange MediaFlowInStateChange}
 * @fires {@link module:core#event:MediaFlowInStateChanged MediaFlowInStateChanged}
 * @fires {@link module:core#event:MediaFlowOutStateChange MediaFlowOutStateChange}
 * @fires {@link module:core#event:MediaFlowOutStateChanged MediaFlowOutStateChanged}
 * @fires {@link module:core#event:MediaTranscodingStateChange MediaTranscodingStateChange}
 * @fires {@link module:core#event:MediaTranscodingStateChanged MediaTranscodingStateChanged}
 */
function MediaElement(){
  MediaElement.super_.call(this);
};
inherits(MediaElement, MediaObject);


//
// Public properties
//

/**
 * Target video bitrate for media transcoding.
 * <p>
 *   The bitrate of a video has a direct impact on its perceived image quality.
 *   Higher bitrate means higher quality, but also a larger amount of bytes to
 *   transmit or store. Use this parameter to set the desired average bitrate in
 *   videos that are transcoded by the media server.
 * </p>
 * <p>
 *   This parameter is most useful for :rom:cls:`RecorderEndpoint` and
 *   :rom:cls:`RtpEndpoint`: when media is being transcoded (either for 
 *   streaming
 *   or storing on disk), the resulting quality is directly controlled with this
 *   value.
 * </p>
 * <p>
 *   For :rom:cls:`WebRtcEndpoint`, this value should be left as default, as 
 *   remote
 *   WebRTC receivers will already send feedback to inform the media server 
 *   about
 *   what is the optimal bitrate to send.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 300000 (300 kbps).</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#getEncoderBitrate
 *
 * @param {module:core/abstracts.MediaElement~getEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getEncoderBitrate = 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, 'getEncoderBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getEncoderBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Target video bitrate for media transcoding.
 * <p>
 *   The bitrate of a video has a direct impact on its perceived image quality.
 *   Higher bitrate means higher quality, but also a larger amount of bytes to
 *   transmit or store. Use this parameter to set the desired average bitrate in
 *   videos that are transcoded by the media server.
 * </p>
 * <p>
 *   This parameter is most useful for :rom:cls:`RecorderEndpoint` and
 *   :rom:cls:`RtpEndpoint`: when media is being transcoded (either for 
 *   streaming
 *   or storing on disk), the resulting quality is directly controlled with this
 *   value.
 * </p>
 * <p>
 *   For :rom:cls:`WebRtcEndpoint`, this value should be left as default, as 
 *   remote
 *   WebRTC receivers will already send feedback to inform the media server 
 *   about
 *   what is the optimal bitrate to send.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 300000 (300 kbps).</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#setEncoderBitrate
 *
 * @param {external:Integer} encoderBitrate
 * @param {module:core/abstracts.MediaElement~setEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setEncoderBitrate = function(encoderBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    encoderBitrate: encoderBitrate
  };

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

  return disguise(this._invoke(transaction, 'setEncoderBitrate', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setEncoderBitrateCallback
 * @param {external:Error} error
 */

/**
 * Maximum video bitrate for media transcoding.
 * <p>
 *   This parameter can be used to fine tune the automatic bitrate selection 
 *   that
 *   normally takes place within elements that are able to dynamically change 
 *   the
 *   encoding bitrate according to the conditions of the streaming, such as
 *   :rom:cls:`WebRtcEndpoint`.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to limit the total bitrate that is handled by the server, by setting a low
 *   maximum output for all endpoints.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to limit the total bitrate that is handled by the server, by setting a low
 *   maximum output for all endpoints.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 *   <li>
 *     0 = unlimited. Encoding performed with bitrate as requested by receivers.
 *   </li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#getMaxEncoderBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMaxEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMaxEncoderBitrate = 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, 'getMaxEncoderBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMaxEncoderBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Maximum video bitrate for media transcoding.
 * <p>
 *   This parameter can be used to fine tune the automatic bitrate selection 
 *   that
 *   normally takes place within elements that are able to dynamically change 
 *   the
 *   encoding bitrate according to the conditions of the streaming, such as
 *   :rom:cls:`WebRtcEndpoint`.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to limit the total bitrate that is handled by the server, by setting a low
 *   maximum output for all endpoints.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to limit the total bitrate that is handled by the server, by setting a low
 *   maximum output for all endpoints.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 *   <li>
 *     0 = unlimited. Encoding performed with bitrate as requested by receivers.
 *   </li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#setMaxEncoderBitrate
 *
 * @param {external:Integer} maxEncoderBitrate
 * @param {module:core/abstracts.MediaElement~setMaxEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMaxEncoderBitrate = function(maxEncoderBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    maxEncoderBitrate: maxEncoderBitrate
  };

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

  return disguise(this._invoke(transaction, 'setMaxEncoderBitrate', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setMaxEncoderBitrateCallback
 * @param {external:Error} error
 */

/**
 * Minimum video bitrate for media transcoding.
 * <p>
 *   This parameter can be used to fine tune the automatic bitrate selection 
 *   that
 *   normally takes place within elements that are able to dynamically change 
 *   the
 *   encoding bitrate according to the conditions of the streaming, such as
 *   :rom:cls:`WebRtcEndpoint`.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to force a higher bitrate than what is being requested by receivers.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#getMinEncoderBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMinEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMinEncoderBitrate = 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, 'getMinEncoderBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMinEncoderBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Minimum video bitrate for media transcoding.
 * <p>
 *   This parameter can be used to fine tune the automatic bitrate selection 
 *   that
 *   normally takes place within elements that are able to dynamically change 
 *   the
 *   encoding bitrate according to the conditions of the streaming, such as
 *   :rom:cls:`WebRtcEndpoint`.
 * </p>
 * <p>
 *   This should be left as default in most cases, given that remote WebRTC
 *   receivers already send feedback to inform the media server about what is 
 *   the
 *   optimal bitrate to send. Otherwise, this parameter could be used for 
 *   example
 *   to force a higher bitrate than what is being requested by receivers.
 * </p>
 * <p>
 *   Setting a value will only work if done before the media starts to flow.
 * </p>
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#setMinEncoderBitrate
 *
 * @param {external:Integer} minEncoderBitrate
 * @param {module:core/abstracts.MediaElement~setMinEncoderBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMinEncoderBitrate = function(minEncoderBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    minEncoderBitrate: minEncoderBitrate
  };

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

  return disguise(this._invoke(transaction, 'setMinEncoderBitrate', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setMinEncoderBitrateCallback
 * @param {external:Error} error
 */


//
// Public methods
//

/**
 * Connects two elements, with the media flowing from left to right.
 * <p>
 *   The element that invokes the connect will be the source of media, creating 
 *   one
 *   sink pad for each type of media connected. The element given as parameter 
 *   to
 *   the method will be the sink, and it will create one sink pad per media type
 *   connected.
 * </p>
 * <p>
 *   If otherwise not specified, all types of media are connected by default
 *   (AUDIO, VIDEO and DATA). It is recommended to connect the specific types of
 *   media if not all of them will be used. For this purpose, the connect method
 *   can be invoked more than once on the same two elements, but with different
 *   media types.
 * </p>
 * <p>
 *   The connection is unidirectional. If a bidirectional connection is desired,
 *   the position of the media elements must be inverted. For instance,
 *   webrtc1.connect(webrtc2) is connecting webrtc1 as source of webrtc2. In 
 *   order
 *   to create a WebRTC one-2one conversation, the user would need to specify 
 *   the
 *   connection on the other direction with webrtc2.connect(webrtc1).
 * </p>
 * <p>
 *   Even though one media element can have one sink pad per type of media, only
 *   one media element can be connected to another at a given time. If a media
 *   element is connected to another, the former will become the source of the 
 *   sink
 *   media element, regardless whether there was another element connected or 
 *   not.
 * </p>
 *
 * @alias module:core/abstracts.MediaElement.connect
 *
 * @param {module:core/abstracts.MediaElement} sink
 *  the target {@link MediaElement} that will receive media
 *
 * @param {module:core/complexTypes.MediaType} [mediaType]
 *  the {@link MediaType} of the pads that will be connected
 *
 * @param {external:String} [sourceMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {external:String} [sinkMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {module:core/abstracts.MediaElement~connectCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.connect = function(sink, mediaType, sourceMediaDescription, sinkMediaDescription, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

    var media = sink
    var src = this;
    sink = media[media.length-1]

    // Check if we have enought media components
    if(!media.length)
      throw new SyntaxError('Need at least one media element to connect');

    // Check MediaElements are of the correct type
    checkArray('MediaElement', 'media', media)

    // Generate promise
    promise = new Promise(function(resolve, reject)
    {
      function callback(error, result)
      {
        if(error) return reject(error);

        resolve(result);
      };

      each(media, function(sink, callback)
      {
        src = src.connect(sink, callback);
      },
      callback);
    });

    promise = promiseCallback(promise, callback)
  }
  else
  {
  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 1: mediaType = undefined;
    case 2: sourceMediaDescription = undefined;
    case 3: sinkMediaDescription = undefined;
    break;
    case 4: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaElement', 'sink', sink, {required: true});
  //  
  // checkType('MediaType', 'mediaType', mediaType);
  //  
  // checkType('String', 'sourceMediaDescription', sourceMediaDescription);
  //  
  // checkType('String', 'sinkMediaDescription', sinkMediaDescription);
  //  

  var params = {
    sink: sink,
    mediaType: mediaType,
    sourceMediaDescription: sourceMediaDescription,
    sinkMediaDescription: sinkMediaDescription
  };

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

    promise = this._invoke(transaction, 'connect', params, callback)
  }

  return disguise(promise, sink)
};
/**
 * @callback module:core/abstracts.MediaElement~connectCallback
 * @param {external:Error} error
 */

/**
 * Disconnects two media elements. This will release the source pads of the 
 * source media element, and the sink pads of the sink media element.
 *
 * @alias module:core/abstracts.MediaElement.disconnect
 *
 * @param {module:core/abstracts.MediaElement} sink
 *  the target {@link MediaElement} that will stop receiving media
 *
 * @param {module:core/complexTypes.MediaType} [mediaType]
 *  the {@link MediaType} of the pads that will be connected
 *
 * @param {external:String} [sourceMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {external:String} [sinkMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {module:core/abstracts.MediaElement~disconnectCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.disconnect = function(sink, mediaType, sourceMediaDescription, sinkMediaDescription, 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 1: mediaType = undefined;
    case 2: sourceMediaDescription = undefined;
    case 3: sinkMediaDescription = undefined;
    break;
    case 4: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaElement', 'sink', sink, {required: true});
  //  
  // checkType('MediaType', 'mediaType', mediaType);
  //  
  // checkType('String', 'sourceMediaDescription', sourceMediaDescription);
  //  
  // checkType('String', 'sinkMediaDescription', sinkMediaDescription);
  //  

  var params = {
    sink: sink,
    mediaType: mediaType,
    sourceMediaDescription: sourceMediaDescription,
    sinkMediaDescription: sinkMediaDescription
  };

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

  return disguise(this._invoke(transaction, 'disconnect', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~disconnectCallback
 * @param {external:Error} error
 */

/**
 * Return a .dot file describing the topology of the media element.
 * <p>The element can be queried for certain type of data:</p>
 * <ul>
 *   <li>SHOW_ALL: default value</li>
 *   <li>SHOW_CAPS_DETAILS</li>
 *   <li>SHOW_FULL_PARAMS</li>
 *   <li>SHOW_MEDIA_TYPE</li>
 *   <li>SHOW_NON_DEFAULT_PARAMS</li>
 *   <li>SHOW_STATES</li>
 *   <li>SHOW_VERBOSE</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement.getGstreamerDot
 *
 * @param {module:core/complexTypes.GstreamerDotDetails} [details]
 *  Details of graph
 *
 * @param {module:core/abstracts.MediaElement~getGstreamerDotCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getGstreamerDot = function(details, 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: details = undefined;
    break;
    case 1: 
    break;

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

      throw error;
  }

  //  
  // checkType('GstreamerDotDetails', 'details', details);
  //  

  var params = {
    details: details
  };

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

  return disguise(this._invoke(transaction, 'getGstreamerDot', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getGstreamerDotCallback
 * @param {external:Error} error
 * @param {external:String} result
 *  The dot graph.
 */

/**
 * Gets information about the source pads of this media element.
 * <p>
 *   Since source pads connect to other media element's sinks, this is formally 
 *   the
 *   sink of media from the element's perspective. Media can be filtered by 
 *   type,
 *   or by the description given to the pad though which both elements are
 *   connected.
 * </p>
 *
 * @alias module:core/abstracts.MediaElement.getSinkConnections
 *
 * @param {module:core/complexTypes.MediaType} [mediaType]
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO}, {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO} or {@link 
 *  core/abstracts.MediaElementMediaType#DATA}
 *
 * @param {external:String} [description]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {module:core/abstracts.MediaElement~getSinkConnectionsCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getSinkConnections = function(mediaType, description, 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: mediaType = undefined;
    case 1: description = undefined;
    break;
    case 2: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType);
  //  
  // checkType('String', 'description', description);
  //  

  var params = {
    mediaType: mediaType,
    description: description
  };

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

  return disguise(this._invoke(transaction, 'getSinkConnections', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getSinkConnectionsCallback
 * @param {external:Error} error
 * @param {module:core/complexTypes.ElementConnectionData} result
 *  A list of the connections information that are receiving media from this 
 *  element. The list will be empty if no sources are found.
 */

/**
 * Gets information about the sink pads of this media element.
 * <p>
 *   Since sink pads are the interface through which a media element gets it's
 *   media, whatever is connected to an element's sink pad is formally a source 
 *   of
 *   media. Media can be filtered by type, or by the description given to the 
 *   pad
 *   though which both elements are connected.
 * </p>
 *
 * @alias module:core/abstracts.MediaElement.getSourceConnections
 *
 * @param {module:core/complexTypes.MediaType} [mediaType]
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO}, {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO} or {@link 
 *  core/abstracts.MediaElementMediaType#DATA}
 *
 * @param {external:String} [description]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link core/abstracts.MediaElementMediaType#DATA} sources
 *
 * @param {module:core/abstracts.MediaElement~getSourceConnectionsCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getSourceConnections = function(mediaType, description, 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: mediaType = undefined;
    case 1: description = undefined;
    break;
    case 2: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType);
  //  
  // checkType('String', 'description', description);
  //  

  var params = {
    mediaType: mediaType,
    description: description
  };

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

  return disguise(this._invoke(transaction, 'getSourceConnections', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getSourceConnectionsCallback
 * @param {external:Error} error
 * @param {module:core/complexTypes.ElementConnectionData} result
 *  A list of the connections information that are sending media to this 
 *  element. The list will be empty if no sources are found.
 */

/**
 * Gets the statistics related to an endpoint. If no media type is specified, it
 *
 * @alias module:core/abstracts.MediaElement.getStats
 *
 * @param {module:core/complexTypes.MediaType} [mediaType]
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO} or {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO}
 *
 * @param {module:core/abstracts.MediaElement~getStatsCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getStats = function(mediaType, 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: mediaType = undefined;
    break;
    case 1: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType);
  //  

  var params = {
    mediaType: mediaType
  };

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

  return disguise(this._invoke(transaction, 'getStats', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getStatsCallback
 * @param {external:Error} error
 * @param {Object.<string, module:core/complexTypes.Stats>} result
 *  Delivers a successful result in the form of a RTC stats report. A RTC stats 
 *  report represents a map between strings, identifying the inspected objects 
 *  (RTCStats.id), and their corresponding RTCStats objects.
 */

/**
 * This method indicates whether the media element is receiving media of a 
 * certain type. The media sink pad can be identified individually, if needed. 
 * It is only supported for AUDIO and VIDEO types, raising a 
 * MEDIA_OBJECT_ILLEGAL_PARAM_ERROR otherwise. If the pad indicated does not 
 * exist, if will return false.
 *
 * @alias module:core/abstracts.MediaElement.isMediaFlowingIn
 *
 * @param {module:core/complexTypes.MediaType} mediaType
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO} or {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO}
 *
 * @param {external:String} [sinkMediaDescription]
 *  Description of the sink
 *
 * @param {module:core/abstracts.MediaElement~isMediaFlowingInCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.isMediaFlowingIn = function(mediaType, sinkMediaDescription, 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 1: sinkMediaDescription = undefined;
    break;
    case 2: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType, {required: true});
  //  
  // checkType('String', 'sinkMediaDescription', sinkMediaDescription);
  //  

  var params = {
    mediaType: mediaType,
    sinkMediaDescription: sinkMediaDescription
  };

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

  return disguise(this._invoke(transaction, 'isMediaFlowingIn', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~isMediaFlowingInCallback
 * @param {external:Error} error
 * @param {external:Boolean} result
 *  TRUE if there is media, FALSE in other case.
 */

/**
 * This method indicates whether the media element is emitting media of a 
 * certain type. The media source pad can be identified individually, if needed.
 *
 * @alias module:core/abstracts.MediaElement.isMediaFlowingOut
 *
 * @param {module:core/complexTypes.MediaType} mediaType
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO} or {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO}
 *
 * @param {external:String} [sourceMediaDescription]
 *  Description of the source
 *
 * @param {module:core/abstracts.MediaElement~isMediaFlowingOutCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.isMediaFlowingOut = function(mediaType, sourceMediaDescription, 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 1: sourceMediaDescription = undefined;
    break;
    case 2: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType, {required: true});
  //  
  // checkType('String', 'sourceMediaDescription', sourceMediaDescription);
  //  

  var params = {
    mediaType: mediaType,
    sourceMediaDescription: sourceMediaDescription
  };

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

  return disguise(this._invoke(transaction, 'isMediaFlowingOut', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~isMediaFlowingOutCallback
 * @param {external:Error} error
 * @param {external:Boolean} result
 *  TRUE if there is media, FALSE in other case.
 */

/**
 * Indicates whether this media element is actively transcoding between input 
 * and output pads. This operation is only supported for AUDIO and VIDEO media 
 * types, raising a MEDIA_OBJECT_ILLEGAL_PARAM_ERROR otherwise.
 *           The internal GStreamer processing bin can be indicated, if needed; 
 *           if the bin doesn't exist, the return value will be FALSE.
 *
 * @alias module:core/abstracts.MediaElement.isMediaTranscoding
 *
 * @param {module:core/complexTypes.MediaType} mediaType
 *  One of {@link core/abstracts.MediaElementMediaType#AUDIO} or {@link 
 *  core/abstracts.MediaElementMediaType#VIDEO}
 *
 * @param {external:String} [binName]
 *  Internal name of the processing bin, as previously given by 
 *  <code>MediaTranscodingStateChanged</code>.
 *
 * @param {module:core/abstracts.MediaElement~isMediaTranscodingCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.isMediaTranscoding = function(mediaType, binName, 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 1: binName = undefined;
    break;
    case 2: 
    break;

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

      throw error;
  }

  //  
  // checkType('MediaType', 'mediaType', mediaType, {required: true});
  //  
  // checkType('String', 'binName', binName);
  //  

  var params = {
    mediaType: mediaType,
    binName: binName
  };

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

  return disguise(this._invoke(transaction, 'isMediaTranscoding', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~isMediaTranscodingCallback
 * @param {external:Error} error
 * @param {external:Boolean} result
 *  TRUE if media is being transcoded, FALSE otherwise.
 */

/**
 * Set the type of data for the audio stream.
 * <p>
 *   MediaElements that do not support configuration of audio capabilities will
 *   throw a MEDIA_OBJECT_ILLEGAL_PARAM_ERROR exception.
 * </p>
 * <p>
 *   NOTE: This method is not implemented yet by the Media Server to do anything
 *   useful.
 * </p>
 *
 * @alias module:core/abstracts.MediaElement.setAudioFormat
 *
 * @param {module:core/complexTypes.AudioCaps} caps
 *  The format for the stream of audio
 *
 * @param {module:core/abstracts.MediaElement~setAudioFormatCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setAudioFormat = function(caps, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('AudioCaps', 'caps', caps, {required: true});
  //  

  var params = {
    caps: caps
  };

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

  return disguise(this._invoke(transaction, 'setAudioFormat', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setAudioFormatCallback
 * @param {external:Error} error
 */

/**
 * Set the type of data for the video stream.
 * <p>
 *   MediaElements that do not support configuration of video capabilities will
 *   throw a MEDIA_OBJECT_ILLEGAL_PARAM_ERROR exception
 * </p>
 * <p>
 *   NOTE: This method is not implemented yet by the Media Server to do anything
 *   useful.
 * </p>
 *
 * @alias module:core/abstracts.MediaElement.setVideoFormat
 *
 * @param {module:core/complexTypes.VideoCaps} caps
 *  The format for the stream of video
 *
 * @param {module:core/abstracts.MediaElement~setVideoFormatCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setVideoFormat = function(caps, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

  //  
  // checkType('VideoCaps', 'caps', caps, {required: true});
  //  

  var params = {
    caps: caps
  };

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

  return disguise(this._invoke(transaction, 'setVideoFormat', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setVideoFormatCallback
 * @param {external:Error} error
 */


/**
 * @alias module:core/abstracts.MediaElement.constructorParams
 */
MediaElement.constructorParams = {
};

/**
 * @alias module:core/abstracts.MediaElement.events
 *
 * @extends module:core/abstracts.MediaObject.events
 */
MediaElement.events = MediaObject.events.concat(['ElementConnected', 'ElementDisconnected', 'MediaFlowInStateChange', 'MediaFlowInStateChanged', 'MediaFlowOutStateChange', 'MediaFlowOutStateChanged', 'MediaTranscodingStateChange', 'MediaTranscodingStateChanged']);


/**
 * Checker for {@link module:core/abstracts.MediaElement}
 *
 * @memberof module:core/abstracts
 *
 * @param {external:String} key
 * @param {module:core/abstracts.MediaElement} value
 */
function checkMediaElement(key, value)
{
  if(!(value instanceof MediaElement))
    throw ChecktypeError(key, MediaElement, value);
};


module.exports = MediaElement;

MediaElement.check = checkMediaElement;