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")