Source: node_modules/kurento-client-core/lib/abstracts/MediaElement.js

/* Autogenerated with Kurento Idl */

/*
 * (C) Copyright 2013-2015 Kurento (http://kurento.org/)
 *
 * 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 module:core/abstracts.MediaElement MediaElement} is a module that
 *    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
 *    `MediaTranscodingStateChange` 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:MediaFlowOutStateChange MediaFlowOutStateChange}
 * @fires {@link module:core#event:MediaTranscodingStateChange MediaTranscodingStateChange}
 */
function MediaElement(){
  MediaElement.super_.call(this);
};
inherits(MediaElement, MediaObject);


//
// Public properties
//

/**
 * Maximum video bandwidth for transcoding.
 * @deprecated Deprecated due to a typo. Use {@link 
 * module:core/abstracts.MediaElement#maxOutputBitrate} instead of this 
 * function.
 *
 * @alias module:core/abstracts.MediaElement#getMaxOuputBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMaxOuputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMaxOuputBitrate = 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, 'getMaxOuputBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMaxOuputBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Maximum video bandwidth for transcoding.
 * @deprecated Deprecated due to a typo. Use {@link 
 * module:core/abstracts.MediaElement#maxOutputBitrate} instead of this 
 * function.
 *
 * @alias module:core/abstracts.MediaElement#setMaxOuputBitrate
 *
 * @param {external:Integer} maxOuputBitrate
 * @param {module:core/abstracts.MediaElement~setMaxOuputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMaxOuputBitrate = function(maxOuputBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    maxOuputBitrate: maxOuputBitrate
  };

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

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

/**
 * Maximum video bitrate for transcoding.
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: MAXINT.</li>
 *   <li>0 = unlimited.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#getMaxOutputBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMaxOutputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMaxOutputBitrate = 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, 'getMaxOutputBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMaxOutputBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Maximum video bitrate for transcoding.
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: MAXINT.</li>
 *   <li>0 = unlimited.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#setMaxOutputBitrate
 *
 * @param {external:Integer} maxOutputBitrate
 * @param {module:core/abstracts.MediaElement~setMaxOutputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMaxOutputBitrate = function(maxOutputBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    maxOutputBitrate: maxOutputBitrate
  };

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

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

/**
 * Minimum video bandwidth for transcoding.
 * @deprecated Deprecated due to a typo. Use {@link 
 * module:core/abstracts.MediaElement#minOutputBitrate} instead of this 
 * function.
 *
 * @alias module:core/abstracts.MediaElement#getMinOuputBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMinOuputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMinOuputBitrate = 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, 'getMinOuputBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMinOuputBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Minimum video bandwidth for transcoding.
 * @deprecated Deprecated due to a typo. Use {@link 
 * module:core/abstracts.MediaElement#minOutputBitrate} instead of this 
 * function.
 *
 * @alias module:core/abstracts.MediaElement#setMinOuputBitrate
 *
 * @param {external:Integer} minOuputBitrate
 * @param {module:core/abstracts.MediaElement~setMinOuputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMinOuputBitrate = function(minOuputBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    minOuputBitrate: minOuputBitrate
  };

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

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

/**
 * Minimum video bitrate for transcoding.
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#getMinOutputBitrate
 *
 * @param {module:core/abstracts.MediaElement~getMinOutputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.getMinOutputBitrate = 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, 'getMinOutputBitrate', callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~getMinOutputBitrateCallback
 * @param {external:Error} error
 * @param {external:Integer} result
 */

/**
 * Minimum video bitrate for transcoding.
 * <ul>
 *   <li>Unit: bps (bits per second).</li>
 *   <li>Default: 0.</li>
 * </ul>
 *
 * @alias module:core/abstracts.MediaElement#setMinOutputBitrate
 *
 * @param {external:Integer} minOutputBitrate
 * @param {module:core/abstracts.MediaElement~setMinOutputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setMinOutputBitrate = function(minOutputBitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    minOutputBitrate: minOutputBitrate
  };

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

  return disguise(this._invoke(transaction, 'setMinOutputBitrate', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setMinOutputBitrateCallback
 * @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 module:core/abstracts.MediaElement MediaElement} that will
 *
 * @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 module:core/abstracts.MediaElement#MediaType.DATA} sources
 *
 * @param {external:String} [sinkMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement MediaElement} that will
 *
 * @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 module:core/abstracts.MediaElement#MediaType.DATA} sources
 *
 * @param {external:String} [sinkMediaDescription]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO}, {@link 
 *  module:core/abstracts.MediaElement#MediaType.VIDEO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.DATA}
 *
 * @param {external:String} [description]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO}, {@link 
 *  module:core/abstracts.MediaElement#MediaType.VIDEO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.DATA}
 *
 * @param {external:String} [description]
 *  A textual description of the media source. Currently not used, aimed mainly 
 *  for {@link module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.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 module:core/abstracts.MediaElement#MediaType.AUDIO} or {@link 
 *  module:core/abstracts.MediaElement#MediaType.VIDEO}
 *
 * @param {external:String} [binName]
 *  Internal name of the processing bin, as previously given by 
 *  <code>MediaTranscodingStateChange</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
 */

/**
 * @deprecated
 * Allows change the target bitrate for the media output, if the media is 
 * encoded using VP8 or H264. This method only works if it is called before the 
 * media starts to flow.
 *
 * @alias module:core/abstracts.MediaElement.setOutputBitrate
 *
 * @param {external:Integer} bitrate
 *  Configure the enconding media bitrate in bps
 *
 * @param {module:core/abstracts.MediaElement~setOutputBitrateCallback} [callback]
 *
 * @return {external:Promise}
 */
MediaElement.prototype.setOutputBitrate = function(bitrate, callback){
  var transaction = (arguments[0] instanceof Transaction)
                  ? Array.prototype.shift.apply(arguments)
                  : undefined;

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

  var params = {
    bitrate: bitrate
  };

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

  return disguise(this._invoke(transaction, 'setOutputBitrate', params, callback), this)
};
/**
 * @callback module:core/abstracts.MediaElement~setOutputBitrateCallback
 * @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', 'MediaFlowOutStateChange', 'MediaTranscodingStateChange']);


/**
 * 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;