Source: node_modules/kurento-client-elements/lib/RecorderEndpoint.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 UriEndpoint = require('kurento-client-core').abstracts.UriEndpoint;


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

  return result
};


/**
 * Builder for the {@link RecorderEndpoint}
 *
 * @classdesc
 *  Provides functionality to store media contents.
 *  <p>
 *    RecorderEndpoint can store media into local files or send it to a remote
 *    network storage. When another {@link MediaElement} is connected to a
 *    RecorderEndpoint, the media coming from the former will be muxed into the
 *    selected recording format and stored in the designated location.
 *  </p>
 *  <p>
 *    These parameters must be provided to create a RecorderEndpoint, and they
 *    cannot be changed afterwards:
 *  </p>
 *  <ul>
 *    <li>
 *      <strong>Destination URI</strong>, where media will be stored. These 
 *      formats
 *      are supported:
 *      <ul>
 *        <li>
 *          File: A file path that will be written into the local file system.
 *          Example:
 *          <ul>
 *            <li><code>file:///path/to/file</code></li>
 *          </ul>
 *        </li>
 *        <li>
 *          HTTP: A POST request will be used against a remote server. The 
 *          server
 *          must support using the <i>chunked</i> encoding mode (HTTP header
 *          <code>Transfer-Encoding: chunked</code>). Examples:
 *          <ul>
 *            <li><code>http(s)://host/path/to/file</code></li>
 *            <li>
 *              <code>
 *                http(s)://username:password@host:port/path/to/file
 *              </code>
 *            </li>
 *          </ul>
 *        </li>
 *        <li>
 *          Relative URIs (with no schema) are supported. They are completed by
 *          prepending a default URI defined by property <i>defaultPath</i>. 
 *          This
 *          property is defined in the configuration file
 *          <i>/etc/kurento/modules/kurento/UriEndpoint.conf.ini</i>, and the
 *          default value is <code>file:///var/lib/kurento/</code>
 *        </li>
 *        <li>
 *          <strong>
 *            NOTE: Special characters must be
 *            <a href='https://en.wikipedia.org/wiki/Query_string#URL_encoding'>
 *              URL-encoded
 *            </a>
 *            in <code>username</code> and <code>password</code> fields.
 *          </strong>
 *        </li>
 *      </ul>
 *    </li>
 *    <li>
 *      <strong>Media Profile</strong> ({@link MediaProfileSpecType}), which
 *      determines the video and audio encoding. See below for more details.
 *    </li>
 *    <li>
 *      <strong>EndOfStream</strong> (optional), a parameter that dictates if 
 *      the
 *      recording should be automatically stopped once the EOS event is 
 *      detected.
 *    </li>
 *  </ul>
 *  <p>
 *    Note that
 *    <strong>
 *      RecorderEndpoint requires write permissions to the destination
 *    </strong>
 *    ; otherwise, the media server won't be able to store any information, and 
 *    an
 *    {@link ErrorEvent} will be fired. Make sure your application subscribes to
 *    event, otherwise troubleshooting issues will be difficult.
 *  </p>
 *  <ul>
 *    <li>
 *      To write local files (if you use <code>file://</code>), the system user 
 *      that
 *      is owner of the media server process needs to have write permissions for
 *      requested path. By default, this user is named '<code>kurento</code>'.
 *    </li>
 *    <li>
 *      To record through HTTP, the remote server must be accessible through the
 *      network, and also have the correct write permissions for the destination
 *      path.
 *    </li>
 *  </ul>
 *  <p>
 *    Recording will start as soon as the user invokes the
 *    <code>record()</code> method. The recorder will then store, in the 
 *    location
 *    indicated, the media that the source is sending to the endpoint. If no 
 *    media
 *    is being received, or no endpoint has been connected, then the destination
 *    will be empty. The recorder starts storing information into the file as 
 *    soon
 *    as it gets it.
 *  </p>
 *  <p>
 *    <strong>Recording must be stopped</strong> when no more data should be 
 *    stored.
 *    This is done with the <code>stopAndWait()</code> method, which blocks and
 *    returns only after all the information was stored correctly.
 *  </p>
 *  <p>
 *    The source endpoint can be hot-swapped while the recording is taking 
 *    place.
 *    The recorded file will then contain different feeds. When switching video
 *    sources, if the new video has different size, the recorder will retain the
 *    size of the previous source. If the source is disconnected, the last frame
 *    recorded will be shown for the duration of the disconnection, or until the
 *    recording is stopped.
 *  </p>
 *  <p>
 *    <strong>
 *      NOTE: It is recommended to start recording only after media arrives.
 *    </strong>
 *    For this, you may use the <code>MediaFlowInStateChanged</code> and
 *    <code>MediaFlowOutStateChanged</code>
 *    events of your endpoints, and synchronize the recording with the moment 
 *    media
 *    comes into the Recorder.
 *  </p>
 *  <p>
 *    <strong>
 *      WARNING: All connected media types must be flowing to the 
 *      RecorderEndpoint.
 *    </strong>
 *    If you used the default <code>connect()</code> method, it will assume both
 *    AUDIO and VIDEO. Failing to provide both kinds of media will result in the
 *    RecorderEndpoint creating an empty file and buffering indefinitely; the
 *    recorder waits until all kinds of media start arriving, in order to
 *    synchronize them appropriately.<br />
 *    For audio-only or video-only recordings, make sure to use the correct,
 *    media-specific variant of the <code>connect()</code> method.
 *  </p>
 *  <p>For example:</p>
 *  <ol>
 *    <li>
 *      When a web browser's video arrives to Kurento via WebRTC, your
 *      WebRtcEndpoint will emit a <code>MediaFlowOutStateChanged</code> event.
 *    </li>
 *    <li>
 *      When video starts flowing from the WebRtcEndpoint to the 
 *      RecorderEndpoint,
 *      the RecorderEndpoint will emit a <code>MediaFlowInStateChanged</code> 
 *      event.
 *      You should start recording at this point.
 *    </li>
 *    <li>
 *      You should only start recording when RecorderEndpoint has notified a
 *      <code>MediaFlowInStateChanged</code> for ALL streams. So, if you record
 *      AUDIO+VIDEO, your application must receive a
 *      <code>MediaFlowInStateChanged</code> event for audio, and another
 *      <code>MediaFlowInStateChanged</code> event for video.
 *    </li>
 *  </ol>
 *
 * @extends module:core/abstracts.UriEndpoint
 *
 * @constructor module:elements.RecorderEndpoint
 *
 * @fires {@link module:elements#event:Paused Paused}
 * @fires {@link module:elements#event:Recording Recording}
 * @fires {@link module:elements#event:Stopped Stopped}
 */
