API Docs for:
Show:

File: src/stream.coffee

{compat} = require('./compat')
{EventEmitter} = require('events')


###*
# @module rtc
###
###*
# A wrapper around an HTML5 MediaStream
# @class rtc.Stream
#
# @constructor
# @param {RTCDataStream} stream The native stream
###
class exports.Stream extends EventEmitter

  ###*
  # Emitted when tracks are muted or unmuted. Only triggered when changes are
  # made through this objects mute functions.
  # @event mute_changed
  # @param {'audio' | 'video' | 'both'} type The type of tracks which changed
  # @param {Boolean} muted `true` if tracks were muted, `false` if they were unmuted
  ###

  constructor: (@stream) ->


  ###*
  # Get the id of the stream. This is neither user defined nor human readable.
  # @method id
  # @return {String} The id of the underlying stream
  ###
  id: () ->
    return @stream.id


  ###*
  # Checks whether the stream has any tracks of the given type
  # @method hasTracks
  # @param {'audio' | 'video' | 'both'} [type='both'] The type of track to check for
  # @return {Number} The amount of tracks of the given type
  ###
  hasTracks: (type) ->
    return @getTracks(type).length


  ###*
  # Gets the tracks of the given type
  # @method getTracks
  # @param {'audio' | 'video' | 'both'} [type='both'] The type of tracks to get
  # @return {Array} An Array of the tracks
  ###
  getTracks: (type) ->
    type = type.toLowerCase()

    if type == 'audio'
      return @stream.getAudioTracks()
    else if type == 'video'
      return @stream.getVideoTracks()
    else if type == 'both'
      video = @stream.getVideoTracks()
      vaudio = @stream.getAudioTracks()
      return video.concat(audio)
    else
      throw new Error("Invalid stream part '" + type + "'")


  ###*
  # Checks whether a type of track is muted. If there are no tracks of the
  # specified type they will be considered muted
  # @param {'audio' | 'video' | 'both'} [type='audio'] The type of tracks
  # @return {Boolean} Whether the tracks are muted
  ###
  muted: (type='audio') ->
    tracks = @getTracks(type)

    if tracks.length < 1
      return true

    return not tracks[0]?.enabled


  ###*
  # Mutes or unmutes tracks of the stream
  # @method mute
  # @param {Boolean} [muted=true] Mute on `true` and unmute on `false`
  # @param {'audio' | 'video' | 'both'} [type='audio'] The type of tracks to mute or unmute
  # @return {Boolean} Whether the tracks were muted or unmuted
  ###
  mute: (muted=true, type='audio') ->
    for track in @getTracks(type)
      track.enabled = not muted

    @emit('mute_changed', type, muted)

    return muted


  ###*
  # Toggles the mute state of tracks of the stream
  # @method toggleMute
  # @param {'audio' | 'video' | 'both'} [type='audio'] The type of tracks to mute or unmute
  # @return {Boolean} Whether the tracks were muted or unmuted
  ###
  toggleMute: (type='audio') ->
    tracks = @getTracks(type)

    if tracks.length < 1
      return true

    muted = not tracks[0]?.enabled

    for track in tracks
      track.enabled = not muted

    @emit('mute_changed', type, muted)

    return muted


  ###*
  # Stops the stream
  # @method stop
  ###
  stop: () ->
    if @stream.getTracks?
      for track in @stream.getTracks()
        track.stop()
    else
      @stream.stop()


  ###*
  # Clones the stream. You can change both streams independently, for example
  # mute tracks. You will have to `stop()` both streams individually when you
  # are done.
  #
  # This is currently not supported in Firefox and expected to be implemented
  # in version 47. Use `Stream.canClone()` to check whether cloning is supported by
  # your browser.
  #
  # @method clone
  # @return {rtc.Stream} A clone of the stream
  ###
  clone: () ->
    if not @stream.clone?
      throw new Error("Your browser does not support stream cloning. Firefox is expected to implement it in version 47.")

    return new Stream(@stream.clone())


  ###*
  # Checks whether cloning stream is supported by the browser. See `clone()`
  # for details
  # @static
  # @method canClone
  # @return {Boolean} `true` if cloning is supported, `false` otherwise
  ###
  @canClone: () ->
    return compat.MediaStream.prototype.clone?


  ###*
  # Creates a stream using `getUserMedia()`
  # @method createStream
  # @static
  # @param {Object} [config={audio: true, video: true}] The configuration to pass to `getUserMedia()`
  # @return {Promise -> rtc.Stream} Promise to the stream
  #
  # @example
  #     var stream = rtc.Stream.createStream({audio: true, video: false});
  #     rtc.MediaDomElement($('video'), stream);
  ###
  @createStream: (config={audio: true, video: true}) ->
    return new Promise (resolve, reject) ->
      # description to pass to getUserMedia()
      success = (native_stream) ->
        resolve(new Stream(native_stream))

      compat.getUserMedia(config, success, reject)