From 77c0a43ae3473cd5c2d16faa76905b2d7ff67d9b Mon Sep 17 00:00:00 2001 From: Daniel Berteaud Date: Thu, 19 Feb 2015 19:21:47 +0100 Subject: [PATCH] Update to SimpleWebRTC 1.13.3 --- public/js/simplewebrtc.bundle.js | 969 ++++++++++++++++++++------------------- 1 file changed, 487 insertions(+), 482 deletions(-) diff --git a/public/js/simplewebrtc.bundle.js b/public/js/simplewebrtc.bundle.js index 878c1ce..9613fae 100644 --- a/public/js/simplewebrtc.bundle.js +++ b/public/js/simplewebrtc.bundle.js @@ -80,6 +80,7 @@ function SimpleWebRTC(opts) { peers.forEach(function (p) { if (p.sid == message.sid) peer = p; }); + if (!peer) peer = peers[0]; // fallback for old protocol versions } if (!peer) { peer = self.webrtc.createPeer({ @@ -95,7 +96,11 @@ function SimpleWebRTC(opts) { peer.handleMessage(message); } else if (peers.length) { peers.forEach(function (peer) { - if (peer.sid === message.sid) { + if (message.sid) { + if (peer.sid === message.sid) { + peer.handleMessage(message); + } + } else { peer.handleMessage(message); } }); @@ -441,7 +446,47 @@ SimpleWebRTC.prototype.sendFile = function () { module.exports = SimpleWebRTC; -},{"attachmediastream":4,"mockconsole":6,"socket.io-client":7,"webrtc":5,"webrtcsupport":3,"wildemitter":2}],4:[function(require,module,exports){ +},{"attachmediastream":5,"mockconsole":7,"socket.io-client":6,"webrtc":2,"webrtcsupport":4,"wildemitter":3}],4:[function(require,module,exports){ +// created by @HenrikJoreteg +var prefix; + +if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) { + prefix = 'moz'; +} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) { + prefix = 'webkit'; +} + +var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; +var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; +var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; +var MediaStream = window.webkitMediaStream || window.MediaStream; +var screenSharing = window.location.protocol === 'https:' && + ((window.navigator.userAgent.match('Chrome') && parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10) >= 26) || + (window.navigator.userAgent.match('Firefox') && parseInt(window.navigator.userAgent.match(/Firefox\/(.*)/)[1], 10) >= 33)); +var AudioContext = window.AudioContext || window.webkitAudioContext; +var supportVp8 = document.createElement('video').canPlayType('video/webm; codecs="vp8", vorbis') === "probably"; +var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia; + +// export support flags and constructors.prototype && PC +module.exports = { + support: !!PC && supportVp8 && !!getUserMedia, + supportRTCPeerConnection: !!PC, + supportVp8: supportVp8, + supportGetUserMedia: !!getUserMedia, + supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), + supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), + supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), + supportScreenSharing: !!screenSharing, + prefix: prefix, + AudioContext: AudioContext, + PeerConnection: PC, + SessionDescription: SessionDescription, + IceCandidate: IceCandidate, + MediaStream: MediaStream, + getUserMedia: getUserMedia +}; + +},{}],5:[function(require,module,exports){ module.exports = function (stream, el, options) { var URL = window.URL; var opts = { @@ -482,200 +527,7 @@ module.exports = function (stream, el, options) { return element; }; -},{}],2:[function(require,module,exports){ -/* -WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based -on @visionmedia's Emitter from UI Kit. - -Why? I wanted it standalone. - -I also wanted support for wildcard emitters like this: - -emitter.on('*', function (eventName, other, event, payloads) { - -}); - -emitter.on('somenamespace*', function (eventName, payloads) { - -}); - -Please note that callbacks triggered by wildcard registered events also get -the event name as the first argument. -*/ -module.exports = WildEmitter; - -function WildEmitter() { - this.callbacks = {}; -} - -// Listen on the given `event` with `fn`. Store a group name if present. -WildEmitter.prototype.on = function (event, groupName, fn) { - var hasGroup = (arguments.length === 3), - group = hasGroup ? arguments[1] : undefined, - func = hasGroup ? arguments[2] : arguments[1]; - func._groupName = group; - (this.callbacks[event] = this.callbacks[event] || []).push(func); - return this; -}; - -// Adds an `event` listener that will be invoked a single -// time then automatically removed. -WildEmitter.prototype.once = function (event, groupName, fn) { - var self = this, - hasGroup = (arguments.length === 3), - group = hasGroup ? arguments[1] : undefined, - func = hasGroup ? arguments[2] : arguments[1]; - function on() { - self.off(event, on); - func.apply(this, arguments); - } - this.on(event, group, on); - return this; -}; - -// Unbinds an entire group -WildEmitter.prototype.releaseGroup = function (groupName) { - var item, i, len, handlers; - for (item in this.callbacks) { - handlers = this.callbacks[item]; - for (i = 0, len = handlers.length; i < len; i++) { - if (handlers[i]._groupName === groupName) { - //console.log('removing'); - // remove it and shorten the array we're looping through - handlers.splice(i, 1); - i--; - len--; - } - } - } - return this; -}; - -// Remove the given callback for `event` or all -// registered callbacks. -WildEmitter.prototype.off = function (event, fn) { - var callbacks = this.callbacks[event], - i; - - if (!callbacks) return this; - - // remove all handlers - if (arguments.length === 1) { - delete this.callbacks[event]; - return this; - } - - // remove specific handler - i = callbacks.indexOf(fn); - callbacks.splice(i, 1); - return this; -}; - -/// Emit `event` with the given args. -// also calls any `*` handlers -WildEmitter.prototype.emit = function (event) { - var args = [].slice.call(arguments, 1), - callbacks = this.callbacks[event], - specialCallbacks = this.getWildcardCallbacks(event), - i, - len, - item, - listeners; - - if (callbacks) { - listeners = callbacks.slice(); - for (i = 0, len = listeners.length; i < len; ++i) { - if (listeners[i]) { - listeners[i].apply(this, args); - } else { - break; - } - } - } - - if (specialCallbacks) { - len = specialCallbacks.length; - listeners = specialCallbacks.slice(); - for (i = 0, len = listeners.length; i < len; ++i) { - if (listeners[i]) { - listeners[i].apply(this, [event].concat(args)); - } else { - break; - } - } - } - - return this; -}; - -// Helper for for finding special wildcard event handlers that match the event -WildEmitter.prototype.getWildcardCallbacks = function (eventName) { - var item, - split, - result = []; - - for (item in this.callbacks) { - split = item.split('*'); - if (item === '*' || (split.length === 2 && eventName.slice(0, split[0].length) === split[0])) { - result = result.concat(this.callbacks[item]); - } - } - return result; -}; - },{}],6:[function(require,module,exports){ -var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","); -var l = methods.length; -var fn = function () {}; -var mockconsole = {}; - -while (l--) { - mockconsole[methods[l]] = fn; -} - -module.exports = mockconsole; - -},{}],3:[function(require,module,exports){ -// created by @HenrikJoreteg -var prefix; - -if (window.mozRTCPeerConnection || navigator.mozGetUserMedia) { - prefix = 'moz'; -} else if (window.webkitRTCPeerConnection || navigator.webkitGetUserMedia) { - prefix = 'webkit'; -} - -var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; -var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; -var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; -var MediaStream = window.webkitMediaStream || window.MediaStream; -var screenSharing = window.location.protocol === 'https:' && - ((window.navigator.userAgent.match('Chrome') && parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10) >= 26) || - (window.navigator.userAgent.match('Firefox') && parseInt(window.navigator.userAgent.match(/Firefox\/(.*)/)[1], 10) >= 33)); -var AudioContext = window.AudioContext || window.webkitAudioContext; -var supportVp8 = document.createElement('video').canPlayType('video/webm; codecs="vp8", vorbis') === "probably"; -var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia; - -// export support flags and constructors.prototype && PC -module.exports = { - support: !!PC && supportVp8 && !!getUserMedia, - supportRTCPeerConnection: !!PC, - supportVp8: supportVp8, - supportGetUserMedia: !!getUserMedia, - supportDataChannel: !!(PC && PC.prototype && PC.prototype.createDataChannel), - supportWebAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), - supportMediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), - supportScreenSharing: !!screenSharing, - prefix: prefix, - AudioContext: AudioContext, - PeerConnection: PC, - SessionDescription: SessionDescription, - IceCandidate: IceCandidate, - MediaStream: MediaStream, - getUserMedia: getUserMedia -}; - -},{}],7:[function(require,module,exports){ /*! Socket.IO.js build:0.9.16, development. Copyright(c) 2011 LearnBoost MIT Licensed */ var io = ('undefined' === typeof module ? {} : module.exports); @@ -4549,20 +4401,173 @@ if (typeof define === "function" && define.amd) { define([], function () { return io; }); } })(); -},{}],8:[function(require,module,exports){ -var events = require('events'); +},{}],7:[function(require,module,exports){ +var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","); +var l = methods.length; +var fn = function () {}; +var mockconsole = {}; -exports.isArray = isArray; -exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; -exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; +while (l--) { + mockconsole[methods[l]] = fn; +} +module.exports = mockconsole; -exports.print = function () {}; -exports.puts = function () {}; -exports.debug = function() {}; +},{}],3:[function(require,module,exports){ +/* +WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based +on @visionmedia's Emitter from UI Kit. -exports.inspect = function(obj, showHidden, depth, colors) { - var seen = []; +Why? I wanted it standalone. + +I also wanted support for wildcard emitters like this: + +emitter.on('*', function (eventName, other, event, payloads) { + +}); + +emitter.on('somenamespace*', function (eventName, payloads) { + +}); + +Please note that callbacks triggered by wildcard registered events also get +the event name as the first argument. +*/ +module.exports = WildEmitter; + +function WildEmitter() { + this.callbacks = {}; +} + +// Listen on the given `event` with `fn`. Store a group name if present. +WildEmitter.prototype.on = function (event, groupName, fn) { + var hasGroup = (arguments.length === 3), + group = hasGroup ? arguments[1] : undefined, + func = hasGroup ? arguments[2] : arguments[1]; + func._groupName = group; + (this.callbacks[event] = this.callbacks[event] || []).push(func); + return this; +}; + +// Adds an `event` listener that will be invoked a single +// time then automatically removed. +WildEmitter.prototype.once = function (event, groupName, fn) { + var self = this, + hasGroup = (arguments.length === 3), + group = hasGroup ? arguments[1] : undefined, + func = hasGroup ? arguments[2] : arguments[1]; + function on() { + self.off(event, on); + func.apply(this, arguments); + } + this.on(event, group, on); + return this; +}; + +// Unbinds an entire group +WildEmitter.prototype.releaseGroup = function (groupName) { + var item, i, len, handlers; + for (item in this.callbacks) { + handlers = this.callbacks[item]; + for (i = 0, len = handlers.length; i < len; i++) { + if (handlers[i]._groupName === groupName) { + //console.log('removing'); + // remove it and shorten the array we're looping through + handlers.splice(i, 1); + i--; + len--; + } + } + } + return this; +}; + +// Remove the given callback for `event` or all +// registered callbacks. +WildEmitter.prototype.off = function (event, fn) { + var callbacks = this.callbacks[event], + i; + + if (!callbacks) return this; + + // remove all handlers + if (arguments.length === 1) { + delete this.callbacks[event]; + return this; + } + + // remove specific handler + i = callbacks.indexOf(fn); + callbacks.splice(i, 1); + return this; +}; + +/// Emit `event` with the given args. +// also calls any `*` handlers +WildEmitter.prototype.emit = function (event) { + var args = [].slice.call(arguments, 1), + callbacks = this.callbacks[event], + specialCallbacks = this.getWildcardCallbacks(event), + i, + len, + item, + listeners; + + if (callbacks) { + listeners = callbacks.slice(); + for (i = 0, len = listeners.length; i < len; ++i) { + if (listeners[i]) { + listeners[i].apply(this, args); + } else { + break; + } + } + } + + if (specialCallbacks) { + len = specialCallbacks.length; + listeners = specialCallbacks.slice(); + for (i = 0, len = listeners.length; i < len; ++i) { + if (listeners[i]) { + listeners[i].apply(this, [event].concat(args)); + } else { + break; + } + } + } + + return this; +}; + +// Helper for for finding special wildcard event handlers that match the event +WildEmitter.prototype.getWildcardCallbacks = function (eventName) { + var item, + split, + result = []; + + for (item in this.callbacks) { + split = item.split('*'); + if (item === '*' || (split.length === 2 && eventName.slice(0, split[0].length) === split[0])) { + result = result.concat(this.callbacks[item]); + } + } + return result; +}; + +},{}],8:[function(require,module,exports){ +var events = require('events'); + +exports.isArray = isArray; +exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; +exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; + + +exports.print = function () {}; +exports.puts = function () {}; +exports.debug = function() {}; + +exports.inspect = function(obj, showHidden, depth, colors) { + var seen = []; var stylize = function(str, styleType) { // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics @@ -4896,7 +4901,7 @@ exports.format = function(f) { return str; }; -},{"events":9}],5:[function(require,module,exports){ +},{"events":9}],2:[function(require,module,exports){ var util = require('util'); var webrtc = require('webrtcsupport'); var WildEmitter = require('wildemitter'); @@ -5061,7 +5066,7 @@ WebRTC.prototype.sendDirectlyToAll = function (channel, message, payload) { module.exports = WebRTC; -},{"./peer":10,"localmedia":11,"mockconsole":6,"util":8,"webrtcsupport":3,"wildemitter":2}],12:[function(require,module,exports){ +},{"./peer":10,"localmedia":11,"mockconsole":7,"util":8,"webrtcsupport":4,"wildemitter":3}],12:[function(require,module,exports){ // shim for using process in browser var process = module.exports = {}; @@ -5419,7 +5424,7 @@ Peer.prototype.handleMessage = function (message) { this.parent.emit('mute', {id: message.from, name: message.payload.name}); } else if (message.type === 'unmute') { this.parent.emit('unmute', {id: message.from, name: message.payload.name}); - } else { + } else { this.parent.emit(message.type, {id: message.from, payload: message.payload, roomType: message.roomType}); } }; @@ -5541,7 +5546,7 @@ Peer.prototype.handleDataChannelAdded = function (channel) { module.exports = Peer; -},{"rtcpeerconnection":13,"util":8,"webrtcsupport":3,"wildemitter":2}],14:[function(require,module,exports){ +},{"rtcpeerconnection":13,"util":8,"webrtcsupport":4,"wildemitter":3}],14:[function(require,module,exports){ // getUserMedia helper by @HenrikJoreteg var func = (window.navigator.getUserMedia || window.navigator.webkitGetUserMedia || @@ -5914,7 +5919,7 @@ Object.defineProperty(LocalMedia.prototype, 'localScreen', { module.exports = LocalMedia; -},{"getscreenmedia":16,"getusermedia":14,"hark":15,"mediastream-gain":17,"mockconsole":6,"util":8,"webrtcsupport":3,"wildemitter":2}],18:[function(require,module,exports){ +},{"getscreenmedia":16,"getusermedia":14,"hark":15,"mediastream-gain":17,"mockconsole":7,"util":8,"webrtcsupport":4,"wildemitter":3}],18:[function(require,module,exports){ // Underscore.js 1.7.0 // http://underscorejs.org // (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors @@ -7378,7 +7383,45 @@ GainController.prototype.on = function () { module.exports = GainController; -},{"webrtcsupport":19}],20:[function(require,module,exports){ +},{"webrtcsupport":19}],19:[function(require,module,exports){ +// created by @HenrikJoreteg +var prefix; +var isChrome = false; +var isFirefox = false; +var ua = window.navigator.userAgent.toLowerCase(); + +// basic sniffing +if (ua.indexOf('firefox') !== -1) { + prefix = 'moz'; + isFirefox = true; +} else if (ua.indexOf('chrome') !== -1) { + prefix = 'webkit'; + isChrome = true; +} + +var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; +var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; +var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; +var MediaStream = window.webkitMediaStream || window.MediaStream; +var screenSharing = window.location.protocol === 'https:' && window.navigator.userAgent.match('Chrome') && parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10) >= 26; +var AudioContext = window.webkitAudioContext || window.AudioContext; + + +// export support flags and constructors.prototype && PC +module.exports = { + support: !!PC, + dataChannel: isChrome || isFirefox || (PC && PC.prototype && PC.prototype.createDataChannel), + prefix: prefix, + webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), + mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), + screenSharing: !!screenSharing, + AudioContext: AudioContext, + PeerConnection: PC, + SessionDescription: SessionDescription, + IceCandidate: IceCandidate +}; + +},{}],20:[function(require,module,exports){ var toSDP = require('./lib/tosdp'); var toJSON = require('./lib/tojson'); @@ -7500,7 +7543,7 @@ exports.toCandidateJSON = toJSON.toCandidateJSON; exports.toMediaJSON = toJSON.toMediaJSON; exports.toSessionJSON = toJSON.toSessionJSON; -},{"./lib/tojson":22,"./lib/tosdp":21}],13:[function(require,module,exports){ +},{"./lib/tojson":21,"./lib/tosdp":22}],13:[function(require,module,exports){ var _ = require('underscore'); var util = require('util'); var webrtc = require('webrtcsupport'); @@ -8146,45 +8189,7 @@ PeerConnection.prototype.getStats = function (cb) { module.exports = PeerConnection; -},{"sdp-jingle-json":20,"traceablepeerconnection":23,"underscore":18,"util":8,"webrtcsupport":3,"wildemitter":2}],19:[function(require,module,exports){ -// created by @HenrikJoreteg -var prefix; -var isChrome = false; -var isFirefox = false; -var ua = window.navigator.userAgent.toLowerCase(); - -// basic sniffing -if (ua.indexOf('firefox') !== -1) { - prefix = 'moz'; - isFirefox = true; -} else if (ua.indexOf('chrome') !== -1) { - prefix = 'webkit'; - isChrome = true; -} - -var PC = window.mozRTCPeerConnection || window.webkitRTCPeerConnection; -var IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate; -var SessionDescription = window.mozRTCSessionDescription || window.RTCSessionDescription; -var MediaStream = window.webkitMediaStream || window.MediaStream; -var screenSharing = window.location.protocol === 'https:' && window.navigator.userAgent.match('Chrome') && parseInt(window.navigator.userAgent.match(/Chrome\/(.*) /)[1], 10) >= 26; -var AudioContext = window.webkitAudioContext || window.AudioContext; - - -// export support flags and constructors.prototype && PC -module.exports = { - support: !!PC, - dataChannel: isChrome || isFirefox || (PC && PC.prototype && PC.prototype.createDataChannel), - prefix: prefix, - webAudio: !!(AudioContext && AudioContext.prototype.createMediaStreamSource), - mediaStream: !!(MediaStream && MediaStream.prototype.removeTrack), - screenSharing: !!screenSharing, - AudioContext: AudioContext, - PeerConnection: PC, - SessionDescription: SessionDescription, - IceCandidate: IceCandidate -}; - -},{}],16:[function(require,module,exports){ +},{"sdp-jingle-json":20,"traceablepeerconnection":23,"underscore":18,"util":8,"webrtcsupport":4,"wildemitter":3}],16:[function(require,module,exports){ // getScreenMedia helper by @HenrikJoreteg var getUserMedia = require('getusermedia'); @@ -8300,237 +8305,21 @@ window.addEventListener('message', function (event) { } }); -},{"getusermedia":14}],21:[function(require,module,exports){ -var SENDERS = require('./senders'); +},{"getusermedia":14}],15:[function(require,module,exports){ +var WildEmitter = require('wildemitter'); +function getMaxVolume (analyser, fftBins) { + var maxVolume = -Infinity; + analyser.getFloatFrequencyData(fftBins); -exports.toSessionSDP = function (session, opts) { - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; - var sid = opts.sid || session.sid || Date.now(); - var time = opts.time || Date.now(); + for(var i=4, ii=fftBins.length; i < ii; i++) { + if (fftBins[i] > maxVolume && fftBins[i] < 0) { + maxVolume = fftBins[i]; + } + }; - var sdp = [ - 'v=0', - 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0', - 's=-', - 't=0 0' - ]; - - var groups = session.groups || []; - groups.forEach(function (group) { - sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' ')); - }); - - var contents = session.contents || []; - contents.forEach(function (content) { - sdp.push(exports.toMediaSDP(content, opts)); - }); - - return sdp.join('\r\n') + '\r\n'; -}; - -exports.toMediaSDP = function (content, opts) { - var sdp = []; - - var role = opts.role || 'initiator'; - var direction = opts.direction || 'outgoing'; - - var desc = content.description; - var transport = content.transport; - var payloads = desc.payloads || []; - var fingerprints = (transport && transport.fingerprints) || []; - - var mline = []; - if (desc.descType == 'datachannel') { - mline.push('application'); - mline.push('1'); - mline.push('DTLS/SCTP'); - if (transport.sctp) { - transport.sctp.forEach(function (map) { - mline.push(map.number); - }); - } - } else { - mline.push(desc.media); - mline.push('1'); - if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) { - mline.push('RTP/SAVPF'); - } else { - mline.push('RTP/AVPF'); - } - payloads.forEach(function (payload) { - mline.push(payload.id); - }); - } - - - sdp.push('m=' + mline.join(' ')); - - sdp.push('c=IN IP4 0.0.0.0'); - if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) { - sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth); - } - if (desc.descType == 'rtp') { - sdp.push('a=rtcp:1 IN IP4 0.0.0.0'); - } - - if (transport) { - if (transport.ufrag) { - sdp.push('a=ice-ufrag:' + transport.ufrag); - } - if (transport.pwd) { - sdp.push('a=ice-pwd:' + transport.pwd); - } - - var pushedSetup = false; - fingerprints.forEach(function (fingerprint) { - sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value); - if (fingerprint.setup && !pushedSetup) { - sdp.push('a=setup:' + fingerprint.setup); - } - }); - - if (transport.sctp) { - transport.sctp.forEach(function (map) { - sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams); - }); - } - } - - if (desc.descType == 'rtp') { - sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv')); - } - sdp.push('a=mid:' + content.name); - - if (desc.mux) { - sdp.push('a=rtcp-mux'); - } - - var encryption = desc.encryption || []; - encryption.forEach(function (crypto) { - sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : '')); - }); - if (desc.googConferenceFlag) { - sdp.push('a=x-google-flag:conference'); - } - - payloads.forEach(function (payload) { - var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate; - if (payload.channels && payload.channels != '1') { - rtpmap += '/' + payload.channels; - } - sdp.push(rtpmap); - - if (payload.parameters && payload.parameters.length) { - var fmtp = ['a=fmtp:' + payload.id]; - var parameters = []; - payload.parameters.forEach(function (param) { - parameters.push((param.key ? param.key + '=' : '') + param.value); - }); - fmtp.push(parameters.join(';')); - sdp.push(fmtp.join(' ')); - } - - if (payload.feedback) { - payload.feedback.forEach(function (fb) { - if (fb.type === 'trr-int') { - sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + fb.value ? fb.value : '0'); - } else { - sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); - } - }); - } - }); - - if (desc.feedback) { - desc.feedback.forEach(function (fb) { - if (fb.type === 'trr-int') { - sdp.push('a=rtcp-fb:* trr-int ' + fb.value ? fb.value : '0'); - } else { - sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); - } - }); - } - - var hdrExts = desc.headerExtensions || []; - hdrExts.forEach(function (hdr) { - sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri); - }); - - var ssrcGroups = desc.sourceGroups || []; - ssrcGroups.forEach(function (ssrcGroup) { - sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' ')); - }); - - var ssrcs = desc.sources || []; - ssrcs.forEach(function (ssrc) { - for (var i = 0; i < ssrc.parameters.length; i++) { - var param = ssrc.parameters[i]; - sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : '')); - } - }); - - var candidates = transport.candidates || []; - candidates.forEach(function (candidate) { - sdp.push(exports.toCandidateSDP(candidate)); - }); - - return sdp.join('\r\n'); -}; - -exports.toCandidateSDP = function (candidate) { - var sdp = []; - - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type === 'srflx' || type === 'prflx' || type === 'relay') { - if (candidate.relAddr && candidate.relPort) { - sdp.push('raddr'); - sdp.push(candidate.relAddr); - sdp.push('rport'); - sdp.push(candidate.relPort); - } - } - if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - - sdp.push('generation'); - sdp.push(candidate.generation || '0'); - - // FIXME: apparently this is wrong per spec - // but then, we need this when actually putting this into - // SDP so it's going to stay. - // decision needs to be revisited when browsers dont - // accept this any longer - return 'a=candidate:' + sdp.join(' '); -}; - -},{"./senders":24}],15:[function(require,module,exports){ -var WildEmitter = require('wildemitter'); - -function getMaxVolume (analyser, fftBins) { - var maxVolume = -Infinity; - analyser.getFloatFrequencyData(fftBins); - - for(var i=4, ii=fftBins.length; i < ii; i++) { - if (fftBins[i] > maxVolume && fftBins[i] < 0) { - maxVolume = fftBins[i]; - } - }; - - return maxVolume; -} + return maxVolume; +} var audioContextType = window.webkitAudioContext || window.AudioContext; @@ -8646,7 +8435,7 @@ module.exports = function(stream, options) { return harker; } -},{"wildemitter":2}],22:[function(require,module,exports){ +},{"wildemitter":3}],21:[function(require,module,exports){ var SENDERS = require('./senders'); var parsers = require('./parsers'); var idCounter = Math.random(); @@ -8852,7 +8641,223 @@ exports.toCandidateJSON = function (line) { return candidate; }; -},{"./parsers":25,"./senders":24}],24:[function(require,module,exports){ +},{"./parsers":25,"./senders":24}],22:[function(require,module,exports){ +var SENDERS = require('./senders'); + + +exports.toSessionSDP = function (session, opts) { + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + var sid = opts.sid || session.sid || Date.now(); + var time = opts.time || Date.now(); + + var sdp = [ + 'v=0', + 'o=- ' + sid + ' ' + time + ' IN IP4 0.0.0.0', + 's=-', + 't=0 0' + ]; + + var groups = session.groups || []; + groups.forEach(function (group) { + sdp.push('a=group:' + group.semantics + ' ' + group.contents.join(' ')); + }); + + var contents = session.contents || []; + contents.forEach(function (content) { + sdp.push(exports.toMediaSDP(content, opts)); + }); + + return sdp.join('\r\n') + '\r\n'; +}; + +exports.toMediaSDP = function (content, opts) { + var sdp = []; + + var role = opts.role || 'initiator'; + var direction = opts.direction || 'outgoing'; + + var desc = content.description; + var transport = content.transport; + var payloads = desc.payloads || []; + var fingerprints = (transport && transport.fingerprints) || []; + + var mline = []; + if (desc.descType == 'datachannel') { + mline.push('application'); + mline.push('1'); + mline.push('DTLS/SCTP'); + if (transport.sctp) { + transport.sctp.forEach(function (map) { + mline.push(map.number); + }); + } + } else { + mline.push(desc.media); + mline.push('1'); + if ((desc.encryption && desc.encryption.length > 0) || (fingerprints.length > 0)) { + mline.push('RTP/SAVPF'); + } else { + mline.push('RTP/AVPF'); + } + payloads.forEach(function (payload) { + mline.push(payload.id); + }); + } + + + sdp.push('m=' + mline.join(' ')); + + sdp.push('c=IN IP4 0.0.0.0'); + if (desc.bandwidth && desc.bandwidth.type && desc.bandwidth.bandwidth) { + sdp.push('b=' + desc.bandwidth.type + ':' + desc.bandwidth.bandwidth); + } + if (desc.descType == 'rtp') { + sdp.push('a=rtcp:1 IN IP4 0.0.0.0'); + } + + if (transport) { + if (transport.ufrag) { + sdp.push('a=ice-ufrag:' + transport.ufrag); + } + if (transport.pwd) { + sdp.push('a=ice-pwd:' + transport.pwd); + } + + var pushedSetup = false; + fingerprints.forEach(function (fingerprint) { + sdp.push('a=fingerprint:' + fingerprint.hash + ' ' + fingerprint.value); + if (fingerprint.setup && !pushedSetup) { + sdp.push('a=setup:' + fingerprint.setup); + } + }); + + if (transport.sctp) { + transport.sctp.forEach(function (map) { + sdp.push('a=sctpmap:' + map.number + ' ' + map.protocol + ' ' + map.streams); + }); + } + } + + if (desc.descType == 'rtp') { + sdp.push('a=' + (SENDERS[role][direction][content.senders] || 'sendrecv')); + } + sdp.push('a=mid:' + content.name); + + if (desc.mux) { + sdp.push('a=rtcp-mux'); + } + + var encryption = desc.encryption || []; + encryption.forEach(function (crypto) { + sdp.push('a=crypto:' + crypto.tag + ' ' + crypto.cipherSuite + ' ' + crypto.keyParams + (crypto.sessionParams ? ' ' + crypto.sessionParams : '')); + }); + if (desc.googConferenceFlag) { + sdp.push('a=x-google-flag:conference'); + } + + payloads.forEach(function (payload) { + var rtpmap = 'a=rtpmap:' + payload.id + ' ' + payload.name + '/' + payload.clockrate; + if (payload.channels && payload.channels != '1') { + rtpmap += '/' + payload.channels; + } + sdp.push(rtpmap); + + if (payload.parameters && payload.parameters.length) { + var fmtp = ['a=fmtp:' + payload.id]; + var parameters = []; + payload.parameters.forEach(function (param) { + parameters.push((param.key ? param.key + '=' : '') + param.value); + }); + fmtp.push(parameters.join(';')); + sdp.push(fmtp.join(' ')); + } + + if (payload.feedback) { + payload.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:' + payload.id + ' trr-int ' + fb.value ? fb.value : '0'); + } else { + sdp.push('a=rtcp-fb:' + payload.id + ' ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } + }); + + if (desc.feedback) { + desc.feedback.forEach(function (fb) { + if (fb.type === 'trr-int') { + sdp.push('a=rtcp-fb:* trr-int ' + fb.value ? fb.value : '0'); + } else { + sdp.push('a=rtcp-fb:* ' + fb.type + (fb.subtype ? ' ' + fb.subtype : '')); + } + }); + } + + var hdrExts = desc.headerExtensions || []; + hdrExts.forEach(function (hdr) { + sdp.push('a=extmap:' + hdr.id + (hdr.senders ? '/' + SENDERS[role][direction][hdr.senders] : '') + ' ' + hdr.uri); + }); + + var ssrcGroups = desc.sourceGroups || []; + ssrcGroups.forEach(function (ssrcGroup) { + sdp.push('a=ssrc-group:' + ssrcGroup.semantics + ' ' + ssrcGroup.sources.join(' ')); + }); + + var ssrcs = desc.sources || []; + ssrcs.forEach(function (ssrc) { + for (var i = 0; i < ssrc.parameters.length; i++) { + var param = ssrc.parameters[i]; + sdp.push('a=ssrc:' + (ssrc.ssrc || desc.ssrc) + ' ' + param.key + (param.value ? (':' + param.value) : '')); + } + }); + + var candidates = transport.candidates || []; + candidates.forEach(function (candidate) { + sdp.push(exports.toCandidateSDP(candidate)); + }); + + return sdp.join('\r\n'); +}; + +exports.toCandidateSDP = function (candidate) { + var sdp = []; + + sdp.push(candidate.foundation); + sdp.push(candidate.component); + sdp.push(candidate.protocol.toUpperCase()); + sdp.push(candidate.priority); + sdp.push(candidate.ip); + sdp.push(candidate.port); + + var type = candidate.type; + sdp.push('typ'); + sdp.push(type); + if (type === 'srflx' || type === 'prflx' || type === 'relay') { + if (candidate.relAddr && candidate.relPort) { + sdp.push('raddr'); + sdp.push(candidate.relAddr); + sdp.push('rport'); + sdp.push(candidate.relPort); + } + } + if (candidate.tcpType && candidate.protocol.toUpperCase() == 'TCP') { + sdp.push('tcptype'); + sdp.push(candidate.tcpType); + } + + sdp.push('generation'); + sdp.push(candidate.generation || '0'); + + // FIXME: apparently this is wrong per spec + // but then, we need this when actually putting this into + // SDP so it's going to stay. + // decision needs to be revisited when browsers dont + // accept this any longer + return 'a=candidate:' + sdp.join(' '); +}; + +},{"./senders":24}],24:[function(require,module,exports){ module.exports = { initiator: { incoming: { @@ -9398,6 +9403,6 @@ TraceablePeerConnection.prototype.getStats = function (callback, errback) { module.exports = TraceablePeerConnection; -},{"util":8,"webrtcsupport":3,"wildemitter":2}]},{},[1])(1) +},{"util":8,"webrtcsupport":4,"wildemitter":3}]},{},[1])(1) }); ;