API Docs for:
Show:

File: src/internal/stream_collection.coffee

{Deferred} = require('./promise')
EventEmitter = require('events').EventEmitter

###*
# @module rtc.internal
###
###*
# Helper handling the mapping of streams for RemotePeer
# @class rtc.internal.StreamCollection
#
# @constructor
###
class exports.StreamCollection extends EventEmitter

  ###*
  # A new stream was added to the collection
  # @event steam_added
  # @param {String} name The user defined name of the stream
  # @param {Promise -> rtc.Stream} stream Promise to the stream
  ###

  constructor: () ->
    ###*
    # Contains the promises which will resolve to the streams
    # @property {Object} streams
    ###
    @streams = {}

    @_defers = {}
    @_waiting = {}
    @_pending = {}

    @wait_d = new Deferred()
    @wait_p = @wait_d.promise


  ###*
  # Set stream description and generate promises
  # @method update
  # @param data {Object} An object mapping the stream ids to stream names
  ###
  update: (data) ->
    members = []
    @_waiting = {}

    # remove old streams

    for name, stream_p in @streams
      if not data[name]?
        # remove

        delete @streams[name]
        @emit('stream_removed', name)

        # close/fail

        # TODO: this does not work anymore ...
        if stream_p.isFullfilled()
          stream_p.then (stream) ->
            stream.close()
        else if stream_p.isPending()
          stream_p.reject(new Error("Stream removed before being established"))

    # update mappings

    for name, id of data
      # does stream exist?

      if not @streams[name]?
        # create stream promise

        defer = new Deferred()

        @streams[name] = defer.promise
        @_defers[name] = defer

        @emit('stream_added', name, defer.promise)

      # do we adjust stream initialization?

      if @_defers[name]?
        if @_pending[id]?
          # got it!

          stream = @_pending[id]
          delete @_pending[id]

          @_defers[name].resolve(stream)
          delete @_defers[name]

        else
          # add waiting mapping

          @_waiting[id] = name

    @wait_d.resolve()


  ###*
  # Add stream to the collection and resolve promises waiting for it
  # @method resolve
  # @param {rtc.Stream} stream
  ###
  resolve: (stream) ->
    id = stream.id()

    # streams from Chrome to Firefox are coming in with id set to 'default' ...
    if id == 'default'
      if Object.keys(@streams).length == 1 and Object.keys(@_waiting).length == 1
        console.log("Working around incompatibility between Firefox and Chrome concerning stream identification")
        id = Object.keys(@_waiting)[0]
      else
        console.log("Unable to work around incompatibility between Firefox and Chrome concerning stream identification")

    if @_waiting[id]?
      # stream is expected

      name = @_waiting[id]
      delete @_waiting[id]

      @_defers[name].resolve(stream)
      delete @_defers[name]

    else
      # lets hope someone wants this later ...

      @_pending[id] = stream


  ###*
  # Gets a promise for a stream with the given name. Might be rejected after `update()`
  #
  # @method get
  # @param {String} name
  # @return {Promise} The promise for the `rtc.Stream`
  ###
  get: (name) ->
    @wait_p.then () =>
      if @streams[name]?
        return @streams[name]
      else
        throw new Error("Stream not offered")