function RecorderEndpoint(){
  RecorderEndpoint.super_.call(this);
};
inherits(RecorderEndpoint, UriEndpoint);


//
// Public methods
//

/**
 * Starts storing media received through the sink pad.
 *
 * @alias module:elements.RecorderEndpoint.record
 *
 * @param {module:elements.RecorderEndpoint~recordCallback} [callback]
 *
 * @return {external:Promise}
 */
RecorderEndpoint.prototype.record = 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, 'record', callback), this)
};
/**
 * @callback module:elements.RecorderEndpoint~recordCallback
 * @param {external:Error} error
 */

/**
 * Stops recording and does not return until all the content has been written to
 *
 * @alias module:elements.RecorderEndpoint.stopAndWait
 *
 * @param {module:elements.RecorderEndpoint~stopAndWaitCallback} [callback]
 *
 * @return {external:Promise}
 */
RecorderEndpoint.prototype.stopAndWait = 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, 'stopAndWait', callback), this)
};
/**
 * @callback module:elements.RecorderEndpoint~stopAndWaitCallback
 * @param {external:Error} error
 */


/**
 * @alias module:elements.RecorderEndpoint.constructorParams
 *
 * @property {module:core.MediaPipeline} mediaPipeline
 *  the {@link MediaPipeline} to which the endpoint belongs
 *
 * @property {module:elements/complexTypes.MediaProfileSpecType} [mediaProfile]
 *  Selects the media format used for recording.
 *  <p>
 *    The media profile allows you to specify which codecs and media container 
 *    will
 *    be used for the recordings. This is currently the only way available to 
 *    tell
 *    Kurento about which codecs should be used.
 *  </p>
 *  <p>
 *    Watch out for these important remarks:
 *  </p>
 *  <ul>
 *    <li>
 *      If the format of incoming media differs from the recording profile, 
 *      media
 *      will need to be transcoded. Transcoding always incurs in noticeable CPU
 *      load, so it is always good trying to avoid it. For instance, if a
 *      VP8-encoded video (from WebRTC) is recorded with an MP4 recording 
 *      profile
 *      (which means H.264 encoding), the video needs to be transcoded from VP8 
 *      to
 *      H.264. On the other hand, recording with the WEBM profile would allow to
 *      store the video as-is with its VP8 encoding.
 *    </li>
 *    <li>
 *      If you intend to record audio-only or video-only media, select the
 *      appropriate <code>_AUDIO_ONLY</code> or <code>_VIDEO_ONLY</code> 
 *      profile.
 *      For example, to record a WebRTC screen capture (as obtained from a web
 *      browser's call to <code>MediaDevices.getDisplayMedia()</code>), choose
 *      <code>WEBM_VIDEO_ONLY</code> instead of just <code>WEBM</code>.
 *    </li>
 *  </ul>
 *
 * @property {external:Boolean} [stopOnEndOfStream]
 *  Forces the recorder endpoint to finish processing data when an End Of Stream
 *
 * @property {external:String} uri
 *  URI where the recording will be stored. It must be accessible from the media
 *                <ul>
 *                  <li>Local server resources: The user running the Kurento 
 *                  Media Server must have write permission over the file.</li>
 *                  <li>Network resources: Must be accessible from the network 
 *                  where the media server is running.</li>
 *                </ul>
 */
RecorderEndpoint.constructorParams = {
  mediaPipeline: {
    type: 'kurento.MediaPipeline',
    required: true
  },
  mediaProfile: {
    type: 'kurento.MediaProfileSpecType'  },
  stopOnEndOfStream: {
    type: 'boolean'  },
  uri: {
    type: 'String',
    required: true
  }
};

/**
 * @alias module:elements.RecorderEndpoint.events
 *
 * @extends module:core/abstracts.UriEndpoint.events
 */
RecorderEndpoint.events = UriEndpoint.events.concat(['Paused', 'Recording', 'Stopped']);


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


module.exports = RecorderEndpoint;

RecorderEndpoint.check = checkRecorderEndpoint;