From 1a2d406e86ae5a0b714f1962dc7bfc5a09583956 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 29 Dec 2017 16:04:44 -0600 Subject: [PATCH] FS-10862: [freeswitch-core] Updates on webrtc to keep up with browsers #resolve --- html5/verto/js/src/jquery.FSRTC.js | 2 + html5/verto/js/src/vendor/adapter-latest.js | 3785 ++++++++++------- .../video_demo-live_canvas/js/verto-min.js | 317 +- html5/verto/video_demo/js/verto-min.js | 317 +- 4 files changed, 2589 insertions(+), 1832 deletions(-) diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index 39073ecbab..c2ea803d0b 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -684,6 +684,8 @@ } } + config.bundlePolicy = "max-compat"; + var peer = new window.RTCPeerConnection(config); openOffererChannel(); diff --git a/html5/verto/js/src/vendor/adapter-latest.js b/html5/verto/js/src/vendor/adapter-latest.js index 5b32e894af..46242f30c6 100644 --- a/html5/verto/js/src/vendor/adapter-latest.js +++ b/html5/verto/js/src/vendor/adapter-latest.js @@ -1,4 +1,1564 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 14393 && + url.indexOf('?transport=udp') === -1; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + return false; + }); +} + +// Determines the intersection of local and remote capabilities. +function getCommonCapabilities(localCapabilities, remoteCapabilities) { + var commonCapabilities = { + codecs: [], + headerExtensions: [], + fecMechanisms: [] + }; + + var findCodecByPayloadType = function(pt, codecs) { + pt = parseInt(pt, 10); + for (var i = 0; i < codecs.length; i++) { + if (codecs[i].payloadType === pt || + codecs[i].preferredPayloadType === pt) { + return codecs[i]; + } + } + }; + + var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { + var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); + var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); + return lCodec && rCodec && + lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); + }; + + localCapabilities.codecs.forEach(function(lCodec) { + for (var i = 0; i < remoteCapabilities.codecs.length; i++) { + var rCodec = remoteCapabilities.codecs[i]; + if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && + lCodec.clockRate === rCodec.clockRate) { + if (lCodec.name.toLowerCase() === 'rtx' && + lCodec.parameters && rCodec.parameters.apt) { + // for RTX we need to find the local rtx that has a apt + // which points to the same local codec as the remote one. + if (!rtxCapabilityMatches(lCodec, rCodec, + localCapabilities.codecs, remoteCapabilities.codecs)) { + continue; + } + } + rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy + // number of channels is the highest common number of channels + rCodec.numChannels = Math.min(lCodec.numChannels, + rCodec.numChannels); + // push rCodec so we reply with offerer payload type + commonCapabilities.codecs.push(rCodec); + + // determine common feedback mechanisms + rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { + for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { + if (lCodec.rtcpFeedback[j].type === fb.type && + lCodec.rtcpFeedback[j].parameter === fb.parameter) { + return true; + } + } + return false; + }); + // FIXME: also need to determine .parameters + // see https://github.com/openpeer/ortc/issues/569 + break; + } + } + }); + + localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { + for (var i = 0; i < remoteCapabilities.headerExtensions.length; + i++) { + var rHeaderExtension = remoteCapabilities.headerExtensions[i]; + if (lHeaderExtension.uri === rHeaderExtension.uri) { + commonCapabilities.headerExtensions.push(rHeaderExtension); + break; + } + } + }); + + // FIXME: fecMechanisms + return commonCapabilities; +} + +// is action=setLocalDescription with type allowed in signalingState +function isActionAllowedInSignalingState(action, type, signalingState) { + return { + offer: { + setLocalDescription: ['stable', 'have-local-offer'], + setRemoteDescription: ['stable', 'have-remote-offer'] + }, + answer: { + setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], + setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] + } + }[type][action].indexOf(signalingState) !== -1; +} + +function maybeAddCandidate(iceTransport, candidate) { + // Edge's internal representation adds some fields therefore + // not all fieldѕ are taken into account. + var alreadyAdded = iceTransport.getRemoteCandidates() + .find(function(remoteCandidate) { + return candidate.foundation === remoteCandidate.foundation && + candidate.ip === remoteCandidate.ip && + candidate.port === remoteCandidate.port && + candidate.priority === remoteCandidate.priority && + candidate.protocol === remoteCandidate.protocol && + candidate.type === remoteCandidate.type; + }); + if (!alreadyAdded) { + iceTransport.addRemoteCandidate(candidate); + } + return !alreadyAdded; +} + +module.exports = function(window, edgeVersion) { + var RTCPeerConnection = function(config) { + var self = this; + + var _eventTarget = document.createDocumentFragment(); + ['addEventListener', 'removeEventListener', 'dispatchEvent'] + .forEach(function(method) { + self[method] = _eventTarget[method].bind(_eventTarget); + }); + + this.onicecandidate = null; + this.onaddstream = null; + this.ontrack = null; + this.onremovestream = null; + this.onsignalingstatechange = null; + this.oniceconnectionstatechange = null; + this.onicegatheringstatechange = null; + this.onnegotiationneeded = null; + this.ondatachannel = null; + this.canTrickleIceCandidates = null; + + this.needNegotiation = false; + + this.localStreams = []; + this.remoteStreams = []; + + this.localDescription = null; + this.remoteDescription = null; + + this.signalingState = 'stable'; + this.iceConnectionState = 'new'; + this.iceGatheringState = 'new'; + + config = JSON.parse(JSON.stringify(config || {})); + + this.usingBundle = config.bundlePolicy === 'max-bundle'; + if (config.rtcpMuxPolicy === 'negotiate') { + var e = new Error('rtcpMuxPolicy \'negotiate\' is not supported'); + e.name = 'NotSupportedError'; + throw(e); + } else if (!config.rtcpMuxPolicy) { + config.rtcpMuxPolicy = 'require'; + } + + switch (config.iceTransportPolicy) { + case 'all': + case 'relay': + break; + default: + config.iceTransportPolicy = 'all'; + break; + } + + switch (config.bundlePolicy) { + case 'balanced': + case 'max-compat': + case 'max-bundle': + break; + default: + config.bundlePolicy = 'balanced'; + break; + } + + config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); + + this._iceGatherers = []; + if (config.iceCandidatePoolSize) { + for (var i = config.iceCandidatePoolSize; i > 0; i--) { + this._iceGatherers = new window.RTCIceGatherer({ + iceServers: config.iceServers, + gatherPolicy: config.iceTransportPolicy + }); + } + } else { + config.iceCandidatePoolSize = 0; + } + + this._config = config; + + // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... + // everything that is needed to describe a SDP m-line. + this.transceivers = []; + + this._sdpSessionId = SDPUtils.generateSessionId(); + this._sdpSessionVersion = 0; + + this._dtlsRole = undefined; // role for a=setup to use in answers. + }; + + RTCPeerConnection.prototype._emitGatheringStateChange = function() { + var event = new Event('icegatheringstatechange'); + this.dispatchEvent(event); + if (typeof this.onicegatheringstatechange === 'function') { + this.onicegatheringstatechange(event); + } + }; + + RTCPeerConnection.prototype.getConfiguration = function() { + return this._config; + }; + + RTCPeerConnection.prototype.getLocalStreams = function() { + return this.localStreams; + }; + + RTCPeerConnection.prototype.getRemoteStreams = function() { + return this.remoteStreams; + }; + + // internal helper to create a transceiver object. + // (whih is not yet the same as the WebRTC 1.0 transceiver) + RTCPeerConnection.prototype._createTransceiver = function(kind) { + var hasBundleTransport = this.transceivers.length > 0; + var transceiver = { + track: null, + iceGatherer: null, + iceTransport: null, + dtlsTransport: null, + localCapabilities: null, + remoteCapabilities: null, + rtpSender: null, + rtpReceiver: null, + kind: kind, + mid: null, + sendEncodingParameters: null, + recvEncodingParameters: null, + stream: null, + wantReceive: true + }; + if (this.usingBundle && hasBundleTransport) { + transceiver.iceTransport = this.transceivers[0].iceTransport; + transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; + } else { + var transports = this._createIceAndDtlsTransports(); + transceiver.iceTransport = transports.iceTransport; + transceiver.dtlsTransport = transports.dtlsTransport; + } + this.transceivers.push(transceiver); + return transceiver; + }; + + RTCPeerConnection.prototype.addTrack = function(track, stream) { + var transceiver; + for (var i = 0; i < this.transceivers.length; i++) { + if (!this.transceivers[i].track && + this.transceivers[i].kind === track.kind) { + transceiver = this.transceivers[i]; + } + } + if (!transceiver) { + transceiver = this._createTransceiver(track.kind); + } + + this._maybeFireNegotiationNeeded(); + + if (this.localStreams.indexOf(stream) === -1) { + this.localStreams.push(stream); + } + + transceiver.track = track; + transceiver.stream = stream; + transceiver.rtpSender = new window.RTCRtpSender(track, + transceiver.dtlsTransport); + return transceiver.rtpSender; + }; + + RTCPeerConnection.prototype.addStream = function(stream) { + var self = this; + if (edgeVersion >= 15025) { + stream.getTracks().forEach(function(track) { + self.addTrack(track, stream); + }); + } else { + // Clone is necessary for local demos mostly, attaching directly + // to two different senders does not work (build 10547). + // Fixed in 15025 (or earlier) + var clonedStream = stream.clone(); + stream.getTracks().forEach(function(track, idx) { + var clonedTrack = clonedStream.getTracks()[idx]; + track.addEventListener('enabled', function(event) { + clonedTrack.enabled = event.enabled; + }); + }); + clonedStream.getTracks().forEach(function(track) { + self.addTrack(track, clonedStream); + }); + } + }; + + RTCPeerConnection.prototype.removeStream = function(stream) { + var idx = this.localStreams.indexOf(stream); + if (idx > -1) { + this.localStreams.splice(idx, 1); + this._maybeFireNegotiationNeeded(); + } + }; + + RTCPeerConnection.prototype.getSenders = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpSender; + }) + .map(function(transceiver) { + return transceiver.rtpSender; + }); + }; + + RTCPeerConnection.prototype.getReceivers = function() { + return this.transceivers.filter(function(transceiver) { + return !!transceiver.rtpReceiver; + }) + .map(function(transceiver) { + return transceiver.rtpReceiver; + }); + }; + + + RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, + usingBundle) { + var self = this; + if (usingBundle && sdpMLineIndex > 0) { + return this.transceivers[0].iceGatherer; + } else if (this._iceGatherers.length) { + return this._iceGatherers.shift(); + } + var iceGatherer = new window.RTCIceGatherer({ + iceServers: this._config.iceServers, + gatherPolicy: this._config.iceTransportPolicy + }); + Object.defineProperty(iceGatherer, 'state', + {value: 'new', writable: true} + ); + + this.transceivers[sdpMLineIndex].candidates = []; + this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { + var end = !event.candidate || Object.keys(event.candidate).length === 0; + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + iceGatherer.state = end ? 'completed' : 'gathering'; + if (self.transceivers[sdpMLineIndex].candidates !== null) { + self.transceivers[sdpMLineIndex].candidates.push(event.candidate); + } + }; + iceGatherer.addEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + return iceGatherer; + }; + + // start gathering from an RTCIceGatherer. + RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { + var self = this; + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer.onlocalcandidate) { + return; + } + var candidates = this.transceivers[sdpMLineIndex].candidates; + this.transceivers[sdpMLineIndex].candidates = null; + iceGatherer.removeEventListener('localcandidate', + this.transceivers[sdpMLineIndex].bufferCandidates); + iceGatherer.onlocalcandidate = function(evt) { + if (self.usingBundle && sdpMLineIndex > 0) { + // if we know that we use bundle we can drop candidates with + // ѕdpMLineIndex > 0. If we don't do this then our state gets + // confused since we dispose the extra ice gatherer. + return; + } + var event = new Event('icecandidate'); + event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; + + var cand = evt.candidate; + // Edge emits an empty object for RTCIceCandidateComplete‥ + var end = !cand || Object.keys(cand).length === 0; + if (end) { + // polyfill since RTCIceGatherer.state is not implemented in + // Edge 10547 yet. + if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { + iceGatherer.state = 'completed'; + } + } else { + if (iceGatherer.state === 'new') { + iceGatherer.state = 'gathering'; + } + // RTCIceCandidate doesn't have a component, needs to be added + cand.component = 1; + event.candidate.candidate = SDPUtils.writeCandidate(cand); + } + + // update local description. + var sections = SDPUtils.splitSections(self.localDescription.sdp); + if (!end) { + sections[event.candidate.sdpMLineIndex + 1] += + 'a=' + event.candidate.candidate + '\r\n'; + } else { + sections[event.candidate.sdpMLineIndex + 1] += + 'a=end-of-candidates\r\n'; + } + self.localDescription.sdp = sections.join(''); + var complete = self.transceivers.every(function(transceiver) { + return transceiver.iceGatherer && + transceiver.iceGatherer.state === 'completed'; + }); + + if (self.iceGatheringState !== 'gathering') { + self.iceGatheringState = 'gathering'; + self._emitGatheringStateChange(); + } + + // Emit candidate. Also emit null candidate when all gatherers are + // complete. + if (!end) { + self.dispatchEvent(event); + if (typeof self.onicecandidate === 'function') { + self.onicecandidate(event); + } + } + if (complete) { + self.dispatchEvent(new Event('icecandidate')); + if (typeof self.onicecandidate === 'function') { + self.onicecandidate(new Event('icecandidate')); + } + self.iceGatheringState = 'complete'; + self._emitGatheringStateChange(); + } + }; + + // emit already gathered candidates. + window.setTimeout(function() { + candidates.forEach(function(candidate) { + var e = new Event('RTCIceGatherEvent'); + e.candidate = candidate; + iceGatherer.onlocalcandidate(e); + }); + }, 0); + }; + + // Create ICE transport and DTLS transport. + RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { + var self = this; + var iceTransport = new window.RTCIceTransport(null); + iceTransport.onicestatechange = function() { + self._updateConnectionState(); + }; + + var dtlsTransport = new window.RTCDtlsTransport(iceTransport); + dtlsTransport.ondtlsstatechange = function() { + self._updateConnectionState(); + }; + dtlsTransport.onerror = function() { + // onerror does not set state to failed by itself. + Object.defineProperty(dtlsTransport, 'state', + {value: 'failed', writable: true}); + self._updateConnectionState(); + }; + + return { + iceTransport: iceTransport, + dtlsTransport: dtlsTransport + }; + }; + + // Destroy ICE gatherer, ICE transport and DTLS transport. + // Without triggering the callbacks. + RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( + sdpMLineIndex) { + var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; + if (iceGatherer) { + delete iceGatherer.onlocalcandidate; + delete this.transceivers[sdpMLineIndex].iceGatherer; + } + var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; + if (iceTransport) { + delete iceTransport.onicestatechange; + delete this.transceivers[sdpMLineIndex].iceTransport; + } + var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; + if (dtlsTransport) { + delete dtlsTransport.ondtlsstatechange; + delete dtlsTransport.onerror; + delete this.transceivers[sdpMLineIndex].dtlsTransport; + } + }; + + // Start the RTP Sender and Receiver for a transceiver. + RTCPeerConnection.prototype._transceive = function(transceiver, + send, recv) { + var params = getCommonCapabilities(transceiver.localCapabilities, + transceiver.remoteCapabilities); + if (send && transceiver.rtpSender) { + params.encodings = transceiver.sendEncodingParameters; + params.rtcp = { + cname: SDPUtils.localCName, + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.recvEncodingParameters.length) { + params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; + } + transceiver.rtpSender.send(params); + } + if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { + // remove RTX field in Edge 14942 + if (transceiver.kind === 'video' + && transceiver.recvEncodingParameters + && edgeVersion < 15019) { + transceiver.recvEncodingParameters.forEach(function(p) { + delete p.rtx; + }); + } + params.encodings = transceiver.recvEncodingParameters; + params.rtcp = { + cname: transceiver.rtcpParameters.cname, + compound: transceiver.rtcpParameters.compound + }; + if (transceiver.sendEncodingParameters.length) { + params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; + } + transceiver.rtpReceiver.receive(params); + } + }; + + RTCPeerConnection.prototype.setLocalDescription = function(description) { + var self = this; + var args = arguments; + + if (!isActionAllowedInSignalingState('setLocalDescription', + description.type, this.signalingState)) { + return new Promise(function(resolve, reject) { + var e = new Error('Can not set local ' + description.type + + ' in state ' + self.signalingState); + e.name = 'InvalidStateError'; + if (args.length > 2 && typeof args[2] === 'function') { + args[2].apply(null, [e]); + } + reject(e); + }); + } + + var sections; + var sessionpart; + if (description.type === 'offer') { + // VERY limited support for SDP munging. Limited to: + // * changing the order of codecs + sections = SDPUtils.splitSections(description.sdp); + sessionpart = sections.shift(); + sections.forEach(function(mediaSection, sdpMLineIndex) { + var caps = SDPUtils.parseRtpParameters(mediaSection); + self.transceivers[sdpMLineIndex].localCapabilities = caps; + }); + + this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + self._gather(transceiver.mid, sdpMLineIndex); + }); + } else if (description.type === 'answer') { + sections = SDPUtils.splitSections(self.remoteDescription.sdp); + sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + sections.forEach(function(mediaSection, sdpMLineIndex) { + var transceiver = self.transceivers[sdpMLineIndex]; + var iceGatherer = transceiver.iceGatherer; + var iceTransport = transceiver.iceTransport; + var dtlsTransport = transceiver.dtlsTransport; + var localCapabilities = transceiver.localCapabilities; + var remoteCapabilities = transceiver.remoteCapabilities; + + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + !SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 1; + + if (!rejected && !transceiver.isDatachannel) { + var remoteIceParameters = SDPUtils.getIceParameters( + mediaSection, sessionpart); + var remoteDtlsParameters = SDPUtils.getDtlsParameters( + mediaSection, sessionpart); + if (isIceLite) { + remoteDtlsParameters.role = 'server'; + } + + if (!self.usingBundle || sdpMLineIndex === 0) { + self._gather(transceiver.mid, sdpMLineIndex); + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + isIceLite ? 'controlling' : 'controlled'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + // Calculate intersection of capabilities. + var params = getCommonCapabilities(localCapabilities, + remoteCapabilities); + + // Start the RTCRtpSender. The RTCRtpReceiver for this + // transceiver has already been started in setRemoteDescription. + self._transceive(transceiver, + params.codecs.length > 0, + false); + } + }); + } + + this.localDescription = { + type: description.type, + sdp: description.sdp + }; + switch (description.type) { + case 'offer': + this._updateSignalingState('have-local-offer'); + break; + case 'answer': + this._updateSignalingState('stable'); + break; + default: + throw new TypeError('unsupported type "' + description.type + + '"'); + } + + // If a success callback was provided, emit ICE candidates after it + // has been executed. Otherwise, emit callback after the Promise is + // resolved. + var cb = arguments.length > 1 && typeof arguments[1] === 'function' && + arguments[1]; + return new Promise(function(resolve) { + if (cb) { + cb.apply(null); + } + resolve(); + }); + }; + + RTCPeerConnection.prototype.setRemoteDescription = function(description) { + var self = this; + var args = arguments; + + if (!isActionAllowedInSignalingState('setRemoteDescription', + description.type, this.signalingState)) { + return new Promise(function(resolve, reject) { + var e = new Error('Can not set remote ' + description.type + + ' in state ' + self.signalingState); + e.name = 'InvalidStateError'; + if (args.length > 2 && typeof args[2] === 'function') { + args[2].apply(null, [e]); + } + reject(e); + }); + } + + var streams = {}; + this.remoteStreams.forEach(function(stream) { + streams[stream.id] = stream; + }); + var receiverList = []; + var sections = SDPUtils.splitSections(description.sdp); + var sessionpart = sections.shift(); + var isIceLite = SDPUtils.matchPrefix(sessionpart, + 'a=ice-lite').length > 0; + var usingBundle = SDPUtils.matchPrefix(sessionpart, + 'a=group:BUNDLE ').length > 0; + this.usingBundle = usingBundle; + var iceOptions = SDPUtils.matchPrefix(sessionpart, + 'a=ice-options:')[0]; + if (iceOptions) { + this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') + .indexOf('trickle') >= 0; + } else { + this.canTrickleIceCandidates = false; + } + + sections.forEach(function(mediaSection, sdpMLineIndex) { + var lines = SDPUtils.splitLines(mediaSection); + var kind = SDPUtils.getKind(mediaSection); + // treat bundle-only as not-rejected. + var rejected = SDPUtils.isRejected(mediaSection) && + !SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 1; + var protocol = lines[0].substr(2).split(' ')[2]; + + var direction = SDPUtils.getDirection(mediaSection, sessionpart); + var remoteMsid = SDPUtils.parseMsid(mediaSection); + + var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); + + // Reject datachannels which are not implemented yet. + if (kind === 'application' && protocol === 'DTLS/SCTP') { + self.transceivers[sdpMLineIndex] = { + mid: mid, + isDatachannel: true + }; + return; + } + + var transceiver; + var iceGatherer; + var iceTransport; + var dtlsTransport; + var rtpReceiver; + var sendEncodingParameters; + var recvEncodingParameters; + var localCapabilities; + + var track; + // FIXME: ensure the mediaSection has rtcp-mux set. + var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); + var remoteIceParameters; + var remoteDtlsParameters; + if (!rejected) { + remoteIceParameters = SDPUtils.getIceParameters(mediaSection, + sessionpart); + remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, + sessionpart); + remoteDtlsParameters.role = 'client'; + } + recvEncodingParameters = + SDPUtils.parseRtpEncodingParameters(mediaSection); + + var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); + + var isComplete = SDPUtils.matchPrefix(mediaSection, + 'a=end-of-candidates', sessionpart).length > 0; + var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') + .map(function(cand) { + return SDPUtils.parseCandidate(cand); + }) + .filter(function(cand) { + return cand.component === 1; + }); + + // Check if we can use BUNDLE and dispose transports. + if ((description.type === 'offer' || description.type === 'answer') && + !rejected && usingBundle && sdpMLineIndex > 0 && + self.transceivers[sdpMLineIndex]) { + self._disposeIceAndDtlsTransports(sdpMLineIndex); + self.transceivers[sdpMLineIndex].iceGatherer = + self.transceivers[0].iceGatherer; + self.transceivers[sdpMLineIndex].iceTransport = + self.transceivers[0].iceTransport; + self.transceivers[sdpMLineIndex].dtlsTransport = + self.transceivers[0].dtlsTransport; + if (self.transceivers[sdpMLineIndex].rtpSender) { + self.transceivers[sdpMLineIndex].rtpSender.setTransport( + self.transceivers[0].dtlsTransport); + } + if (self.transceivers[sdpMLineIndex].rtpReceiver) { + self.transceivers[sdpMLineIndex].rtpReceiver.setTransport( + self.transceivers[0].dtlsTransport); + } + } + if (description.type === 'offer' && !rejected) { + transceiver = self.transceivers[sdpMLineIndex] || + self._createTransceiver(kind); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = self._createIceGatherer(sdpMLineIndex, + usingBundle); + } + + if (cands.length && transceiver.iceTransport.state === 'new') { + if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { + transceiver.iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); + + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + + sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 2) * 1001 + }]; + + var isNewTrack = false; + if (direction === 'sendrecv' || direction === 'sendonly') { + isNewTrack = !transceiver.rtpReceiver; + rtpReceiver = transceiver.rtpReceiver || + new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); + + if (isNewTrack) { + var stream; + track = rtpReceiver.track; + // FIXME: does not work with Plan B. + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + Object.defineProperty(streams[remoteMsid.stream], 'id', { + get: function() { + return remoteMsid.stream; + } + }); + } + Object.defineProperty(track, 'id', { + get: function() { + return remoteMsid.track; + } + }); + stream = streams[remoteMsid.stream]; + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + stream = streams.default; + } + stream.addTrack(track); + receiverList.push([track, rtpReceiver, stream]); + } + } + + transceiver.localCapabilities = localCapabilities; + transceiver.remoteCapabilities = remoteCapabilities; + transceiver.rtpReceiver = rtpReceiver; + transceiver.rtcpParameters = rtcpParameters; + transceiver.sendEncodingParameters = sendEncodingParameters; + transceiver.recvEncodingParameters = recvEncodingParameters; + + // Start the RTCRtpReceiver now. The RTPSender is started in + // setLocalDescription. + self._transceive(self.transceivers[sdpMLineIndex], + false, + isNewTrack); + } else if (description.type === 'answer' && !rejected) { + transceiver = self.transceivers[sdpMLineIndex]; + iceGatherer = transceiver.iceGatherer; + iceTransport = transceiver.iceTransport; + dtlsTransport = transceiver.dtlsTransport; + rtpReceiver = transceiver.rtpReceiver; + sendEncodingParameters = transceiver.sendEncodingParameters; + localCapabilities = transceiver.localCapabilities; + + self.transceivers[sdpMLineIndex].recvEncodingParameters = + recvEncodingParameters; + self.transceivers[sdpMLineIndex].remoteCapabilities = + remoteCapabilities; + self.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; + + if (cands.length && iceTransport.state === 'new') { + if ((isIceLite || isComplete) && + (!usingBundle || sdpMLineIndex === 0)) { + iceTransport.setRemoteCandidates(cands); + } else { + cands.forEach(function(candidate) { + maybeAddCandidate(transceiver.iceTransport, candidate); + }); + } + } + + if (!usingBundle || sdpMLineIndex === 0) { + if (iceTransport.state === 'new') { + iceTransport.start(iceGatherer, remoteIceParameters, + 'controlling'); + } + if (dtlsTransport.state === 'new') { + dtlsTransport.start(remoteDtlsParameters); + } + } + + self._transceive(transceiver, + direction === 'sendrecv' || direction === 'recvonly', + direction === 'sendrecv' || direction === 'sendonly'); + + if (rtpReceiver && + (direction === 'sendrecv' || direction === 'sendonly')) { + track = rtpReceiver.track; + if (remoteMsid) { + if (!streams[remoteMsid.stream]) { + streams[remoteMsid.stream] = new window.MediaStream(); + } + streams[remoteMsid.stream].addTrack(track); + receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); + } else { + if (!streams.default) { + streams.default = new window.MediaStream(); + } + streams.default.addTrack(track); + receiverList.push([track, rtpReceiver, streams.default]); + } + } else { + // FIXME: actually the receiver should be created later. + delete transceiver.rtpReceiver; + } + } + }); + + if (this._dtlsRole === undefined) { + this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; + } + + this.remoteDescription = { + type: description.type, + sdp: description.sdp + }; + switch (description.type) { + case 'offer': + this._updateSignalingState('have-remote-offer'); + break; + case 'answer': + this._updateSignalingState('stable'); + break; + default: + throw new TypeError('unsupported type "' + description.type + + '"'); + } + Object.keys(streams).forEach(function(sid) { + var stream = streams[sid]; + if (stream.getTracks().length) { + if (self.remoteStreams.indexOf(stream) === -1) { + self.remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + window.setTimeout(function() { + self.dispatchEvent(event); + if (typeof self.onaddstream === 'function') { + self.onaddstream(event); + } + }); + } + + receiverList.forEach(function(item) { + var track = item[0]; + var receiver = item[1]; + if (stream.id !== item[2].id) { + return; + } + var trackEvent = new Event('track'); + trackEvent.track = track; + trackEvent.receiver = receiver; + trackEvent.transceiver = {receiver: receiver}; + trackEvent.streams = [stream]; + window.setTimeout(function() { + self.dispatchEvent(trackEvent); + if (typeof self.ontrack === 'function') { + self.ontrack(trackEvent); + } + }); + }); + } + }); + + // check whether addIceCandidate({}) was called within four seconds after + // setRemoteDescription. + window.setTimeout(function() { + if (!(self && self.transceivers)) { + return; + } + self.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && + transceiver.iceTransport.state === 'new' && + transceiver.iceTransport.getRemoteCandidates().length > 0) { + console.warn('Timeout for addRemoteCandidate. Consider sending ' + + 'an end-of-candidates notification'); + transceiver.iceTransport.addRemoteCandidate({}); + } + }); + }, 4000); + + return new Promise(function(resolve) { + if (args.length > 1 && typeof args[1] === 'function') { + args[1].apply(null); + } + resolve(); + }); + }; + + RTCPeerConnection.prototype.close = function() { + this.transceivers.forEach(function(transceiver) { + /* not yet + if (transceiver.iceGatherer) { + transceiver.iceGatherer.close(); + } + */ + if (transceiver.iceTransport) { + transceiver.iceTransport.stop(); + } + if (transceiver.dtlsTransport) { + transceiver.dtlsTransport.stop(); + } + if (transceiver.rtpSender) { + transceiver.rtpSender.stop(); + } + if (transceiver.rtpReceiver) { + transceiver.rtpReceiver.stop(); + } + }); + // FIXME: clean up tracks, local streams, remote streams, etc + this._updateSignalingState('closed'); + }; + + // Update the signaling state. + RTCPeerConnection.prototype._updateSignalingState = function(newState) { + this.signalingState = newState; + var event = new Event('signalingstatechange'); + this.dispatchEvent(event); + if (typeof this.onsignalingstatechange === 'function') { + this.onsignalingstatechange(event); + } + }; + + // Determine whether to fire the negotiationneeded event. + RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { + var self = this; + if (this.signalingState !== 'stable' || this.needNegotiation === true) { + return; + } + this.needNegotiation = true; + window.setTimeout(function() { + if (self.needNegotiation === false) { + return; + } + self.needNegotiation = false; + var event = new Event('negotiationneeded'); + self.dispatchEvent(event); + if (typeof self.onnegotiationneeded === 'function') { + self.onnegotiationneeded(event); + } + }, 0); + }; + + // Update the connection state. + RTCPeerConnection.prototype._updateConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + connecting: 0, + checking: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + states[transceiver.iceTransport.state]++; + states[transceiver.dtlsTransport.state]++; + }); + // ICETransport.completed and connected are the same for this purpose. + states.connected += states.completed; + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.connecting > 0 || states.checking > 0) { + newState = 'connecting'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0 || states.completed > 0) { + newState = 'connected'; + } + + if (newState !== this.iceConnectionState) { + this.iceConnectionState = newState; + var event = new Event('iceconnectionstatechange'); + this.dispatchEvent(event); + if (typeof this.oniceconnectionstatechange === 'function') { + this.oniceconnectionstatechange(event); + } + } + }; + + RTCPeerConnection.prototype.createOffer = function() { + var self = this; + var args = arguments; + + var offerOptions; + if (arguments.length === 1 && typeof arguments[0] !== 'function') { + offerOptions = arguments[0]; + } else if (arguments.length === 3) { + offerOptions = arguments[2]; + } + + var numAudioTracks = this.transceivers.filter(function(t) { + return t.kind === 'audio'; + }).length; + var numVideoTracks = this.transceivers.filter(function(t) { + return t.kind === 'video'; + }).length; + + // Determine number of audio and video tracks we need to send/recv. + if (offerOptions) { + // Reject Chrome legacy constraints. + if (offerOptions.mandatory || offerOptions.optional) { + throw new TypeError( + 'Legacy mandatory/optional constraints not supported.'); + } + if (offerOptions.offerToReceiveAudio !== undefined) { + if (offerOptions.offerToReceiveAudio === true) { + numAudioTracks = 1; + } else if (offerOptions.offerToReceiveAudio === false) { + numAudioTracks = 0; + } else { + numAudioTracks = offerOptions.offerToReceiveAudio; + } + } + if (offerOptions.offerToReceiveVideo !== undefined) { + if (offerOptions.offerToReceiveVideo === true) { + numVideoTracks = 1; + } else if (offerOptions.offerToReceiveVideo === false) { + numVideoTracks = 0; + } else { + numVideoTracks = offerOptions.offerToReceiveVideo; + } + } + } + + this.transceivers.forEach(function(transceiver) { + if (transceiver.kind === 'audio') { + numAudioTracks--; + if (numAudioTracks < 0) { + transceiver.wantReceive = false; + } + } else if (transceiver.kind === 'video') { + numVideoTracks--; + if (numVideoTracks < 0) { + transceiver.wantReceive = false; + } + } + }); + + // Create M-lines for recvonly streams. + while (numAudioTracks > 0 || numVideoTracks > 0) { + if (numAudioTracks > 0) { + this._createTransceiver('audio'); + numAudioTracks--; + } + if (numVideoTracks > 0) { + this._createTransceiver('video'); + numVideoTracks--; + } + } + + var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, + this._sdpSessionVersion++); + this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + // For each track, create an ice gatherer, ice transport, + // dtls transport, potentially rtpsender and rtpreceiver. + var track = transceiver.track; + var kind = transceiver.kind; + var mid = SDPUtils.generateIdentifier(); + transceiver.mid = mid; + + if (!transceiver.iceGatherer) { + transceiver.iceGatherer = self._createIceGatherer(sdpMLineIndex, + self.usingBundle); + } + + var localCapabilities = window.RTCRtpSender.getCapabilities(kind); + // filter RTX until additional stuff needed for RTX is implemented + // in adapter.js + if (edgeVersion < 15019) { + localCapabilities.codecs = localCapabilities.codecs.filter( + function(codec) { + return codec.name !== 'rtx'; + }); + } + localCapabilities.codecs.forEach(function(codec) { + // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 + // by adding level-asymmetry-allowed=1 + if (codec.name === 'H264' && + codec.parameters['level-asymmetry-allowed'] === undefined) { + codec.parameters['level-asymmetry-allowed'] = '1'; + } + }); + + // generate an ssrc now, to be used later in rtpSender.send + var sendEncodingParameters = transceiver.sendEncodingParameters || [{ + ssrc: (2 * sdpMLineIndex + 1) * 1001 + }]; + if (track) { + // add RTX + if (edgeVersion >= 15019 && kind === 'video' && + !sendEncodingParameters[0].rtx) { + sendEncodingParameters[0].rtx = { + ssrc: sendEncodingParameters[0].ssrc + 1 + }; + } + } + + if (transceiver.wantReceive) { + transceiver.rtpReceiver = new window.RTCRtpReceiver( + transceiver.dtlsTransport, kind); + } + + transceiver.localCapabilities = localCapabilities; + transceiver.sendEncodingParameters = sendEncodingParameters; + }); + + // always offer BUNDLE and dispose on return if not supported. + if (this._config.bundlePolicy !== 'max-compat') { + sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + sdp += 'a=ice-options:trickle\r\n'; + + this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + sdp += writeMediaSection(transceiver, transceiver.localCapabilities, + 'offer', transceiver.stream, self._dtlsRole); + sdp += 'a=rtcp-rsize\r\n'; + + if (transceiver.iceGatherer && self.iceGatheringState !== 'new' && + (sdpMLineIndex === 0 || !self.usingBundle)) { + transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { + cand.component = 1; + sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; + }); + + if (transceiver.iceGatherer.state === 'completed') { + sdp += 'a=end-of-candidates\r\n'; + } + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'offer', + sdp: sdp + }); + return new Promise(function(resolve) { + if (args.length > 0 && typeof args[0] === 'function') { + args[0].apply(null, [desc]); + resolve(); + return; + } + resolve(desc); + }); + }; + + RTCPeerConnection.prototype.createAnswer = function() { + var self = this; + var args = arguments; + + var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, + this._sdpSessionVersion++); + if (this.usingBundle) { + sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { + return t.mid; + }).join(' ') + '\r\n'; + } + var mediaSectionsInOffer = SDPUtils.splitSections( + this.remoteDescription.sdp).length - 1; + this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + if (sdpMLineIndex + 1 > mediaSectionsInOffer) { + return; + } + if (transceiver.isDatachannel) { + sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + + 'c=IN IP4 0.0.0.0\r\n' + + 'a=mid:' + transceiver.mid + '\r\n'; + return; + } + + // FIXME: look at direction. + if (transceiver.stream) { + var localTrack; + if (transceiver.kind === 'audio') { + localTrack = transceiver.stream.getAudioTracks()[0]; + } else if (transceiver.kind === 'video') { + localTrack = transceiver.stream.getVideoTracks()[0]; + } + if (localTrack) { + // add RTX + if (edgeVersion >= 15019 && transceiver.kind === 'video' && + !transceiver.sendEncodingParameters[0].rtx) { + transceiver.sendEncodingParameters[0].rtx = { + ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 + }; + } + } + } + + // Calculate intersection of capabilities. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + + sdp += writeMediaSection(transceiver, commonCapabilities, + 'answer', transceiver.stream, self._dtlsRole); + if (transceiver.rtcpParameters && + transceiver.rtcpParameters.reducedSize) { + sdp += 'a=rtcp-rsize\r\n'; + } + }); + + var desc = new window.RTCSessionDescription({ + type: 'answer', + sdp: sdp + }); + return new Promise(function(resolve) { + if (args.length > 0 && typeof args[0] === 'function') { + args[0].apply(null, [desc]); + resolve(); + return; + } + resolve(desc); + }); + }; + + RTCPeerConnection.prototype.addIceCandidate = function(candidate) { + var err; + var sections; + if (!candidate || candidate.candidate === '') { + for (var j = 0; j < this.transceivers.length; j++) { + if (this.transceivers[j].isDatachannel) { + continue; + } + this.transceivers[j].iceTransport.addRemoteCandidate({}); + sections = SDPUtils.splitSections(this.remoteDescription.sdp); + sections[j + 1] += 'a=end-of-candidates\r\n'; + this.remoteDescription.sdp = sections.join(''); + if (this.usingBundle) { + break; + } + } + } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { + throw new TypeError('sdpMLineIndex or sdpMid required'); + } else if (!this.remoteDescription) { + err = new Error('Can not add ICE candidate without ' + + 'a remote description'); + err.name = 'InvalidStateError'; + } else { + var sdpMLineIndex = candidate.sdpMLineIndex; + if (candidate.sdpMid) { + for (var i = 0; i < this.transceivers.length; i++) { + if (this.transceivers[i].mid === candidate.sdpMid) { + sdpMLineIndex = i; + break; + } + } + } + var transceiver = this.transceivers[sdpMLineIndex]; + if (transceiver) { + if (transceiver.isDatachannel) { + return Promise.resolve(); + } + var cand = Object.keys(candidate.candidate).length > 0 ? + SDPUtils.parseCandidate(candidate.candidate) : {}; + // Ignore Chrome's invalid candidates since Edge does not like them. + if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { + return Promise.resolve(); + } + // Ignore RTCP candidates, we assume RTCP-MUX. + if (cand.component && cand.component !== 1) { + return Promise.resolve(); + } + // when using bundle, avoid adding candidates to the wrong + // ice transport. And avoid adding candidates added in the SDP. + if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && + transceiver.iceTransport !== this.transceivers[0].iceTransport)) { + if (!maybeAddCandidate(transceiver.iceTransport, cand)) { + err = new Error('Can not add ICE candidate'); + err.name = 'OperationError'; + } + } + + if (!err) { + // update the remoteDescription. + var candidateString = candidate.candidate.trim(); + if (candidateString.indexOf('a=') === 0) { + candidateString = candidateString.substr(2); + } + sections = SDPUtils.splitSections(this.remoteDescription.sdp); + sections[sdpMLineIndex + 1] += 'a=' + + (cand.type ? candidateString : 'end-of-candidates') + + '\r\n'; + this.remoteDescription.sdp = sections.join(''); + } + } else { + err = new Error('Can not add ICE candidate'); + err.name = 'OperationError'; + } + } + var args = arguments; + return new Promise(function(resolve, reject) { + if (err) { + if (args.length > 2 && typeof args[2] === 'function') { + args[2].apply(null, [err]); + } + reject(err); + } else { + if (args.length > 1 && typeof args[1] === 'function') { + args[1].apply(null); + } + resolve(); + } + }); + }; + + RTCPeerConnection.prototype.getStats = function() { + var promises = []; + this.transceivers.forEach(function(transceiver) { + ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', + 'dtlsTransport'].forEach(function(method) { + if (transceiver[method]) { + promises.push(transceiver[method].getStats()); + } + }); + }); + var cb = arguments.length > 1 && typeof arguments[1] === 'function' && + arguments[1]; + var fixStatsType = function(stat) { + return { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[stat.type] || stat.type; + }; + return new Promise(function(resolve) { + // shim getStats with maplike support + var results = new Map(); + Promise.all(promises).then(function(res) { + res.forEach(function(result) { + Object.keys(result).forEach(function(id) { + result[id].type = fixStatsType(result[id]); + results.set(id, result[id]); + }); + }); + if (cb) { + cb.apply(null, results); + } + resolve(results); + }); + }); + }; + return RTCPeerConnection; +}; + +},{"sdp":2}],2:[function(require,module,exports){ /* eslint-env node */ 'use strict'; @@ -69,6 +1629,10 @@ SDPUtils.parseCandidate = function(line) { case 'tcptype': candidate.tcpType = parts[i + 1]; break; + case 'ufrag': + candidate.ufrag = parts[i + 1]; // for backward compability. + candidate.usernameFragment = parts[i + 1]; + break; default: // extension handling, in particular ufrag candidate[parts[i]] = parts[i + 1]; break; @@ -529,8 +2093,10 @@ SDPUtils.generateSessionId = function() { // Write boilder plate for start of SDP // sessId argument is optional - if not supplied it will // be generated randomly -SDPUtils.writeSessionBoilerplate = function(sessId) { +// sessVersion is optional and defaults to 2 +SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { var sessionId; + var version = sessVer !== undefined ? sessVer : 2; if (sessId) { sessionId = sessId; } else { @@ -538,7 +2104,7 @@ SDPUtils.writeSessionBoilerplate = function(sessId) { } // FIXME: sess-id should be an NTP timestamp. return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' 2 IN IP4 127.0.0.1\r\n' + + 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; }; @@ -628,10 +2194,23 @@ SDPUtils.isRejected = function(mediaSection) { return mediaSection.split(' ', 2)[1] === '0'; }; -// Expose public methods. -module.exports = SDPUtils; +SDPUtils.parseMLine = function(mediaSection) { + var lines = SDPUtils.splitLines(mediaSection); + var mline = lines[0].split(' '); + return { + kind: mline[0].substr(2), + port: parseInt(mline[1], 10), + protocol: mline[2], + fmt: mline.slice(3).join(' ') + }; +}; -},{}],2:[function(require,module,exports){ +// Expose public methods. +if (typeof module === 'object') { + module.exports = SDPUtils; +} + +},{}],3:[function(require,module,exports){ (function (global){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. @@ -648,7 +2227,7 @@ var adapterFactory = require('./adapter_factory.js'); module.exports = adapterFactory({window: global.window}); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":3}],3:[function(require,module,exports){ +},{"./adapter_factory.js":4}],4:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -660,12 +2239,25 @@ module.exports = adapterFactory({window: global.window}); 'use strict'; +var utils = require('./utils'); // Shimming starts here. -module.exports = function(dependencies) { +module.exports = function(dependencies, opts) { var window = dependencies && dependencies.window; + var options = { + shimChrome: true, + shimFirefox: true, + shimEdge: true, + shimSafari: true, + }; + + for (var key in opts) { + if (hasOwnProperty.call(opts, key)) { + options[key] = opts[key]; + } + } + // Utils. - var utils = require('./utils'); var logging = utils.log; var browserDetails = utils.detectBrowser(window); @@ -688,70 +2280,85 @@ module.exports = function(dependencies) { var edgeShim = require('./edge/edge_shim') || null; var firefoxShim = require('./firefox/firefox_shim') || null; var safariShim = require('./safari/safari_shim') || null; + var commonShim = require('./common_shim') || null; // Shim browser if found. switch (browserDetails.browser) { case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection) { + if (!chromeShim || !chromeShim.shimPeerConnection || + !options.shimChrome) { logging('Chrome shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming chrome.'); // Export to the adapter global object visible in the browser. adapter.browserShim = chromeShim; + commonShim.shimCreateObjectURL(window); chromeShim.shimGetUserMedia(window); chromeShim.shimMediaStream(window); - utils.shimCreateObjectURL(window); chromeShim.shimSourceObject(window); chromeShim.shimPeerConnection(window); chromeShim.shimOnTrack(window); + chromeShim.shimAddTrackRemoveTrack(window); chromeShim.shimGetSendersWithDtmf(window); + + commonShim.shimRTCIceCandidate(window); break; case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection) { + if (!firefoxShim || !firefoxShim.shimPeerConnection || + !options.shimFirefox) { logging('Firefox shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming firefox.'); // Export to the adapter global object visible in the browser. adapter.browserShim = firefoxShim; + commonShim.shimCreateObjectURL(window); firefoxShim.shimGetUserMedia(window); - utils.shimCreateObjectURL(window); firefoxShim.shimSourceObject(window); firefoxShim.shimPeerConnection(window); firefoxShim.shimOnTrack(window); + firefoxShim.shimRemoveStream(window); + + commonShim.shimRTCIceCandidate(window); break; case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection) { + if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { logging('MS edge shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming edge.'); // Export to the adapter global object visible in the browser. adapter.browserShim = edgeShim; + commonShim.shimCreateObjectURL(window); edgeShim.shimGetUserMedia(window); - utils.shimCreateObjectURL(window); edgeShim.shimPeerConnection(window); edgeShim.shimReplaceTrack(window); + + // the edge shim implements the full RTCIceCandidate object. break; case 'safari': - if (!safariShim) { + if (!safariShim || !options.shimSafari) { logging('Safari shim is not included in this adapter release.'); return adapter; } logging('adapter.js shimming safari.'); // Export to the adapter global object visible in the browser. adapter.browserShim = safariShim; - // shim window.URL.createObjectURL Safari (technical preview) - utils.shimCreateObjectURL(window); + commonShim.shimCreateObjectURL(window); + safariShim.shimRTCIceServerUrls(window); safariShim.shimCallbacksAPI(window); safariShim.shimLocalStreamsAPI(window); safariShim.shimRemoteStreamsAPI(window); + safariShim.shimTrackEventTransceiver(window); safariShim.shimGetUserMedia(window); + safariShim.shimCreateOfferLegacy(window); + + commonShim.shimRTCIceCandidate(window); break; default: logging('Unsupported browser!'); @@ -761,7 +2368,7 @@ module.exports = function(dependencies) { return adapter; }; -},{"./chrome/chrome_shim":4,"./edge/edge_shim":6,"./firefox/firefox_shim":9,"./safari/safari_shim":11,"./utils":12}],4:[function(require,module,exports){ +},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. @@ -788,20 +2395,25 @@ var chromeShim = { return this._ontrack; }, set: function(f) { - var self = this; if (this._ontrack) { this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); } this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { + } + }); + var origSetRemoteDescription = + window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function() { + var pc = this; + if (!pc._ontrackpoly) { + pc._ontrackpoly = function(e) { // onaddstream does not fire when a track is added to an existing // stream. But stream.onaddtrack is implemented so we use that. e.stream.addEventListener('addtrack', function(te) { var receiver; if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = self.getReceivers().find(function(r) { - return r.track.id === te.track.id; + receiver = pc.getReceivers().find(function(r) { + return r.track && r.track.id === te.track.id; }); } else { receiver = {track: te.track}; @@ -810,14 +2422,15 @@ var chromeShim = { var event = new Event('track'); event.track = te.track; event.receiver = receiver; + event.transceiver = {receiver: receiver}; event.streams = [e.stream]; - self.dispatchEvent(event); + pc.dispatchEvent(event); }); e.stream.getTracks().forEach(function(track) { var receiver; if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = self.getReceivers().find(function(r) { - return r.track.id === track.id; + receiver = pc.getReceivers().find(function(r) { + return r.track && r.track.id === track.id; }); } else { receiver = {track: track}; @@ -825,109 +2438,83 @@ var chromeShim = { var event = new Event('track'); event.track = track; event.receiver = receiver; + event.transceiver = {receiver: receiver}; event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); + pc.dispatchEvent(event); + }); + }; + pc.addEventListener('addstream', pc._ontrackpoly); } - }); + return origSetRemoteDescription.apply(pc, arguments); + }; } }, shimGetSendersWithDtmf: function(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. if (typeof window === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { - window.RTCPeerConnection.prototype.getSenders = function() { - return this._senders || []; + var shimSenderWithDtmf = function(pc, track) { + return { + track: track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; }; - var origAddStream = window.RTCPeerConnection.prototype.addStream; - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - if (!window.RTCPeerConnection.prototype.addTrack) { + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function() { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; window.RTCPeerConnection.prototype.addTrack = function(track, stream) { var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); + var sender = origAddTrack.apply(pc, arguments); + if (!sender) { + sender = shimSenderWithDtmf(pc, track); + pc._senders.push(sender); } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - pc._senders = pc._senders || []; - var alreadyExists = pc._senders.find(function(t) { - return t.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - oldStream.addTrack(track); - pc.removeStream(oldStream); - pc.addStream(oldStream); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc.addStream(newStream); - } - - var sender = { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }; - pc._senders.push(sender); return sender; }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function(sender) { + var pc = this; + origRemoveTrack.apply(pc, arguments); + var idx = pc._senders.indexOf(sender); + if (idx !== -1) { + pc._senders.splice(idx, 1); + } + }; } + var origAddStream = window.RTCPeerConnection.prototype.addStream; window.RTCPeerConnection.prototype.addStream = function(stream) { var pc = this; pc._senders = pc._senders || []; origAddStream.apply(pc, [stream]); stream.getTracks().forEach(function(track) { - pc._senders.push({ - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); + pc._senders.push(shimSenderWithDtmf(pc, track)); }); }; + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; window.RTCPeerConnection.prototype.removeStream = function(stream) { var pc = this; pc._senders = pc._senders || []; origRemoveStream.apply(pc, [stream]); + stream.getTracks().forEach(function(track) { var sender = pc._senders.find(function(s) { return s.track === track; @@ -962,7 +2549,7 @@ var chromeShim = { } } return this._dtmf; - }, + } }); } }, @@ -1011,6 +2598,245 @@ var chromeShim = { } }, + shimAddTrackRemoveTrack: function(window) { + var browserDetails = utils.detectBrowser(window); + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack && + browserDetails.version >= 64) { + return; + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + var origGetLocalStreams = window.RTCPeerConnection.prototype + .getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function() { + var self = this; + var nativeStreams = origGetLocalStreams.apply(this); + self._reverseStreams = self._reverseStreams || {}; + return nativeStreams.map(function(stream) { + return self._reverseStreams[stream.id]; + }); + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function(stream) { + var pc = this; + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + + stream.getTracks().forEach(function(track) { + var alreadyExists = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', + 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!pc._reverseStreams[stream.id]) { + var newStream = new window.MediaStream(stream.getTracks()); + pc._streams[stream.id] = newStream; + pc._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(pc, [stream]); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function(stream) { + var pc = this; + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + + origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); + delete pc._reverseStreams[(pc._streams[stream.id] ? + pc._streams[stream.id].id : stream.id)]; + delete pc._streams[stream.id]; + }; + + window.RTCPeerConnection.prototype.addTrack = function(track, stream) { + var pc = this; + if (pc.signalingState === 'closed') { + throw new DOMException( + 'The RTCPeerConnection\'s signalingState is \'closed\'.', + 'InvalidStateError'); + } + var streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || + !streams[0].getTracks().find(function(t) { + return t === track; + })) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException( + 'The adapter.js addTrack polyfill only supports a single ' + + ' stream which is associated with the specified track.', + 'NotSupportedError'); + } + + var alreadyExists = pc.getSenders().find(function(s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', + 'InvalidAccessError'); + } + + pc._streams = pc._streams || {}; + pc._reverseStreams = pc._reverseStreams || {}; + var oldStream = pc._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + + // Trigger ONN async. + Promise.resolve().then(function() { + pc.dispatchEvent(new Event('negotiationneeded')); + }); + } else { + var newStream = new window.MediaStream([track]); + pc._streams[stream.id] = newStream; + pc._reverseStreams[newStream.id] = stream; + pc.addStream(newStream); + } + return pc.getSenders().find(function(s) { + return s.track === track; + }); + }; + + // replace the internal stream id with the external one and + // vice versa. + function replaceInternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function(internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(internalStream.id, 'g'), + externalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + function replaceExternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function(internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(externalStream.id, 'g'), + internalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + ['createOffer', 'createAnswer'].forEach(function(method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function() { + var pc = this; + var args = arguments; + var isLegacyCall = arguments.length && + typeof arguments[0] === 'function'; + if (isLegacyCall) { + return nativeMethod.apply(pc, [ + function(description) { + var desc = replaceInternalStreamId(pc, description); + args[0].apply(null, [desc]); + }, + function(err) { + if (args[1]) { + args[1].apply(null, err); + } + }, arguments[2] + ]); + } + return nativeMethod.apply(pc, arguments) + .then(function(description) { + return replaceInternalStreamId(pc, description); + }); + }; + }); + + var origSetLocalDescription = + window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function() { + var pc = this; + if (!arguments.length || !arguments[0].type) { + return origSetLocalDescription.apply(pc, arguments); + } + arguments[0] = replaceExternalStreamId(pc, arguments[0]); + return origSetLocalDescription.apply(pc, arguments); + }; + + // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier + + var origLocalDescription = Object.getOwnPropertyDescriptor( + window.RTCPeerConnection.prototype, 'localDescription'); + Object.defineProperty(window.RTCPeerConnection.prototype, + 'localDescription', { + get: function() { + var pc = this; + var description = origLocalDescription.get.apply(this); + if (description.type === '') { + return description; + } + return replaceInternalStreamId(pc, description); + } + }); + + window.RTCPeerConnection.prototype.removeTrack = function(sender) { + var pc = this; + if (pc.signalingState === 'closed') { + throw new DOMException( + 'The RTCPeerConnection\'s signalingState is \'closed\'.', + 'InvalidStateError'); + } + // We can not yet check for sender instanceof RTCRtpSender + // since we shim RTPSender. So we check if sender._pc is set. + if (!sender._pc) { + throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + + 'does not implement interface RTCRtpSender.', 'TypeError'); + } + var isLocal = sender._pc === pc; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', + 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + pc._streams = pc._streams || {}; + var stream; + Object.keys(pc._streams).forEach(function(streamid) { + var hasTrack = pc._streams[streamid].getTracks().find(function(track) { + return sender.track === track; + }); + if (hasTrack) { + stream = pc._streams[streamid]; + } + }); + + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + pc.removeStream(pc._reverseStreams[stream.id]); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + pc.dispatchEvent(new Event('negotiationneeded')); + } + }; + }, + shimPeerConnection: function(window) { var browserDetails = utils.detectBrowser(window); @@ -1047,7 +2873,7 @@ var chromeShim = { var server = pcConfig.iceServers[i]; if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { - console.warn('RTCIceServer.url is deprecated! Use urls instead.'); + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); server = JSON.parse(JSON.stringify(server)); server.urls = server.url; newIceServers.push(server); @@ -1210,13 +3036,14 @@ var chromeShim = { module.exports = { shimMediaStream: chromeShim.shimMediaStream, shimOnTrack: chromeShim.shimOnTrack, + shimAddTrackRemoveTrack: chromeShim.shimAddTrackRemoveTrack, shimGetSendersWithDtmf: chromeShim.shimGetSendersWithDtmf, shimSourceObject: chromeShim.shimSourceObject, shimPeerConnection: chromeShim.shimPeerConnection, shimGetUserMedia: require('./getusermedia') }; -},{"../utils.js":12,"./getusermedia":5}],5:[function(require,module,exports){ +},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -1286,6 +3113,9 @@ module.exports = function(window) { }; var shimConstraints_ = function(constraints, func) { + if (browserDetails.version >= 61) { + return func(constraints); + } constraints = JSON.parse(JSON.stringify(constraints)); if (constraints && typeof constraints.audio === 'object') { var remap = function(obj, a, b) { @@ -1303,7 +3133,7 @@ module.exports = function(window) { // Shim facingMode for mobile & surface pro. var face = constraints.video.facingMode; face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 61; + var getSupportedFacingModeLies = browserDetails.version < 66; if ((face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment')) && @@ -1370,7 +3200,9 @@ module.exports = function(window) { var getUserMedia_ = function(constraints, onSuccess, onError) { shimConstraints_(constraints, function(c) { navigator.webkitGetUserMedia(c, onSuccess, function(e) { - onError(shimError_(e)); + if (onError) { + onError(shimError_(e)); + } }); }); }; @@ -1453,7 +3285,175 @@ module.exports = function(window) { } }; -},{"../utils.js":12}],6:[function(require,module,exports){ +},{"../utils.js":13}],7:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + /* eslint-env node */ +'use strict'; + +var SDPUtils = require('sdp'); +var utils = require('./utils'); + +// Wraps the peerconnection event eventNameToWrap in a function +// which returns the modified event object. +function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { + if (!window.RTCPeerConnection) { + return; + } + var proto = window.RTCPeerConnection.prototype; + var nativeAddEventListener = proto.addEventListener; + proto.addEventListener = function(nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap) { + return nativeAddEventListener.apply(this, arguments); + } + var wrappedCallback = function(e) { + cb(wrapper(e)); + }; + this._eventMap = this._eventMap || {}; + this._eventMap[cb] = wrappedCallback; + return nativeAddEventListener.apply(this, [nativeEventName, + wrappedCallback]); + }; + + var nativeRemoveEventListener = proto.removeEventListener; + proto.removeEventListener = function(nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap || !this._eventMap + || !this._eventMap[cb]) { + return nativeRemoveEventListener.apply(this, arguments); + } + var unwrappedCb = this._eventMap[cb]; + delete this._eventMap[cb]; + return nativeRemoveEventListener.apply(this, [nativeEventName, + unwrappedCb]); + }; + + Object.defineProperty(proto, 'on' + eventNameToWrap, { + get: function() { + return this['_on' + eventNameToWrap]; + }, + set: function(cb) { + if (this['_on' + eventNameToWrap]) { + this.removeEventListener(eventNameToWrap, + this['_on' + eventNameToWrap]); + delete this['_on' + eventNameToWrap]; + } + if (cb) { + this.addEventListener(eventNameToWrap, + this['_on' + eventNameToWrap] = cb); + } + } + }); +} + +module.exports = { + shimRTCIceCandidate: function(window) { + // foundation is arbitrarily chosen as an indicator for full support for + // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface + if (window.RTCIceCandidate && 'foundation' in + window.RTCIceCandidate.prototype) { + return; + } + + var NativeRTCIceCandidate = window.RTCIceCandidate; + window.RTCIceCandidate = function(args) { + // Remove the a= which shouldn't be part of the candidate string. + if (typeof args === 'object' && args.candidate && + args.candidate.indexOf('a=') === 0) { + args = JSON.parse(JSON.stringify(args)); + args.candidate = args.candidate.substr(2); + } + + // Augment the native candidate with the parsed fields. + var nativeCandidate = new NativeRTCIceCandidate(args); + var parsedCandidate = SDPUtils.parseCandidate(args.candidate); + var augmentedCandidate = Object.assign(nativeCandidate, + parsedCandidate); + + // Add a serializer that does not serialize the extra attributes. + augmentedCandidate.toJSON = function() { + return { + candidate: augmentedCandidate.candidate, + sdpMid: augmentedCandidate.sdpMid, + sdpMLineIndex: augmentedCandidate.sdpMLineIndex, + usernameFragment: augmentedCandidate.usernameFragment, + }; + }; + return augmentedCandidate; + }; + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + wrapPeerConnectionEvent(window, 'icecandidate', function(e) { + if (e.candidate) { + Object.defineProperty(e, 'candidate', { + value: new window.RTCIceCandidate(e.candidate), + writable: 'false' + }); + } + return e; + }); + }, + + // shimCreateObjectURL must be called before shimSourceObject to avoid loop. + + shimCreateObjectURL: function(window) { + var URL = window && window.URL; + + if (!(typeof window === 'object' && window.HTMLMediaElement && + 'srcObject' in window.HTMLMediaElement.prototype && + URL.createObjectURL && URL.revokeObjectURL)) { + // Only shim CreateObjectURL using srcObject if srcObject exists. + return undefined; + } + + var nativeCreateObjectURL = URL.createObjectURL.bind(URL); + var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); + var streams = new Map(), newId = 0; + + URL.createObjectURL = function(stream) { + if ('getTracks' in stream) { + var url = 'polyblob:' + (++newId); + streams.set(url, stream); + utils.deprecated('URL.createObjectURL(stream)', + 'elem.srcObject = stream'); + return url; + } + return nativeCreateObjectURL(stream); + }; + URL.revokeObjectURL = function(url) { + nativeRevokeObjectURL(url); + streams.delete(url); + }; + + var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, + 'src'); + Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { + get: function() { + return dsc.get.apply(this); + }, + set: function(url) { + this.srcObject = streams.get(url) || null; + return dsc.set.apply(this, [url]); + } + }); + + var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; + window.HTMLMediaElement.prototype.setAttribute = function() { + if (arguments.length === 2 && + ('' + arguments[0]).toLowerCase() === 'src') { + this.srcObject = streams.get(arguments[1]) || null; + } + return nativeSetAttribute.apply(this, arguments); + }; + } +}; + +},{"./utils":13,"sdp":2}],8:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -1465,7 +3465,7 @@ module.exports = function(window) { 'use strict'; var utils = require('../utils'); -var shimRTCPeerConnection = require('./rtcpeerconnection_shim'); +var shimRTCPeerConnection = require('rtcpeerconnection-shim'); module.exports = { shimGetUserMedia: require('./getusermedia'), @@ -1504,6 +3504,24 @@ module.exports = { }); } } + + // ORTC defines the DTMF sender a bit different. + // https://github.com/w3c/ortc/issues/714 + if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = new window.RTCDtmfSender(this); + } else if (this.track.kind === 'video') { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + window.RTCPeerConnection = shimRTCPeerConnection(window, browserDetails.version); }, @@ -1517,7 +3535,7 @@ module.exports = { } }; -},{"../utils":12,"./getusermedia":7,"./rtcpeerconnection_shim":8}],7:[function(require,module,exports){ +},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -1553,1397 +3571,7 @@ module.exports = function(window) { }; }; -},{}],8:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); - -// sort tracks such that they follow an a-v-a-v... -// pattern. -function sortTracks(tracks) { - var audioTracks = tracks.filter(function(track) { - return track.kind === 'audio'; - }); - var videoTracks = tracks.filter(function(track) { - return track.kind === 'video'; - }); - tracks = []; - while (audioTracks.length || videoTracks.length) { - if (audioTracks.length) { - tracks.push(audioTracks.shift()); - } - if (videoTracks.length) { - tracks.push(videoTracks.shift()); - } - } - return tracks; -} - -// Edge does not like -// 1) stun: -// 2) turn: that does not have all of turn:host:port?transport=udp -// 3) turn: with ipv6 addresses -// 4) turn: occurring muliple times -function filterIceServers(iceServers, edgeVersion) { - var hasTurn = false; - iceServers = JSON.parse(JSON.stringify(iceServers)); - return iceServers.filter(function(server) { - if (server && (server.urls || server.url)) { - var urls = server.urls || server.url; - if (server.url && !server.urls) { - console.warn('RTCIceServer.url is deprecated! Use urls instead.'); - } - var isString = typeof urls === 'string'; - if (isString) { - urls = [urls]; - } - urls = urls.filter(function(url) { - var validTurn = url.indexOf('turn:') === 0 && - url.indexOf('transport=udp') !== -1 && - url.indexOf('turn:[') === -1 && - !hasTurn; - - if (validTurn) { - hasTurn = true; - return true; - } - return url.indexOf('stun:') === 0 && edgeVersion >= 14393; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - return false; - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -module.exports = function(window, edgeVersion) { - var RTCPeerConnection = function(config) { - var self = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - self[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.needNegotiation = false; - - this.onicecandidate = null; - this.onaddstream = null; - this.ontrack = null; - this.onremovestream = null; - this.onsignalingstatechange = null; - this.oniceconnectionstatechange = null; - this.onicegatheringstatechange = null; - this.onnegotiationneeded = null; - this.ondatachannel = null; - this.canTrickleIceCandidates = null; - - this.localStreams = []; - this.remoteStreams = []; - this.getLocalStreams = function() { - return self.localStreams; - }; - this.getRemoteStreams = function() { - return self.remoteStreams; - }; - - this.localDescription = new window.RTCSessionDescription({ - type: '', - sdp: '' - }); - this.remoteDescription = new window.RTCSessionDescription({ - type: '', - sdp: '' - }); - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - this.iceOptions = { - gatherPolicy: 'all', - iceServers: [] - }; - if (config && config.iceTransportPolicy) { - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - this.iceOptions.gatherPolicy = config.iceTransportPolicy; - break; - default: - // don't set iceTransportPolicy. - break; - } - } - this.usingBundle = config && config.bundlePolicy === 'max-bundle'; - - if (config && config.iceServers) { - this.iceOptions.iceServers = filterIceServers(config.iceServers, - edgeVersion); - } - this._config = config || {}; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - // since the iceGatherer is currently created in createOffer but we - // must not emit candidates until after setLocalDescription we buffer - // them in this array. - this._localIceCandidatesBuffer = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this.dispatchEvent(event); - if (this.onicegatheringstatechange !== null) { - this.onicegatheringstatechange(event); - } - }; - - RTCPeerConnection.prototype._emitBufferedCandidates = function() { - var self = this; - var sections = SDPUtils.splitSections(self.localDescription.sdp); - // FIXME: need to apply ice candidates in a way which is async but - // in-order - this._localIceCandidatesBuffer.forEach(function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - if (end) { - for (var j = 1; j < sections.length; j++) { - if (sections[j].indexOf('\r\na=end-of-candidates\r\n') === -1) { - sections[j] += 'a=end-of-candidates\r\n'; - } - } - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } - self.localDescription.sdp = sections.join(''); - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - if (!event.candidate && self.iceGatheringState !== 'complete') { - var complete = self.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - if (complete && self.iceGatheringStateChange !== 'complete') { - self.iceGatheringState = 'complete'; - self._emitGatheringStateChange(); - } - } - }); - this._localIceCandidatesBuffer = []; - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - this.transceivers.push(transceiver); - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - - this._maybeFireNegotiationNeeded(); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var self = this; - if (edgeVersion >= 15025) { - this.localStreams.push(stream); - stream.getTracks().forEach(function(track) { - self.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - self.addTrack(track, clonedStream); - }); - this.localStreams.push(clonedStream); - } - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var idx = this.localStreams.indexOf(stream); - if (idx > -1) { - this.localStreams.splice(idx, 1); - this._maybeFireNegotiationNeeded(); - } - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - // Create ICE gatherer and hook it up. - RTCPeerConnection.prototype._createIceGatherer = function(mid, - sdpMLineIndex) { - var self = this; - var iceGatherer = new window.RTCIceGatherer(self.iceOptions); - iceGatherer.onlocalcandidate = function(evt) { - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - var end = !cand || Object.keys(cand).length === 0; - // Edge emits an empty object for RTCIceCandidateComplete‥ - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === undefined) { - iceGatherer.state = 'completed'; - } - } else { - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(self.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - self.localDescription.sdp = sections.join(''); - var transceivers = self._pendingOffer ? self._pendingOffer : - self.transceivers; - var complete = transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - // Emit candidate if localDescription is set. - // Also emits null candidate when all gatherers are complete. - switch (self.iceGatheringState) { - case 'new': - if (!end) { - self._localIceCandidatesBuffer.push(event); - } - if (end && complete) { - self._localIceCandidatesBuffer.push( - new Event('icecandidate')); - } - break; - case 'gathering': - self._emitBufferedCandidates(); - if (!end) { - self.dispatchEvent(event); - if (self.onicecandidate !== null) { - self.onicecandidate(event); - } - } - if (complete) { - self.dispatchEvent(new Event('icecandidate')); - if (self.onicecandidate !== null) { - self.onicecandidate(new Event('icecandidate')); - } - self.iceGatheringState = 'complete'; - self._emitGatheringStateChange(); - } - break; - case 'complete': - // should not happen... currently! - break; - default: // no-op. - break; - } - }; - return iceGatherer; - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var self = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - self._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - self._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itself. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - self._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlssttatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - params.encodings = transceiver.recvEncodingParameters; - params.rtcp = { - cname: transceiver.rtcpParameters.cname, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var self = this; - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState)) { - var e = new Error('Can not set local ' + description.type + - ' in state ' + this.signalingState); - e.name = 'InvalidStateError'; - if (arguments.length > 2 && typeof arguments[2] === 'function') { - window.setTimeout(arguments[2], 0, e); - } - return Promise.reject(e); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // FIXME: What was the purpose of this empty if statement? - // if (!this._pendingOffer) { - // } else { - if (this._pendingOffer) { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - self._pendingOffer[sdpMLineIndex].localCapabilities = caps; - }); - this.transceivers = this._pendingOffer; - delete this._pendingOffer; - } - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(self.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = self.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - var rejected = SDPUtils.isRejected(mediaSection); - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!self.usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - dtlsTransport.start(remoteDtlsParameters); - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - self._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - // If a success callback was provided, emit ICE candidates after it - // has been executed. Otherwise, emit callback after the Promise is - // resolved. - var hasCallback = arguments.length > 1 && - typeof arguments[1] === 'function'; - if (hasCallback) { - var cb = arguments[1]; - window.setTimeout(function() { - cb(); - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - self._emitBufferedCandidates(); - }, 0); - } - var p = Promise.resolve(); - p.then(function() { - if (!hasCallback) { - if (self.iceGatheringState === 'new') { - self.iceGatheringState = 'gathering'; - self._emitGatheringStateChange(); - } - // Usually candidates will be emitted earlier. - window.setTimeout(self._emitBufferedCandidates.bind(self), 500); - } - }); - return p; - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var self = this; - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState)) { - var e = new Error('Can not set remote ' + description.type + - ' in state ' + this.signalingState); - e.name = 'InvalidStateError'; - if (arguments.length > 2 && typeof arguments[2] === 'function') { - window.setTimeout(arguments[2], 0, e); - } - return Promise.reject(e); - } - - var streams = {}; - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - this.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - var rejected = SDPUtils.isRejected(mediaSection); - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { - self.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === '1' || cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - self.transceivers[sdpMLineIndex]) { - self._disposeIceAndDtlsTransports(sdpMLineIndex); - self.transceivers[sdpMLineIndex].iceGatherer = - self.transceivers[0].iceGatherer; - self.transceivers[sdpMLineIndex].iceTransport = - self.transceivers[0].iceTransport; - self.transceivers[sdpMLineIndex].dtlsTransport = - self.transceivers[0].dtlsTransport; - if (self.transceivers[sdpMLineIndex].rtpSender) { - self.transceivers[sdpMLineIndex].rtpSender.setTransport( - self.transceivers[0].dtlsTransport); - } - if (self.transceivers[sdpMLineIndex].rtpReceiver) { - self.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - self.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex] || - self._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = usingBundle && sdpMLineIndex > 0 ? - self.transceivers[0].iceGatherer : - self._createIceGatherer(mid, sdpMLineIndex); - } - - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - if (direction === 'sendrecv' || direction === 'sendonly') { - rtpReceiver = new window.RTCRtpReceiver(transceiver.dtlsTransport, - kind); - - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - streams[remoteMsid.stream].addTrack(track); - receiverList.push([track, rtpReceiver, - streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - streams.default.addTrack(track); - receiverList.push([track, rtpReceiver, streams.default]); - } - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - self._transceive(self.transceivers[sdpMLineIndex], - false, - direction === 'sendrecv' || direction === 'sendonly'); - } else if (description.type === 'answer' && !rejected) { - transceiver = self.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - self.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - self.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - self.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if ((isIceLite || isComplete) && cands.length) { - iceTransport.setRemoteCandidates(cands); - } - if (!usingBundle || sdpMLineIndex === 0) { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - dtlsTransport.start(remoteDtlsParameters); - } - - self._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - streams[remoteMsid.stream].addTrack(track); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - streams.default.addTrack(track); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - self.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - self.dispatchEvent(event); - if (self.onaddstream !== null) { - window.setTimeout(function() { - self.onaddstream(event); - }, 0); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.streams = [stream]; - self.dispatchEvent(trackEvent); - if (self.ontrack !== null) { - window.setTimeout(function() { - self.ontrack(trackEvent); - }, 0); - } - }); - } - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(self && self.transceivers)) { - return; - } - self.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this.dispatchEvent(event); - if (this.onsignalingstatechange !== null) { - this.onsignalingstatechange(event); - } - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var self = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (self.needNegotiation === false) { - return; - } - self.needNegotiation = false; - var event = new Event('negotiationneeded'); - self.dispatchEvent(event); - if (self.onnegotiationneeded !== null) { - self.onnegotiationneeded(event); - } - }, 0); - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var self = this; - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== self.iceConnectionState) { - self.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this.dispatchEvent(event); - if (this.oniceconnectionstatechange !== null) { - this.oniceconnectionstatechange(event); - } - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var self = this; - if (this._pendingOffer) { - throw new Error('createOffer called while there is a pending offer.'); - } - var offerOptions; - if (arguments.length === 1 && typeof arguments[0] !== 'function') { - offerOptions = arguments[0]; - } else if (arguments.length === 3) { - offerOptions = arguments[2]; - } - - var numAudioTracks = this.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = this.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - this.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - this._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - this._createTransceiver('video'); - numVideoTracks--; - } - } - // reorder tracks - var transceivers = sortTracks(this.transceivers); - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); - transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = self.usingBundle && sdpMLineIndex > 0 ? - transceivers[0].iceGatherer : - self._createIceGatherer(mid, sdpMLineIndex); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video') { - sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 1) * 1001 + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, - kind - ); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += SDPUtils.writeMediaSection(transceiver, - transceiver.localCapabilities, 'offer', transceiver.stream); - sdp += 'a=rtcp-rsize\r\n'; - }); - - this._pendingOffer = transceivers; - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video') { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: (2 * sdpMLineIndex + 2) * 1001 + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += SDPUtils.writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - if (arguments.length && typeof arguments[0] === 'function') { - window.setTimeout(arguments[0], 0, desc); - } - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - if (!candidate) { - for (var j = 0; j < this.transceivers.length; j++) { - this.transceivers[j].iceTransport.addRemoteCandidate({}); - if (this.usingBundle) { - return Promise.resolve(); - } - } - } else { - var mLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - mLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[mLineIndex]; - if (transceiver) { - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && - !(cand.component === '1' || cand.component === 1)) { - return Promise.resolve(); - } - transceiver.iceTransport.addRemoteCandidate(cand); - - // update the remoteDescription. - var sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[mLineIndex + 1] += (cand.type ? candidate.candidate.trim() - : 'a=end-of-candidates') + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } - } - if (arguments.length > 1 && typeof arguments[1] === 'function') { - window.setTimeout(arguments[1], 0); - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var cb = arguments.length > 1 && typeof arguments[1] === 'function' && - arguments[1]; - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - if (cb) { - window.setTimeout(cb, 0, results); - } - resolve(results); - }); - }); - }; - return RTCPeerConnection; -}; - -},{"sdp":1}],9:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -2975,6 +3603,7 @@ var firefoxShim = { var event = new Event('track'); event.track = track; event.receiver = {track: track}; + event.transceiver = {receiver: event.receiver}; event.streams = [e.stream]; this.dispatchEvent(event); }.bind(this)); @@ -2982,6 +3611,15 @@ var firefoxShim = { } }); } + if (typeof window === 'object' && window.RTCTrackEvent && + ('receiver' in window.RTCTrackEvent.prototype) && + !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function() { + return {receiver: this.receiver}; + } + }); + } }, shimSourceObject: function(window) { @@ -3132,6 +3770,22 @@ var firefoxShim = { }) .then(onSucc, onErr); }; + }, + + shimRemoveStream: function(window) { + if (!window.RTCPeerConnection || + 'removeStream' in window.RTCPeerConnection.prototype) { + return; + } + window.RTCPeerConnection.prototype.removeStream = function(stream) { + var pc = this; + utils.deprecated('removeStream', 'removeTrack'); + this.getSenders().forEach(function(sender) { + if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { + pc.removeTrack(sender); + } + }); + }; } }; @@ -3140,10 +3794,11 @@ module.exports = { shimOnTrack: firefoxShim.shimOnTrack, shimSourceObject: firefoxShim.shimSourceObject, shimPeerConnection: firefoxShim.shimPeerConnection, + shimRemoveStream: firefoxShim.shimRemoveStream, shimGetUserMedia: require('./getusermedia') }; -},{"../utils":12,"./getusermedia":10}],10:[function(require,module,exports){ +},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -3348,13 +4003,13 @@ module.exports = function(window) { return getUserMedia_(constraints, onSuccess, onError); } // Replace Firefox 44+'s deprecation warning with unprefixed version. - console.warn('navigator.getUserMedia has been replaced by ' + - 'navigator.mediaDevices.getUserMedia'); + utils.deprecated('navigator.getUserMedia', + 'navigator.mediaDevices.getUserMedia'); navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); }; }; -},{"../utils":12}],11:[function(require,module,exports){ +},{"../utils":13}],12:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -3427,7 +4082,7 @@ var safariShim = { this._localStreams.push(stream); } } - _addTrack.call(this, track, stream); + return _addTrack.call(this, track, stream); }; } if (!('removeStream' in window.RTCPeerConnection.prototype)) { @@ -3588,11 +4243,66 @@ var safariShim = { }; window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; + if ('generateCertificate' in window.RTCPeerConnection) { + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function() { + return OrigPeerConnection.generateCertificate; + } + }); + } + }, + shimTrackEventTransceiver: function(window) { + // Add event.transceiver member over deprecated event.receiver + if (typeof window === 'object' && window.RTCPeerConnection && + ('receiver' in window.RTCTrackEvent.prototype) && + // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is + // defined for some reason even when window.RTCTransceiver is not. + !window.RTCTransceiver) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function() { + return {receiver: this.receiver}; + } + }); + } + }, + + shimCreateOfferLegacy: function(window) { + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { + var pc = this; + if (offerOptions) { + var audioTransceiver = pc.getTransceivers().find(function(transceiver) { + return transceiver.sender.track && + transceiver.sender.track.kind === 'audio'; + }); + if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { + if (audioTransceiver.direction === 'sendrecv') { + audioTransceiver.setDirection('sendonly'); + } else if (audioTransceiver.direction === 'recvonly') { + audioTransceiver.setDirection('inactive'); + } + } else if (offerOptions.offerToReceiveAudio === true && + !audioTransceiver) { + pc.addTransceiver('audio'); + } + + var videoTransceiver = pc.getTransceivers().find(function(transceiver) { + return transceiver.sender.track && + transceiver.sender.track.kind === 'video'; + }); + if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { + if (videoTransceiver.direction === 'sendrecv') { + videoTransceiver.setDirection('sendonly'); + } else if (videoTransceiver.direction === 'recvonly') { + videoTransceiver.setDirection('inactive'); + } + } else if (offerOptions.offerToReceiveVideo === true && + !videoTransceiver) { + pc.addTransceiver('video'); + } } - }); + return origCreateOffer.apply(pc, arguments); + }; } }; @@ -3602,12 +4312,14 @@ module.exports = { shimLocalStreamsAPI: safariShim.shimLocalStreamsAPI, shimRemoteStreamsAPI: safariShim.shimRemoteStreamsAPI, shimGetUserMedia: safariShim.shimGetUserMedia, - shimRTCIceServerUrls: safariShim.shimRTCIceServerUrls + shimRTCIceServerUrls: safariShim.shimRTCIceServerUrls, + shimTrackEventTransceiver: safariShim.shimTrackEventTransceiver, + shimCreateOfferLegacy: safariShim.shimCreateOfferLegacy // TODO // shimPeerConnection: safariShim.shimPeerConnection }; -},{"../utils":12}],12:[function(require,module,exports){ +},{"../utils":13}],13:[function(require,module,exports){ /* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * @@ -3742,57 +4454,6 @@ var utils = { return result; }, - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - } }; // Export. @@ -3806,5 +4467,5 @@ module.exports = { detectBrowser: utils.detectBrowser.bind(utils) }; -},{}]},{},[2])(2) +},{}]},{},[3])(3) }); \ No newline at end of file diff --git a/html5/verto/video_demo-live_canvas/js/verto-min.js b/html5/verto/video_demo-live_canvas/js/verto-min.js index c93b8aca64..fdf5432fa5 100644 --- a/html5/verto/video_demo-live_canvas/js/verto-min.js +++ b/html5/verto/video_demo-live_canvas/js/verto-min.js @@ -56,7 +56,7 @@ function onSuccess(stream){self.localStream=stream;if(screen){self.constraints.o self.peer=FSRTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:screen?function(stream){}:function(stream){return onRemoteStream(self,stream);},onOfferSDP:function(sdp){return onOfferSDP(self,sdp);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints,iceServers:self.options.iceServers,});onStreamSuccess(self,stream);} function onError(e){onStreamError(self,e);} var mediaParams=getMediaParams(self);console.log("Audio constraints",mediaParams.audio);console.log("Video constraints",mediaParams.video);if(mediaParams.audio||mediaParams.video){getUserMedia({constraints:{audio:mediaParams.audio,video:mediaParams.video},video:mediaParams.useVideo,onsuccess:onSuccess,onerror:onError});}else{onSuccess(null);}};function FSRTCPeerConnection(options){var gathering=false,done=false;var config={};var default_ice={urls:['stun:stun.l.google.com:19302']};if(options.iceServers){if(typeof(options.iceServers)==="boolean"){config.iceServers=[default_ice];}else{config.iceServers=options.iceServers;}} -var peer=new window.RTCPeerConnection(config);openOffererChannel();var x=0;function ice_handler(){done=true;gathering=null;if(options.onICEComplete){options.onICEComplete();} +config.bundlePolicy="max-compat";var peer=new window.RTCPeerConnection(config);openOffererChannel();var x=0;function ice_handler(){done=true;gathering=null;if(options.onICEComplete){options.onICEComplete();} if(options.type=="offer"){options.onICESDP(peer.localDescription);}else{if(!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}} peer.onicecandidate=function(event){if(done){return;} if(!gathering){gathering=setTimeout(ice_handler,1000);} @@ -163,6 +163,7 @@ if(sendChannels.length){verto.sendMethod("verto.unsubscribe",{eventChannel:sendC verto.sendMethod("verto.broadcast",msg);};$.verto.prototype.purge=function(callID){var verto=this;var x=0;var i;for(i in verto.dialogs){if(!x){console.log("purging dialogs");} x++;verto.dialogs[i].setState($.verto.enum.state.purge);} for(i in verto.eventSUBS){if(verto.eventSUBS[i]){console.log("purging subscription: "+i);delete verto.eventSUBS[i];}}};$.verto.prototype.hangup=function(callID){var verto=this;if(callID){var dialog=verto.dialogs[callID];if(dialog){dialog.hangup();}}else{for(var i in verto.dialogs){verto.dialogs[i].hangup();}}};$.verto.prototype.newCall=function(args,callbacks){var verto=this;if(!verto.rpcClient.socketReady()){console.error("Not Connected...");return;} +if(args["useCamera"]){verto.options.deviceParams["useCamera"]=args["useCamera"];} var dialog=new $.verto.dialog($.verto.enum.direction.outbound,this,args);dialog.invite();if(callbacks){dialog.callbacks=callbacks;} return dialog;};$.verto.prototype.handleMessage=function(data){var verto=this;if(!(data&&data.method)){console.error("Invalid Data",data);return;} if(data.params.callID){var dialog=verto.dialogs[data.params.callID];if(data.method==="verto.attach"&&dialog){delete dialog.verto.dialogs[dialog.callID];dialog.rtc.stop();dialog=null;} @@ -306,8 +307,120 @@ navigator.getUserMedia({audio:(has_audio>0?true:false),video:(has_video>0?true:f navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError);};$.verto.refreshDevices=function(runtime){checkDevices(runtime);} $.verto.init=function(obj,runtime){if(!obj){obj={};} if(!obj.skipPermCheck&&!obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){checkDevices(runtime);},true,true);}else if(obj.skipPermCheck&&!obj.skipDeviceCheck){checkDevices(runtime);}else if(!obj.skipPermCheck&&obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){runtime(status);},true,true);}else{runtime(null);}} -$.verto.genUUID=function(){return generateGUID();}})(jQuery);(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter=f()}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0?'m='+part:part).trim()+'\r\n';});};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} -var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i=14393&&url.indexOf('?transport=udp')===-1;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;} +return false;});} +function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;i--){this._iceGatherers=new window.RTCIceGatherer({iceServers:config.iceServers,gatherPolicy:config.iceTransportPolicy});}}else{config.iceCandidatePoolSize=0;} +this._config=config;this.transceivers=[];this._sdpSessionId=SDPUtils.generateSessionId();this._sdpSessionVersion=0;this._dtlsRole=undefined;};RTCPeerConnection.prototype._emitGatheringStateChange=function(){var event=new Event('icegatheringstatechange');this.dispatchEvent(event);if(typeof this.onicegatheringstatechange==='function'){this.onicegatheringstatechange(event);}};RTCPeerConnection.prototype.getConfiguration=function(){return this._config;};RTCPeerConnection.prototype.getLocalStreams=function(){return this.localStreams;};RTCPeerConnection.prototype.getRemoteStreams=function(){return this.remoteStreams;};RTCPeerConnection.prototype._createTransceiver=function(kind){var hasBundleTransport=this.transceivers.length>0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} +this.transceivers.push(transceiver);return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){var transceiver;for(var i=0;i=15025){stream.getTracks().forEach(function(track){self.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){self.addTrack(track,clonedStream);});}};RTCPeerConnection.prototype.removeStream=function(stream){var idx=this.localStreams.indexOf(stream);if(idx>-1){this.localStreams.splice(idx,1);this._maybeFireNegotiationNeeded();}};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(sdpMLineIndex,usingBundle){var self=this;if(usingBundle&&sdpMLineIndex>0){return this.transceivers[0].iceGatherer;}else if(this._iceGatherers.length){return this._iceGatherers.shift();} +var iceGatherer=new window.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});Object.defineProperty(iceGatherer,'state',{value:'new',writable:true});this.transceivers[sdpMLineIndex].candidates=[];this.transceivers[sdpMLineIndex].bufferCandidates=function(event){var end=!event.candidate||Object.keys(event.candidate).length===0;iceGatherer.state=end?'completed':'gathering';if(self.transceivers[sdpMLineIndex].candidates!==null){self.transceivers[sdpMLineIndex].candidates.push(event.candidate);}};iceGatherer.addEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);return iceGatherer;};RTCPeerConnection.prototype._gather=function(mid,sdpMLineIndex){var self=this;var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer.onlocalcandidate){return;} +var candidates=this.transceivers[sdpMLineIndex].candidates;this.transceivers[sdpMLineIndex].candidates=null;iceGatherer.removeEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);iceGatherer.onlocalcandidate=function(evt){if(self.usingBundle&&sdpMLineIndex>0){return;} +var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state==='new'||iceGatherer.state==='gathering'){iceGatherer.state='completed';}}else{if(iceGatherer.state==='new'){iceGatherer.state='gathering';} +cand.component=1;event.candidate.candidate=SDPUtils.writeCandidate(cand);} +var sections=SDPUtils.splitSections(self.localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex+1]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex+1]+='a=end-of-candidates\r\n';} +self.localDescription.sdp=sections.join('');var complete=self.transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});if(self.iceGatheringState!=='gathering'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} +if(!end){self.dispatchEvent(event);if(typeof self.onicecandidate==='function'){self.onicecandidate(event);}} +if(complete){self.dispatchEvent(new Event('icecandidate'));if(typeof self.onicecandidate==='function'){self.onicecandidate(new Event('icecandidate'));} +self.iceGatheringState='complete';self._emitGatheringStateChange();}};window.setTimeout(function(){candidates.forEach(function(candidate){var e=new Event('RTCIceGatherEvent');e.candidate=candidate;iceGatherer.onlocalcandidate(e);});},0);};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var self=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){self._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){self._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});self._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} +var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} +var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlsstatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} +transceiver.rtpSender.send(params);} +if(recv&&transceiver.rtpReceiver&¶ms.codecs.length>0){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} +params.encodings=transceiver.recvEncodingParameters;params.rtcp={cname:transceiver.rtcpParameters.cname,compound:transceiver.rtcpParameters.compound};if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} +transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var self=this;var args=arguments;if(!isActionAllowedInSignalingState('setLocalDescription',description.type,this.signalingState)){return new Promise(function(resolve,reject){var e=new Error('Can not set local '+description.type+' in state '+self.signalingState);e.name='InvalidStateError';if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[e]);} +reject(e);});} +var sections;var sessionpart;if(description.type==='offer'){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);self.transceivers[sdpMLineIndex].localCapabilities=caps;});this.transceivers.forEach(function(transceiver,sdpMLineIndex){self._gather(transceiver.mid,sdpMLineIndex);});}else if(description.type==='answer'){sections=SDPUtils.splitSections(self.remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection)&&!SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===1;if(!rejected&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} +if(!self.usingBundle||sdpMLineIndex===0){self._gather(transceiver.mid,sdpMLineIndex);if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var params=getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,false);}});} +this.localDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-local-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} +var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];return new Promise(function(resolve){if(cb){cb.apply(null);} +resolve();});};RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this;var args=arguments;if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,this.signalingState)){return new Promise(function(resolve,reject){var e=new Error('Can not set remote '+description.type+' in state '+self.signalingState);e.name='InvalidStateError';if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[e]);} +reject(e);});} +var streams={};this.remoteStreams.forEach(function(stream){streams[stream.id]=stream;});var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;this.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){this.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{this.canTrickleIceCandidates=false;} +sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection)&&!SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===1;var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(kind==='application'&&protocol==='DTLS/SCTP'){self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:true};return;} +var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} +recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&self.transceivers[sdpMLineIndex]){self._disposeIceAndDtlsTransports(sdpMLineIndex);self.transceivers[sdpMLineIndex].iceGatherer=self.transceivers[0].iceGatherer;self.transceivers[sdpMLineIndex].iceTransport=self.transceivers[0].iceTransport;self.transceivers[sdpMLineIndex].dtlsTransport=self.transceivers[0].dtlsTransport;if(self.transceivers[sdpMLineIndex].rtpSender){self.transceivers[sdpMLineIndex].rtpSender.setTransport(self.transceivers[0].dtlsTransport);} +if(self.transceivers[sdpMLineIndex].rtpReceiver){self.transceivers[sdpMLineIndex].rtpReceiver.setTransport(self.transceivers[0].dtlsTransport);}} +if(description.type==='offer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex]||self._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,usingBundle);} +if(cands.length&&transceiver.iceTransport.state==='new'){if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+2)*1001}];var isNewTrack=false;if(direction==='sendrecv'||direction==='sendonly'){isNewTrack=!transceiver.rtpReceiver;rtpReceiver=transceiver.rtpReceiver||new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);if(isNewTrack){var stream;track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} +Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});stream=streams[remoteMsid.stream];}else{if(!streams.default){streams.default=new window.MediaStream();} +stream=streams.default;} +stream.addTrack(track);receiverList.push([track,rtpReceiver,stream]);}} +transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;self._transceive(self.transceivers[sdpMLineIndex],false,isNewTrack);}else if(description.type==='answer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;self.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if(cands.length&&iceTransport.state==='new'){if((isIceLite||isComplete)&&(!usingBundle||sdpMLineIndex===0)){iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +if(!usingBundle||sdpMLineIndex===0){if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +self._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} +streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} +streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});if(this._dtlsRole===undefined){this._dtlsRole=description.type==='offer'?'active':'passive';} +this.remoteDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-remote-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} +Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){if(self.remoteStreams.indexOf(stream)===-1){self.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;window.setTimeout(function(){self.dispatchEvent(event);if(typeof self.onaddstream==='function'){self.onaddstream(event);}});} +receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} +var trackEvent=new Event('track');trackEvent.track=track;trackEvent.receiver=receiver;trackEvent.transceiver={receiver:receiver};trackEvent.streams=[stream];window.setTimeout(function(){self.dispatchEvent(trackEvent);if(typeof self.ontrack==='function'){self.ontrack(trackEvent);}});});}});window.setTimeout(function(){if(!(self&&self.transceivers)){return;} +self.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);return new Promise(function(resolve){if(args.length>1&&typeof args[1]==='function'){args[1].apply(null);} +resolve();});};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} +if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} +if(transceiver.rtpSender){transceiver.rtpSender.stop();} +if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this.dispatchEvent(event);if(typeof this.onsignalingstatechange==='function'){this.onsignalingstatechange(event);}};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} +this.needNegotiation=true;window.setTimeout(function(){if(self.needNegotiation===false){return;} +self.needNegotiation=false;var event=new Event('negotiationneeded');self.dispatchEvent(event);if(typeof self.onnegotiationneeded==='function'){self.onnegotiationneeded(event);}},0);};RTCPeerConnection.prototype._updateConnectionState=function(){var newState;var states={'new':0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0||states.checking>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0||states.completed>0){newState='connected';} +if(newState!==this.iceConnectionState){this.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this.dispatchEvent(event);if(typeof this.oniceconnectionstatechange==='function'){this.oniceconnectionstatechange(event);}}};RTCPeerConnection.prototype.createOffer=function(){var self=this;var args=arguments;var offerOptions;if(arguments.length===1&&typeof arguments[0]!=='function'){offerOptions=arguments[0];}else if(arguments.length===3){offerOptions=arguments[2];} +var numAudioTracks=this.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=this.transceivers.filter(function(t){return t.kind==='video';}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} +if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} +if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} +this.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){this._createTransceiver('audio');numAudioTracks--;} +if(numVideoTracks>0){this._createTransceiver('video');numVideoTracks--;}} +var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,self.usingBundle);} +var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';}});var sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'&&!sendEncodingParameters[0].rtx){sendEncodingParameters[0].rtx={ssrc:sendEncodingParameters[0].ssrc+1};}} +if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} +transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(this._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';this.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream,self._dtlsRole);sdp+='a=rtcp-rsize\r\n';if(transceiver.iceGatherer&&self.iceGatheringState!=='new'&&(sdpMLineIndex===0||!self.usingBundle)){transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1;sdp+='a='+SDPUtils.writeCandidate(cand)+'\r\n';});if(transceiver.iceGatherer.state==='completed'){sdp+='a=end-of-candidates\r\n';}}});var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});return new Promise(function(resolve){if(args.length>0&&typeof args[0]==='function'){args[0].apply(null,[desc]);resolve();return;} +resolve(desc);});};RTCPeerConnection.prototype.createAnswer=function(){var self=this;var args=arguments;var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);if(this.usingBundle){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +var mediaSectionsInOffer=SDPUtils.splitSections(this.remoteDescription.sdp).length-1;this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(sdpMLineIndex+1>mediaSectionsInOffer){return;} +if(transceiver.isDatachannel){sdp+='m=application 0 DTLS/SCTP 5000\r\n'+'c=IN IP4 0.0.0.0\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} +if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} +if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'&&!transceiver.sendEncodingParameters[0].rtx){transceiver.sendEncodingParameters[0].rtx={ssrc:transceiver.sendEncodingParameters[0].ssrc+1};}}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +sdp+=writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream,self._dtlsRole);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});return new Promise(function(resolve){if(args.length>0&&typeof args[0]==='function'){args[0].apply(null,[desc]);resolve();return;} +resolve(desc);});};RTCPeerConnection.prototype.addIceCandidate=function(candidate){var err;var sections;if(!candidate||candidate.candidate===''){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return Promise.resolve();} +if(cand.component&&cand.component!==1){return Promise.resolve();} +if(sdpMLineIndex===0||(sdpMLineIndex>0&&transceiver.iceTransport!==this.transceivers[0].iceTransport)){if(!maybeAddCandidate(transceiver.iceTransport,cand)){err=new Error('Can not add ICE candidate');err.name='OperationError';}} +if(!err){var candidateString=candidate.candidate.trim();if(candidateString.indexOf('a=')===0){candidateString=candidateString.substr(2);} +sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[sdpMLineIndex+1]+='a='+ +(cand.type?candidateString:'end-of-candidates') ++'\r\n';this.remoteDescription.sdp=sections.join('');}}else{err=new Error('Can not add ICE candidate');err.name='OperationError';}} +var args=arguments;return new Promise(function(resolve,reject){if(err){if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[err]);} +reject(err);}else{if(args.length>1&&typeof args[1]==='function'){args[1].apply(null);} +resolve();}});};RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];var fixStatsType=function(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;};return new Promise(function(resolve){var results=new Map();Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]);results.set(id,result[id]);});});if(cb){cb.apply(null,results);} +resolve(results);});});};return RTCPeerConnection;};},{"sdp":2}],2:[function(require,module,exports){'use strict';var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10);};SDPUtils.localCName=SDPUtils.generateIdentifier();SDPUtils.splitLines=function(blob){return blob.trim().split('\n').map(function(line){return line.trim();});};SDPUtils.splitSections=function(blob){var parts=blob.split('\nm=');return parts.map(function(part,index){return(index>0?'m='+part:part).trim()+'\r\n';});};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} +var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i0;rtcpParameters.compound=rsize.length===0;var mux=SDPUtils.matchPrefix(mediaSection,'a=rtcp-mux');rtcpParameters.mux=mux.length>0;return rtcpParameters;};SDPUtils.parseMsid=function(mediaSection){var parts;var spec=SDPUtils.matchPrefix(mediaSection,'a=msid:');if(spec.length===1){parts=spec[0].substr(7).split(' ');return{stream:parts[0],track:parts[1]};} -var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId){var sessionId;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} -return'v=0\r\n'+'o=thisisadapterortc '+sessionId+' 2 IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId,sessVer){var sessionId;var version=sessVer!==undefined?sessVer:2;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} +return'v=0\r\n'+'o=thisisadapterortc '+sessionId+' '+version+' IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} if(transceiver.rtpSender){var msid='msid:'+stream.id+' '+ transceiver.rtpSender.track.id+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ transceiver.sendEncodingParameters[0].ssrc+' '+ @@ -342,29 +455,42 @@ transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} return sdp;};SDPUtils.getDirection=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);for(var i=0;i=64){return;} +var origGetLocalStreams=window.RTCPeerConnection.prototype.getLocalStreams;window.RTCPeerConnection.prototype.getLocalStreams=function(){var self=this;var nativeStreams=origGetLocalStreams.apply(this);self._reverseStreams=self._reverseStreams||{};return nativeStreams.map(function(stream){return self._reverseStreams[stream.id];});};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var pc=this;pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=pc.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});if(!pc._reverseStreams[stream.id]){var newStream=new window.MediaStream(stream.getTracks());pc._streams[stream.id]=newStream;pc._reverseStreams[newStream.id]=stream;stream=newStream;} +origAddStream.apply(pc,[stream]);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){var pc=this;pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};origRemoveStream.apply(pc,[(pc._streams[stream.id]||stream)]);delete pc._reverseStreams[(pc._streams[stream.id]?pc._streams[stream.id].id:stream.id)];delete pc._streams[stream.id];};window.RTCPeerConnection.prototype.addTrack=function(track,stream){var pc=this;if(pc.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +var streams=[].slice.call(arguments,1);if(streams.length!==1||!streams[0].getTracks().find(function(t){return t===track;})){throw new DOMException('The adapter.js addTrack polyfill only supports a single '+' stream which is associated with the specified track.','NotSupportedError');} +var alreadyExists=pc.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');} +pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};var oldStream=pc._streams[stream.id];if(oldStream){oldStream.addTrack(track);Promise.resolve().then(function(){pc.dispatchEvent(new Event('negotiationneeded'));});}else{var newStream=new window.MediaStream([track]);pc._streams[stream.id]=newStream;pc._reverseStreams[newStream.id]=stream;pc.addStream(newStream);} +return pc.getSenders().find(function(s){return s.track===track;});};function replaceInternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(internalStream.id,'g'),externalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +function replaceExternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(externalStream.id,'g'),internalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +['createOffer','createAnswer'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var pc=this;var args=arguments;var isLegacyCall=arguments.length&&typeof arguments[0]==='function';if(isLegacyCall){return nativeMethod.apply(pc,[function(description){var desc=replaceInternalStreamId(pc,description);args[0].apply(null,[desc]);},function(err){if(args[1]){args[1].apply(null,err);}},arguments[2]]);} +return nativeMethod.apply(pc,arguments).then(function(description){return replaceInternalStreamId(pc,description);});};});var origSetLocalDescription=window.RTCPeerConnection.prototype.setLocalDescription;window.RTCPeerConnection.prototype.setLocalDescription=function(){var pc=this;if(!arguments.length||!arguments[0].type){return origSetLocalDescription.apply(pc,arguments);} +arguments[0]=replaceExternalStreamId(pc,arguments[0]);return origSetLocalDescription.apply(pc,arguments);};var origLocalDescription=Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype,'localDescription');Object.defineProperty(window.RTCPeerConnection.prototype,'localDescription',{get:function(){var pc=this;var description=origLocalDescription.get.apply(this);if(description.type===''){return description;} +return replaceInternalStreamId(pc,description);}});window.RTCPeerConnection.prototype.removeTrack=function(sender){var pc=this;if(pc.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +if(!sender._pc){throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.','TypeError');} +var isLocal=sender._pc===pc;if(!isLocal){throw new DOMException('Sender was not created by this connection.','InvalidAccessError');} +pc._streams=pc._streams||{};var stream;Object.keys(pc._streams).forEach(function(streamid){var hasTrack=pc._streams[streamid].getTracks().find(function(track){return sender.track===track;});if(hasTrack){stream=pc._streams[streamid];}});if(stream){if(stream.getTracks().length===1){pc.removeStream(pc._reverseStreams[stream.id]);}else{stream.removeTrack(sender.track);} +pc.dispatchEvent(new Event('negotiationneeded'));}};},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(!window.RTCPeerConnection){window.RTCPeerConnection=function(pcConfig,pcConstraints){logging('PeerConnection');if(pcConfig&&pcConfig.iceTransportPolicy){pcConfig.iceTransports=pcConfig.iceTransportPolicy;} +return new window.webkitRTCPeerConnection(pcConfig,pcConstraints);};window.RTCPeerConnection.prototype=window.webkitRTCPeerConnection.prototype;if(window.webkitRTCPeerConnection.generateCertificate){Object.defineProperty(window.RTCPeerConnection,'generateCertificate',{get:function(){return window.webkitRTCPeerConnection.generateCertificate;}});}}else{var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i0&&typeof selector==='function'){return origGetStats.apply(this,arguments);} @@ -376,123 +502,44 @@ if(browserDetails.version<52){['createOffer','createAnswer'].forEach(function(me return nativeMethod.apply(this,arguments);};});} ['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new((method==='addIceCandidate')?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} return Promise.resolve();} -return nativeAddIceCandidate.apply(this,arguments);};}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:require('./getusermedia')};},{"../utils.js":12,"./getusermedia":5}],5:[function(require,module,exports){'use strict';var utils=require('../utils.js');var logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var constraintsToChrome_=function(c){if(typeof c!=='object'||c.mandatory||c.optional){return c;} +return nativeAddIceCandidate.apply(this,arguments);};}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimAddTrackRemoveTrack:chromeShim.shimAddTrackRemoveTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:require('./getusermedia')};},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){'use strict';var utils=require('../utils.js');var logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var constraintsToChrome_=function(c){if(typeof c!=='object'||c.mandatory||c.optional){return c;} var cc={};Object.keys(c).forEach(function(key){if(key==='require'||key==='advanced'||key==='mediaSource'){return;} var r=(typeof c[key]==='object')?c[key]:{ideal:c[key]};if(r.exact!==undefined&&typeof r.exact==='number'){r.min=r.max=r.exact;} var oldname_=function(prefix,name){if(prefix){return prefix+name.charAt(0).toUpperCase()+name.slice(1);} return(name==='deviceId')?'sourceId':name;};if(r.ideal!==undefined){cc.optional=cc.optional||[];var oc={};if(typeof r.ideal==='number'){oc[oldname_('min',key)]=r.ideal;cc.optional.push(oc);oc={};oc[oldname_('max',key)]=r.ideal;cc.optional.push(oc);}else{oc[oldname_('',key)]=r.ideal;cc.optional.push(oc);}} if(r.exact!==undefined&&typeof r.exact!=='number'){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_('',key)]=r.exact;}else{['min','max'].forEach(function(mix){if(r[mix]!==undefined){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_(mix,key)]=r[mix];}});}});if(c.advanced){cc.optional=(cc.optional||[]).concat(c.advanced);} -return cc;};var shimConstraints_=function(constraints,func){constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&typeof constraints.audio==='object'){var remap=function(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} -if(constraints&&typeof constraints.video==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='object')?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<61;if((face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment'))&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} +return cc;};var shimConstraints_=function(constraints,func){if(browserDetails.version>=61){return func(constraints);} +constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&typeof constraints.audio==='object'){var remap=function(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} +if(constraints&&typeof constraints.video==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='object')?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<66;if((face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment'))&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} if(matches){return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return d.kind==='videoinput';});var dev=devices.find(function(d){return matches.some(function(match){return d.label.toLowerCase().indexOf(match)!==-1;});});if(!dev&&devices.length&&matches.indexOf('back')!==-1){dev=devices[devices.length-1];} if(dev){constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId};} constraints.video=constraintsToChrome_(constraints.video);logging('chrome: '+JSON.stringify(constraints));return func(constraints);});}} constraints.video=constraintsToChrome_(constraints.video);} -logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError',InvalidStateError:'NotReadableError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotReadableError',MediaDeviceKillSwitchOn:'NotReadableError'}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError(shimError_(e));});});};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject);});};if(!navigator.mediaDevices){navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:'audioinput',video:'videoinput'};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:''};}));});});},getSupportedConstraints:function(){return{deviceId:true,echoCancellation:true,facingMode:true,frameRate:true,height:true,width:true};}};} +logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError',InvalidStateError:'NotReadableError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotReadableError',MediaDeviceKillSwitchOn:'NotReadableError'}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){if(onError){onError(shimError_(e));}});});};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject);});};if(!navigator.mediaDevices){navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:'audioinput',video:'videoinput'};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:''};}));});});},getSupportedConstraints:function(){return{deviceId:true,echoCancellation:true,facingMode:true,frameRate:true,height:true,width:true};}};} if(!navigator.mediaDevices.getUserMedia){navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints);};}else{var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length){stream.getTracks().forEach(function(track){track.stop();});throw new DOMException('','NotFoundError');} return stream;},function(e){return Promise.reject(shimError_(e));});});};} if(typeof navigator.mediaDevices.addEventListener==='undefined'){navigator.mediaDevices.addEventListener=function(){logging('Dummy mediaDevices.addEventListener called.');};} -if(typeof navigator.mediaDevices.removeEventListener==='undefined'){navigator.mediaDevices.removeEventListener=function(){logging('Dummy mediaDevices.removeEventListener called.');};}};},{"../utils.js":12}],6:[function(require,module,exports){'use strict';var utils=require('../utils');var shimRTCPeerConnection=require('./rtcpeerconnection_shim');module.exports={shimGetUserMedia:require('./getusermedia'),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} +if(typeof navigator.mediaDevices.removeEventListener==='undefined'){navigator.mediaDevices.removeEventListener=function(){logging('Dummy mediaDevices.removeEventListener called.');};}};},{"../utils.js":13}],7:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');var utils=require('./utils');function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(!window.RTCPeerConnection){return;} +var proto=window.RTCPeerConnection.prototype;var nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap){return nativeAddEventListener.apply(this,arguments);} +var wrappedCallback=function(e){cb(wrapper(e));};this._eventMap=this._eventMap||{};this._eventMap[cb]=wrappedCallback;return nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback]);};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb]){return nativeRemoveEventListener.apply(this,arguments);} +var unwrappedCb=this._eventMap[cb];delete this._eventMap[cb];return nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb]);};Object.defineProperty(proto,'on'+eventNameToWrap,{get:function(){return this['_on'+eventNameToWrap];},set:function(cb){if(this['_on'+eventNameToWrap]){this.removeEventListener(eventNameToWrap,this['_on'+eventNameToWrap]);delete this['_on'+eventNameToWrap];} +if(cb){this.addEventListener(eventNameToWrap,this['_on'+eventNameToWrap]=cb);}}});} +module.exports={shimRTCIceCandidate:function(window){if(window.RTCIceCandidate&&'foundation'in +window.RTCIceCandidate.prototype){return;} +var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){if(typeof args==='object'&&args.candidate&&args.candidate.indexOf('a=')===0){args=JSON.parse(JSON.stringify(args));args.candidate=args.candidate.substr(2);} +var nativeCandidate=new NativeRTCIceCandidate(args);var parsedCandidate=SDPUtils.parseCandidate(args.candidate);var augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment,};};return augmentedCandidate;};wrapPeerConnectionEvent(window,'icecandidate',function(e){if(e.candidate){Object.defineProperty(e,'candidate',{value:new window.RTCIceCandidate(e.candidate),writable:'false'});} +return e;});},shimCreateObjectURL:function(window){var URL=window&&window.URL;if(!(typeof window==='object'&&window.HTMLMediaElement&&'srcObject'in window.HTMLMediaElement.prototype&&URL.createObjectURL&&URL.revokeObjectURL)){return undefined;} +var nativeCreateObjectURL=URL.createObjectURL.bind(URL);var nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL);var streams=new Map(),newId=0;URL.createObjectURL=function(stream){if('getTracks'in stream){var url='polyblob:'+(++newId);streams.set(url,stream);utils.deprecated('URL.createObjectURL(stream)','elem.srcObject = stream');return url;} +return nativeCreateObjectURL(stream);};URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url);streams.delete(url);};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,'src');Object.defineProperty(window.HTMLMediaElement.prototype,'src',{get:function(){return dsc.get.apply(this);},set:function(url){this.srcObject=streams.get(url)||null;return dsc.set.apply(this,[url]);}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){if(arguments.length===2&&(''+arguments[0]).toLowerCase()==='src'){this.srcObject=streams.get(arguments[1])||null;} +return nativeSetAttribute.apply(this,arguments);};}};},{"./utils":13,"sdp":2}],8:[function(require,module,exports){'use strict';var utils=require('../utils');var shimRTCPeerConnection=require('rtcpeerconnection-shim');module.exports={shimGetUserMedia:require('./getusermedia'),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} if(!window.RTCSessionDescription){window.RTCSessionDescription=function(args){return args;};} if(browserDetails.version<15025){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,'enabled');Object.defineProperty(window.MediaStreamTrack.prototype,'enabled',{set:function(value){origMSTEnabled.set.call(this,value);var ev=new Event('enabled');ev.enabled=value;this.dispatchEvent(ev);}});}} -window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version);},shimReplaceTrack:function(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}};},{"../utils":12,"./getusermedia":7,"./rtcpeerconnection_shim":8}],7:[function(require,module,exports){'use strict';module.exports=function(window){var navigator=window&&window.navigator;var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};};},{}],8:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');function sortTracks(tracks){var audioTracks=tracks.filter(function(track){return track.kind==='audio';});var videoTracks=tracks.filter(function(track){return track.kind==='video';});tracks=[];while(audioTracks.length||videoTracks.length){if(audioTracks.length){tracks.push(audioTracks.shift());} -if(videoTracks.length){tracks.push(videoTracks.shift());}} -return tracks;} -function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){console.warn('RTCIceServer.url is deprecated! Use urls instead.');} -var isString=typeof urls==='string';if(isString){urls=[urls];} -urls=urls.filter(function(url){var validTurn=url.indexOf('turn:')===0&&url.indexOf('transport=udp')!==-1&&url.indexOf('turn:[')===-1&&!hasTurn;if(validTurn){hasTurn=true;return true;} -return url.indexOf('stun:')===0&&edgeVersion>=14393;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;} -return false;});} -function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} -this.transceivers.push(transceiver);return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){var transceiver;for(var i=0;i=15025){this.localStreams.push(stream);stream.getTracks().forEach(function(track){self.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){self.addTrack(track,clonedStream);});this.localStreams.push(clonedStream);} -this._maybeFireNegotiationNeeded();};RTCPeerConnection.prototype.removeStream=function(stream){var idx=this.localStreams.indexOf(stream);if(idx>-1){this.localStreams.splice(idx,1);this._maybeFireNegotiationNeeded();}};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(mid,sdpMLineIndex){var self=this;var iceGatherer=new window.RTCIceGatherer(self.iceOptions);iceGatherer.onlocalcandidate=function(evt){var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state===undefined){iceGatherer.state='completed';}}else{cand.component=1;event.candidate.candidate=SDPUtils.writeCandidate(cand);} -var sections=SDPUtils.splitSections(self.localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex+1]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex+1]+='a=end-of-candidates\r\n';} -self.localDescription.sdp=sections.join('');var transceivers=self._pendingOffer?self._pendingOffer:self.transceivers;var complete=transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});switch(self.iceGatheringState){case'new':if(!end){self._localIceCandidatesBuffer.push(event);} -if(end&&complete){self._localIceCandidatesBuffer.push(new Event('icecandidate'));} -break;case'gathering':self._emitBufferedCandidates();if(!end){self.dispatchEvent(event);if(self.onicecandidate!==null){self.onicecandidate(event);}} -if(complete){self.dispatchEvent(new Event('icecandidate'));if(self.onicecandidate!==null){self.onicecandidate(new Event('icecandidate'));} -self.iceGatheringState='complete';self._emitGatheringStateChange();} -break;case'complete':break;default:break;}};return iceGatherer;};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var self=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){self._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){self._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});self._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} -var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} -var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlssttatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} -transceiver.rtpSender.send(params);} -if(recv&&transceiver.rtpReceiver){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} -params.encodings=transceiver.recvEncodingParameters;params.rtcp={cname:transceiver.rtcpParameters.cname,compound:transceiver.rtcpParameters.compound};if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} -transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var self=this;if(!isActionAllowedInSignalingState('setLocalDescription',description.type,this.signalingState)){var e=new Error('Can not set local '+description.type+' in state '+this.signalingState);e.name='InvalidStateError';if(arguments.length>2&&typeof arguments[2]==='function'){window.setTimeout(arguments[2],0,e);} -return Promise.reject(e);} -var sections;var sessionpart;if(description.type==='offer'){if(this._pendingOffer){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);self._pendingOffer[sdpMLineIndex].localCapabilities=caps;});this.transceivers=this._pendingOffer;delete this._pendingOffer;}}else if(description.type==='answer'){sections=SDPUtils.splitSections(self.remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection);if(!rejected&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} -if(!self.usingBundle||sdpMLineIndex===0){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');dtlsTransport.start(remoteDtlsParameters);} -var params=getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,false);}});} -this.localDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-local-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} -var hasCallback=arguments.length>1&&typeof arguments[1]==='function';if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb();if(self.iceGatheringState==='new'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} -self._emitBufferedCandidates();},0);} -var p=Promise.resolve();p.then(function(){if(!hasCallback){if(self.iceGatheringState==='new'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} -window.setTimeout(self._emitBufferedCandidates.bind(self),500);}});return p;};RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this;if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,this.signalingState)){var e=new Error('Can not set remote '+description.type+' in state '+this.signalingState);e.name='InvalidStateError';if(arguments.length>2&&typeof arguments[2]==='function'){window.setTimeout(arguments[2],0,e);} -return Promise.reject(e);} -var streams={};var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;this.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){this.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{this.canTrickleIceCandidates=false;} -sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection);var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(kind==='application'&&protocol==='DTLS/SCTP'){self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:true};return;} -var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} -recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component==='1'||cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&self.transceivers[sdpMLineIndex]){self._disposeIceAndDtlsTransports(sdpMLineIndex);self.transceivers[sdpMLineIndex].iceGatherer=self.transceivers[0].iceGatherer;self.transceivers[sdpMLineIndex].iceTransport=self.transceivers[0].iceTransport;self.transceivers[sdpMLineIndex].dtlsTransport=self.transceivers[0].dtlsTransport;if(self.transceivers[sdpMLineIndex].rtpSender){self.transceivers[sdpMLineIndex].rtpSender.setTransport(self.transceivers[0].dtlsTransport);} -if(self.transceivers[sdpMLineIndex].rtpReceiver){self.transceivers[sdpMLineIndex].rtpReceiver.setTransport(self.transceivers[0].dtlsTransport);}} -if(description.type==='offer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex]||self._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=usingBundle&&sdpMLineIndex>0?self.transceivers[0].iceGatherer:self._createIceGatherer(mid,sdpMLineIndex);} -if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);} -localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} -sendEncodingParameters=[{ssrc:(2*sdpMLineIndex+2)*1001}];if(direction==='sendrecv'||direction==='sendonly'){rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} -Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} -streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}} -transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;self._transceive(self.transceivers[sdpMLineIndex],false,direction==='sendrecv'||direction==='sendonly');}else if(description.type==='answer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;self.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if((isIceLite||isComplete)&&cands.length){iceTransport.setRemoteCandidates(cands);} -if(!usingBundle||sdpMLineIndex===0){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');dtlsTransport.start(remoteDtlsParameters);} -self._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} -streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} -streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});this.remoteDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-remote-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} -Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){self.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;self.dispatchEvent(event);if(self.onaddstream!==null){window.setTimeout(function(){self.onaddstream(event);},0);} -receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} -var trackEvent=new Event('track');trackEvent.track=track;trackEvent.receiver=receiver;trackEvent.streams=[stream];self.dispatchEvent(trackEvent);if(self.ontrack!==null){window.setTimeout(function(){self.ontrack(trackEvent);},0);}});}});window.setTimeout(function(){if(!(self&&self.transceivers)){return;} -self.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);if(arguments.length>1&&typeof arguments[1]==='function'){window.setTimeout(arguments[1],0);} -return Promise.resolve();};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} -if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} -if(transceiver.rtpSender){transceiver.rtpSender.stop();} -if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this.dispatchEvent(event);if(this.onsignalingstatechange!==null){this.onsignalingstatechange(event);}};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} -this.needNegotiation=true;window.setTimeout(function(){if(self.needNegotiation===false){return;} -self.needNegotiation=false;var event=new Event('negotiationneeded');self.dispatchEvent(event);if(self.onnegotiationneeded!==null){self.onnegotiationneeded(event);}},0);};RTCPeerConnection.prototype._updateConnectionState=function(){var self=this;var newState;var states={'new':0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0||states.checking>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0||states.completed>0){newState='connected';} -if(newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this.dispatchEvent(event);if(this.oniceconnectionstatechange!==null){this.oniceconnectionstatechange(event);}}};RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer){throw new Error('createOffer called while there is a pending offer.');} -var offerOptions;if(arguments.length===1&&typeof arguments[0]!=='function'){offerOptions=arguments[0];}else if(arguments.length===3){offerOptions=arguments[2];} -var numAudioTracks=this.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=this.transceivers.filter(function(t){return t.kind==='video';}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} -if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} -if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} -this.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){this._createTransceiver('audio');numAudioTracks--;} -if(numVideoTracks>0){this._createTransceiver('video');numVideoTracks--;}} -var transceivers=sortTracks(this.transceivers);var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId);transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self.usingBundle&&sdpMLineIndex>0?transceivers[0].iceGatherer:self._createIceGatherer(mid,sdpMLineIndex);} -var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} -localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';}});var sendEncodingParameters=[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'){sendEncodingParameters[0].rtx={ssrc:(2*sdpMLineIndex+1)*1001+1};}} -if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} -transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(this._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} -sdp+='a=ice-options:trickle\r\n';transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream);sdp+='a=rtcp-rsize\r\n';});this._pendingOffer=transceivers;var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});if(arguments.length&&typeof arguments[0]==='function'){window.setTimeout(arguments[0],0,desc);} -return Promise.resolve(desc);};RTCPeerConnection.prototype.createAnswer=function(){var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId);if(this.usingBundle){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} -this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(transceiver.isDatachannel){sdp+='m=application 0 DTLS/SCTP 5000\r\n'+'c=IN IP4 0.0.0.0\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} -if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} -if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'){transceiver.sendEncodingParameters[0].rtx={ssrc:(2*sdpMLineIndex+2)*1001+1};}}} -var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} -sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});if(arguments.length&&typeof arguments[0]==='function'){window.setTimeout(arguments[0],0,desc);} -return Promise.resolve(desc);};RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(!candidate){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return Promise.resolve();} -if(cand.component&&!(cand.component==='1'||cand.component===1)){return Promise.resolve();} -transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():'a=end-of-candidates')+'\r\n';this.remoteDescription.sdp=sections.join('');}} -if(arguments.length>1&&typeof arguments[1]==='function'){window.setTimeout(arguments[1],0);} -return Promise.resolve();};RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];var fixStatsType=function(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;};return new Promise(function(resolve){var results=new Map();Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]);results.set(id,result[id]);});});if(cb){window.setTimeout(cb,0,results);} -resolve(results);});});};return RTCPeerConnection;};},{"sdp":1}],9:[function(require,module,exports){'use strict';var utils=require('../utils');var firefoxShim={shimOnTrack:function(window){if(typeof window==='object'&&window.RTCPeerConnection&&!('ontrack'in +if(window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=new window.RTCDtmfSender(this);}else if(this.track.kind==='video'){this._dtmf=null;}} +return this._dtmf;}});} +window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version);},shimReplaceTrack:function(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}};},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){'use strict';module.exports=function(window){var navigator=window&&window.navigator;var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};};},{}],10:[function(require,module,exports){'use strict';var utils=require('../utils');var firefoxShim={shimOnTrack:function(window){if(typeof window==='object'&&window.RTCPeerConnection&&!('ontrack'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'ontrack',{get:function(){return this._ontrack;},set:function(f){if(this._ontrack){this.removeEventListener('track',this._ontrack);this.removeEventListener('addstream',this._ontrackpoly);} -this.addEventListener('track',this._ontrack=f);this.addEventListener('addstream',this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event('track');event.track=track;event.receiver={track:track};event.streams=[e.stream];this.dispatchEvent(event);}.bind(this));}.bind(this));}});}},shimSourceObject:function(window){if(typeof window==='object'){if(window.HTMLMediaElement&&!('srcObject'in window.HTMLMediaElement.prototype)){Object.defineProperty(window.HTMLMediaElement.prototype,'srcObject',{get:function(){return this.mozSrcObject;},set:function(stream){this.mozSrcObject=stream;}});}}},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(typeof window!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} +this.addEventListener('track',this._ontrack=f);this.addEventListener('addstream',this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event('track');event.track=track;event.receiver={track:track};event.transceiver={receiver:event.receiver};event.streams=[e.stream];this.dispatchEvent(event);}.bind(this));}.bind(this));}});} +if(typeof window==='object'&&window.RTCTrackEvent&&('receiver'in window.RTCTrackEvent.prototype)&&!('transceiver'in window.RTCTrackEvent.prototype)){Object.defineProperty(window.RTCTrackEvent.prototype,'transceiver',{get:function(){return{receiver:this.receiver};}});}},shimSourceObject:function(window){if(typeof window==='object'){if(window.HTMLMediaElement&&!('srcObject'in window.HTMLMediaElement.prototype)){Object.defineProperty(window.HTMLMediaElement.prototype,'srcObject',{get:function(){return this.mozSrcObject;},set:function(stream){this.mozSrcObject=stream;}});}}},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(typeof window!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} if(!window.RTCPeerConnection){window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i=pos&&parseInt(match[pos],10);},detectBrowser:function(window){var navigator=window&&window.navigator;var result={};result.browser=null;result.version=null;if(typeof window==='undefined'||!window.navigator){result.browser='Not a browser.';return result;} if(navigator.mozGetUserMedia){result.browser='firefox';result.version=this.extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);}else if(navigator.webkitGetUserMedia){if(window.webkitRTCPeerConnection){result.browser='chrome';result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);}else{if(navigator.userAgent.match(/Version\/(\d+).(\d+)/)){result.browser='safari';result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Unsupported webkit-based browser '+'with GUM support but no WebRTC support.';return result;}}}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)){result.browser='edge';result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);}else if(navigator.mediaDevices&&navigator.userAgent.match(/AppleWebKit\/(\d+)\./)){result.browser='safari';result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Not a supported browser.';return result;} -return result;},shimCreateObjectURL:function(window){var URL=window&&window.URL;if(!(typeof window==='object'&&window.HTMLMediaElement&&'srcObject'in window.HTMLMediaElement.prototype)){return undefined;} -var nativeCreateObjectURL=URL.createObjectURL.bind(URL);var nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL);var streams=new Map(),newId=0;URL.createObjectURL=function(stream){if('getTracks'in stream){var url='polyblob:'+(++newId);streams.set(url,stream);utils.deprecated('URL.createObjectURL(stream)','elem.srcObject = stream');return url;} -return nativeCreateObjectURL(stream);};URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url);streams.delete(url);};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,'src');Object.defineProperty(window.HTMLMediaElement.prototype,'src',{get:function(){return dsc.get.apply(this);},set:function(url){this.srcObject=streams.get(url)||null;return dsc.set.apply(this,[url]);}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){if(arguments.length===2&&(''+arguments[0]).toLowerCase()==='src'){this.srcObject=streams.get(arguments[1])||null;} -return nativeSetAttribute.apply(this,arguments);};}};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)};},{}]},{},[2])(2)}); \ No newline at end of file +return result;},};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)};},{}]},{},[3])(3)}); \ No newline at end of file diff --git a/html5/verto/video_demo/js/verto-min.js b/html5/verto/video_demo/js/verto-min.js index c93b8aca64..fdf5432fa5 100644 --- a/html5/verto/video_demo/js/verto-min.js +++ b/html5/verto/video_demo/js/verto-min.js @@ -56,7 +56,7 @@ function onSuccess(stream){self.localStream=stream;if(screen){self.constraints.o self.peer=FSRTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:screen?function(stream){}:function(stream){return onRemoteStream(self,stream);},onOfferSDP:function(sdp){return onOfferSDP(self,sdp);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints,iceServers:self.options.iceServers,});onStreamSuccess(self,stream);} function onError(e){onStreamError(self,e);} var mediaParams=getMediaParams(self);console.log("Audio constraints",mediaParams.audio);console.log("Video constraints",mediaParams.video);if(mediaParams.audio||mediaParams.video){getUserMedia({constraints:{audio:mediaParams.audio,video:mediaParams.video},video:mediaParams.useVideo,onsuccess:onSuccess,onerror:onError});}else{onSuccess(null);}};function FSRTCPeerConnection(options){var gathering=false,done=false;var config={};var default_ice={urls:['stun:stun.l.google.com:19302']};if(options.iceServers){if(typeof(options.iceServers)==="boolean"){config.iceServers=[default_ice];}else{config.iceServers=options.iceServers;}} -var peer=new window.RTCPeerConnection(config);openOffererChannel();var x=0;function ice_handler(){done=true;gathering=null;if(options.onICEComplete){options.onICEComplete();} +config.bundlePolicy="max-compat";var peer=new window.RTCPeerConnection(config);openOffererChannel();var x=0;function ice_handler(){done=true;gathering=null;if(options.onICEComplete){options.onICEComplete();} if(options.type=="offer"){options.onICESDP(peer.localDescription);}else{if(!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}} peer.onicecandidate=function(event){if(done){return;} if(!gathering){gathering=setTimeout(ice_handler,1000);} @@ -163,6 +163,7 @@ if(sendChannels.length){verto.sendMethod("verto.unsubscribe",{eventChannel:sendC verto.sendMethod("verto.broadcast",msg);};$.verto.prototype.purge=function(callID){var verto=this;var x=0;var i;for(i in verto.dialogs){if(!x){console.log("purging dialogs");} x++;verto.dialogs[i].setState($.verto.enum.state.purge);} for(i in verto.eventSUBS){if(verto.eventSUBS[i]){console.log("purging subscription: "+i);delete verto.eventSUBS[i];}}};$.verto.prototype.hangup=function(callID){var verto=this;if(callID){var dialog=verto.dialogs[callID];if(dialog){dialog.hangup();}}else{for(var i in verto.dialogs){verto.dialogs[i].hangup();}}};$.verto.prototype.newCall=function(args,callbacks){var verto=this;if(!verto.rpcClient.socketReady()){console.error("Not Connected...");return;} +if(args["useCamera"]){verto.options.deviceParams["useCamera"]=args["useCamera"];} var dialog=new $.verto.dialog($.verto.enum.direction.outbound,this,args);dialog.invite();if(callbacks){dialog.callbacks=callbacks;} return dialog;};$.verto.prototype.handleMessage=function(data){var verto=this;if(!(data&&data.method)){console.error("Invalid Data",data);return;} if(data.params.callID){var dialog=verto.dialogs[data.params.callID];if(data.method==="verto.attach"&&dialog){delete dialog.verto.dialogs[dialog.callID];dialog.rtc.stop();dialog=null;} @@ -306,8 +307,120 @@ navigator.getUserMedia({audio:(has_audio>0?true:false),video:(has_video>0?true:f navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError);};$.verto.refreshDevices=function(runtime){checkDevices(runtime);} $.verto.init=function(obj,runtime){if(!obj){obj={};} if(!obj.skipPermCheck&&!obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){checkDevices(runtime);},true,true);}else if(obj.skipPermCheck&&!obj.skipDeviceCheck){checkDevices(runtime);}else if(!obj.skipPermCheck&&obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){runtime(status);},true,true);}else{runtime(null);}} -$.verto.genUUID=function(){return generateGUID();}})(jQuery);(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter=f()}})(function(){var define,module,exports;return(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0?'m='+part:part).trim()+'\r\n';});};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} -var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i=14393&&url.indexOf('?transport=udp')===-1;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;} +return false;});} +function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;i--){this._iceGatherers=new window.RTCIceGatherer({iceServers:config.iceServers,gatherPolicy:config.iceTransportPolicy});}}else{config.iceCandidatePoolSize=0;} +this._config=config;this.transceivers=[];this._sdpSessionId=SDPUtils.generateSessionId();this._sdpSessionVersion=0;this._dtlsRole=undefined;};RTCPeerConnection.prototype._emitGatheringStateChange=function(){var event=new Event('icegatheringstatechange');this.dispatchEvent(event);if(typeof this.onicegatheringstatechange==='function'){this.onicegatheringstatechange(event);}};RTCPeerConnection.prototype.getConfiguration=function(){return this._config;};RTCPeerConnection.prototype.getLocalStreams=function(){return this.localStreams;};RTCPeerConnection.prototype.getRemoteStreams=function(){return this.remoteStreams;};RTCPeerConnection.prototype._createTransceiver=function(kind){var hasBundleTransport=this.transceivers.length>0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} +this.transceivers.push(transceiver);return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){var transceiver;for(var i=0;i=15025){stream.getTracks().forEach(function(track){self.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){self.addTrack(track,clonedStream);});}};RTCPeerConnection.prototype.removeStream=function(stream){var idx=this.localStreams.indexOf(stream);if(idx>-1){this.localStreams.splice(idx,1);this._maybeFireNegotiationNeeded();}};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(sdpMLineIndex,usingBundle){var self=this;if(usingBundle&&sdpMLineIndex>0){return this.transceivers[0].iceGatherer;}else if(this._iceGatherers.length){return this._iceGatherers.shift();} +var iceGatherer=new window.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});Object.defineProperty(iceGatherer,'state',{value:'new',writable:true});this.transceivers[sdpMLineIndex].candidates=[];this.transceivers[sdpMLineIndex].bufferCandidates=function(event){var end=!event.candidate||Object.keys(event.candidate).length===0;iceGatherer.state=end?'completed':'gathering';if(self.transceivers[sdpMLineIndex].candidates!==null){self.transceivers[sdpMLineIndex].candidates.push(event.candidate);}};iceGatherer.addEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);return iceGatherer;};RTCPeerConnection.prototype._gather=function(mid,sdpMLineIndex){var self=this;var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer.onlocalcandidate){return;} +var candidates=this.transceivers[sdpMLineIndex].candidates;this.transceivers[sdpMLineIndex].candidates=null;iceGatherer.removeEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);iceGatherer.onlocalcandidate=function(evt){if(self.usingBundle&&sdpMLineIndex>0){return;} +var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state==='new'||iceGatherer.state==='gathering'){iceGatherer.state='completed';}}else{if(iceGatherer.state==='new'){iceGatherer.state='gathering';} +cand.component=1;event.candidate.candidate=SDPUtils.writeCandidate(cand);} +var sections=SDPUtils.splitSections(self.localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex+1]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex+1]+='a=end-of-candidates\r\n';} +self.localDescription.sdp=sections.join('');var complete=self.transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});if(self.iceGatheringState!=='gathering'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} +if(!end){self.dispatchEvent(event);if(typeof self.onicecandidate==='function'){self.onicecandidate(event);}} +if(complete){self.dispatchEvent(new Event('icecandidate'));if(typeof self.onicecandidate==='function'){self.onicecandidate(new Event('icecandidate'));} +self.iceGatheringState='complete';self._emitGatheringStateChange();}};window.setTimeout(function(){candidates.forEach(function(candidate){var e=new Event('RTCIceGatherEvent');e.candidate=candidate;iceGatherer.onlocalcandidate(e);});},0);};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var self=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){self._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){self._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});self._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} +var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} +var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlsstatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} +transceiver.rtpSender.send(params);} +if(recv&&transceiver.rtpReceiver&¶ms.codecs.length>0){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} +params.encodings=transceiver.recvEncodingParameters;params.rtcp={cname:transceiver.rtcpParameters.cname,compound:transceiver.rtcpParameters.compound};if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} +transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var self=this;var args=arguments;if(!isActionAllowedInSignalingState('setLocalDescription',description.type,this.signalingState)){return new Promise(function(resolve,reject){var e=new Error('Can not set local '+description.type+' in state '+self.signalingState);e.name='InvalidStateError';if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[e]);} +reject(e);});} +var sections;var sessionpart;if(description.type==='offer'){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);self.transceivers[sdpMLineIndex].localCapabilities=caps;});this.transceivers.forEach(function(transceiver,sdpMLineIndex){self._gather(transceiver.mid,sdpMLineIndex);});}else if(description.type==='answer'){sections=SDPUtils.splitSections(self.remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection)&&!SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===1;if(!rejected&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} +if(!self.usingBundle||sdpMLineIndex===0){self._gather(transceiver.mid,sdpMLineIndex);if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var params=getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,false);}});} +this.localDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-local-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} +var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];return new Promise(function(resolve){if(cb){cb.apply(null);} +resolve();});};RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this;var args=arguments;if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,this.signalingState)){return new Promise(function(resolve,reject){var e=new Error('Can not set remote '+description.type+' in state '+self.signalingState);e.name='InvalidStateError';if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[e]);} +reject(e);});} +var streams={};this.remoteStreams.forEach(function(stream){streams[stream.id]=stream;});var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;this.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){this.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{this.canTrickleIceCandidates=false;} +sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection)&&!SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===1;var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(kind==='application'&&protocol==='DTLS/SCTP'){self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:true};return;} +var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} +recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&self.transceivers[sdpMLineIndex]){self._disposeIceAndDtlsTransports(sdpMLineIndex);self.transceivers[sdpMLineIndex].iceGatherer=self.transceivers[0].iceGatherer;self.transceivers[sdpMLineIndex].iceTransport=self.transceivers[0].iceTransport;self.transceivers[sdpMLineIndex].dtlsTransport=self.transceivers[0].dtlsTransport;if(self.transceivers[sdpMLineIndex].rtpSender){self.transceivers[sdpMLineIndex].rtpSender.setTransport(self.transceivers[0].dtlsTransport);} +if(self.transceivers[sdpMLineIndex].rtpReceiver){self.transceivers[sdpMLineIndex].rtpReceiver.setTransport(self.transceivers[0].dtlsTransport);}} +if(description.type==='offer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex]||self._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,usingBundle);} +if(cands.length&&transceiver.iceTransport.state==='new'){if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+2)*1001}];var isNewTrack=false;if(direction==='sendrecv'||direction==='sendonly'){isNewTrack=!transceiver.rtpReceiver;rtpReceiver=transceiver.rtpReceiver||new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);if(isNewTrack){var stream;track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} +Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});stream=streams[remoteMsid.stream];}else{if(!streams.default){streams.default=new window.MediaStream();} +stream=streams.default;} +stream.addTrack(track);receiverList.push([track,rtpReceiver,stream]);}} +transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;self._transceive(self.transceivers[sdpMLineIndex],false,isNewTrack);}else if(description.type==='answer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;self.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if(cands.length&&iceTransport.state==='new'){if((isIceLite||isComplete)&&(!usingBundle||sdpMLineIndex===0)){iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +if(!usingBundle||sdpMLineIndex===0){if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +self._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} +streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} +streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});if(this._dtlsRole===undefined){this._dtlsRole=description.type==='offer'?'active':'passive';} +this.remoteDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-remote-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} +Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){if(self.remoteStreams.indexOf(stream)===-1){self.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;window.setTimeout(function(){self.dispatchEvent(event);if(typeof self.onaddstream==='function'){self.onaddstream(event);}});} +receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} +var trackEvent=new Event('track');trackEvent.track=track;trackEvent.receiver=receiver;trackEvent.transceiver={receiver:receiver};trackEvent.streams=[stream];window.setTimeout(function(){self.dispatchEvent(trackEvent);if(typeof self.ontrack==='function'){self.ontrack(trackEvent);}});});}});window.setTimeout(function(){if(!(self&&self.transceivers)){return;} +self.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);return new Promise(function(resolve){if(args.length>1&&typeof args[1]==='function'){args[1].apply(null);} +resolve();});};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} +if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} +if(transceiver.rtpSender){transceiver.rtpSender.stop();} +if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this.dispatchEvent(event);if(typeof this.onsignalingstatechange==='function'){this.onsignalingstatechange(event);}};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} +this.needNegotiation=true;window.setTimeout(function(){if(self.needNegotiation===false){return;} +self.needNegotiation=false;var event=new Event('negotiationneeded');self.dispatchEvent(event);if(typeof self.onnegotiationneeded==='function'){self.onnegotiationneeded(event);}},0);};RTCPeerConnection.prototype._updateConnectionState=function(){var newState;var states={'new':0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0||states.checking>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0||states.completed>0){newState='connected';} +if(newState!==this.iceConnectionState){this.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this.dispatchEvent(event);if(typeof this.oniceconnectionstatechange==='function'){this.oniceconnectionstatechange(event);}}};RTCPeerConnection.prototype.createOffer=function(){var self=this;var args=arguments;var offerOptions;if(arguments.length===1&&typeof arguments[0]!=='function'){offerOptions=arguments[0];}else if(arguments.length===3){offerOptions=arguments[2];} +var numAudioTracks=this.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=this.transceivers.filter(function(t){return t.kind==='video';}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} +if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} +if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} +this.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){this._createTransceiver('audio');numAudioTracks--;} +if(numVideoTracks>0){this._createTransceiver('video');numVideoTracks--;}} +var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);this.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self._createIceGatherer(sdpMLineIndex,self.usingBundle);} +var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';}});var sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'&&!sendEncodingParameters[0].rtx){sendEncodingParameters[0].rtx={ssrc:sendEncodingParameters[0].ssrc+1};}} +if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} +transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(this._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';this.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream,self._dtlsRole);sdp+='a=rtcp-rsize\r\n';if(transceiver.iceGatherer&&self.iceGatheringState!=='new'&&(sdpMLineIndex===0||!self.usingBundle)){transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1;sdp+='a='+SDPUtils.writeCandidate(cand)+'\r\n';});if(transceiver.iceGatherer.state==='completed'){sdp+='a=end-of-candidates\r\n';}}});var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});return new Promise(function(resolve){if(args.length>0&&typeof args[0]==='function'){args[0].apply(null,[desc]);resolve();return;} +resolve(desc);});};RTCPeerConnection.prototype.createAnswer=function(){var self=this;var args=arguments;var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId,this._sdpSessionVersion++);if(this.usingBundle){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +var mediaSectionsInOffer=SDPUtils.splitSections(this.remoteDescription.sdp).length-1;this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(sdpMLineIndex+1>mediaSectionsInOffer){return;} +if(transceiver.isDatachannel){sdp+='m=application 0 DTLS/SCTP 5000\r\n'+'c=IN IP4 0.0.0.0\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} +if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} +if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'&&!transceiver.sendEncodingParameters[0].rtx){transceiver.sendEncodingParameters[0].rtx={ssrc:transceiver.sendEncodingParameters[0].ssrc+1};}}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +sdp+=writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream,self._dtlsRole);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});return new Promise(function(resolve){if(args.length>0&&typeof args[0]==='function'){args[0].apply(null,[desc]);resolve();return;} +resolve(desc);});};RTCPeerConnection.prototype.addIceCandidate=function(candidate){var err;var sections;if(!candidate||candidate.candidate===''){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return Promise.resolve();} +if(cand.component&&cand.component!==1){return Promise.resolve();} +if(sdpMLineIndex===0||(sdpMLineIndex>0&&transceiver.iceTransport!==this.transceivers[0].iceTransport)){if(!maybeAddCandidate(transceiver.iceTransport,cand)){err=new Error('Can not add ICE candidate');err.name='OperationError';}} +if(!err){var candidateString=candidate.candidate.trim();if(candidateString.indexOf('a=')===0){candidateString=candidateString.substr(2);} +sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[sdpMLineIndex+1]+='a='+ +(cand.type?candidateString:'end-of-candidates') ++'\r\n';this.remoteDescription.sdp=sections.join('');}}else{err=new Error('Can not add ICE candidate');err.name='OperationError';}} +var args=arguments;return new Promise(function(resolve,reject){if(err){if(args.length>2&&typeof args[2]==='function'){args[2].apply(null,[err]);} +reject(err);}else{if(args.length>1&&typeof args[1]==='function'){args[1].apply(null);} +resolve();}});};RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];var fixStatsType=function(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;};return new Promise(function(resolve){var results=new Map();Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]);results.set(id,result[id]);});});if(cb){cb.apply(null,results);} +resolve(results);});});};return RTCPeerConnection;};},{"sdp":2}],2:[function(require,module,exports){'use strict';var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10);};SDPUtils.localCName=SDPUtils.generateIdentifier();SDPUtils.splitLines=function(blob){return blob.trim().split('\n').map(function(line){return line.trim();});};SDPUtils.splitSections=function(blob){var parts=blob.split('\nm=');return parts.map(function(part,index){return(index>0?'m='+part:part).trim()+'\r\n';});};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} +var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i0;rtcpParameters.compound=rsize.length===0;var mux=SDPUtils.matchPrefix(mediaSection,'a=rtcp-mux');rtcpParameters.mux=mux.length>0;return rtcpParameters;};SDPUtils.parseMsid=function(mediaSection){var parts;var spec=SDPUtils.matchPrefix(mediaSection,'a=msid:');if(spec.length===1){parts=spec[0].substr(7).split(' ');return{stream:parts[0],track:parts[1]};} -var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId){var sessionId;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} -return'v=0\r\n'+'o=thisisadapterortc '+sessionId+' 2 IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId,sessVer){var sessionId;var version=sessVer!==undefined?sessVer:2;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} +return'v=0\r\n'+'o=thisisadapterortc '+sessionId+' '+version+' IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} if(transceiver.rtpSender){var msid='msid:'+stream.id+' '+ transceiver.rtpSender.track.id+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ transceiver.sendEncodingParameters[0].ssrc+' '+ @@ -342,29 +455,42 @@ transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} return sdp;};SDPUtils.getDirection=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);for(var i=0;i=64){return;} +var origGetLocalStreams=window.RTCPeerConnection.prototype.getLocalStreams;window.RTCPeerConnection.prototype.getLocalStreams=function(){var self=this;var nativeStreams=origGetLocalStreams.apply(this);self._reverseStreams=self._reverseStreams||{};return nativeStreams.map(function(stream){return self._reverseStreams[stream.id];});};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var pc=this;pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=pc.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});if(!pc._reverseStreams[stream.id]){var newStream=new window.MediaStream(stream.getTracks());pc._streams[stream.id]=newStream;pc._reverseStreams[newStream.id]=stream;stream=newStream;} +origAddStream.apply(pc,[stream]);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){var pc=this;pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};origRemoveStream.apply(pc,[(pc._streams[stream.id]||stream)]);delete pc._reverseStreams[(pc._streams[stream.id]?pc._streams[stream.id].id:stream.id)];delete pc._streams[stream.id];};window.RTCPeerConnection.prototype.addTrack=function(track,stream){var pc=this;if(pc.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +var streams=[].slice.call(arguments,1);if(streams.length!==1||!streams[0].getTracks().find(function(t){return t===track;})){throw new DOMException('The adapter.js addTrack polyfill only supports a single '+' stream which is associated with the specified track.','NotSupportedError');} +var alreadyExists=pc.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');} +pc._streams=pc._streams||{};pc._reverseStreams=pc._reverseStreams||{};var oldStream=pc._streams[stream.id];if(oldStream){oldStream.addTrack(track);Promise.resolve().then(function(){pc.dispatchEvent(new Event('negotiationneeded'));});}else{var newStream=new window.MediaStream([track]);pc._streams[stream.id]=newStream;pc._reverseStreams[newStream.id]=stream;pc.addStream(newStream);} +return pc.getSenders().find(function(s){return s.track===track;});};function replaceInternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(internalStream.id,'g'),externalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +function replaceExternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(externalStream.id,'g'),internalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +['createOffer','createAnswer'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var pc=this;var args=arguments;var isLegacyCall=arguments.length&&typeof arguments[0]==='function';if(isLegacyCall){return nativeMethod.apply(pc,[function(description){var desc=replaceInternalStreamId(pc,description);args[0].apply(null,[desc]);},function(err){if(args[1]){args[1].apply(null,err);}},arguments[2]]);} +return nativeMethod.apply(pc,arguments).then(function(description){return replaceInternalStreamId(pc,description);});};});var origSetLocalDescription=window.RTCPeerConnection.prototype.setLocalDescription;window.RTCPeerConnection.prototype.setLocalDescription=function(){var pc=this;if(!arguments.length||!arguments[0].type){return origSetLocalDescription.apply(pc,arguments);} +arguments[0]=replaceExternalStreamId(pc,arguments[0]);return origSetLocalDescription.apply(pc,arguments);};var origLocalDescription=Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype,'localDescription');Object.defineProperty(window.RTCPeerConnection.prototype,'localDescription',{get:function(){var pc=this;var description=origLocalDescription.get.apply(this);if(description.type===''){return description;} +return replaceInternalStreamId(pc,description);}});window.RTCPeerConnection.prototype.removeTrack=function(sender){var pc=this;if(pc.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +if(!sender._pc){throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.','TypeError');} +var isLocal=sender._pc===pc;if(!isLocal){throw new DOMException('Sender was not created by this connection.','InvalidAccessError');} +pc._streams=pc._streams||{};var stream;Object.keys(pc._streams).forEach(function(streamid){var hasTrack=pc._streams[streamid].getTracks().find(function(track){return sender.track===track;});if(hasTrack){stream=pc._streams[streamid];}});if(stream){if(stream.getTracks().length===1){pc.removeStream(pc._reverseStreams[stream.id]);}else{stream.removeTrack(sender.track);} +pc.dispatchEvent(new Event('negotiationneeded'));}};},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(!window.RTCPeerConnection){window.RTCPeerConnection=function(pcConfig,pcConstraints){logging('PeerConnection');if(pcConfig&&pcConfig.iceTransportPolicy){pcConfig.iceTransports=pcConfig.iceTransportPolicy;} +return new window.webkitRTCPeerConnection(pcConfig,pcConstraints);};window.RTCPeerConnection.prototype=window.webkitRTCPeerConnection.prototype;if(window.webkitRTCPeerConnection.generateCertificate){Object.defineProperty(window.RTCPeerConnection,'generateCertificate',{get:function(){return window.webkitRTCPeerConnection.generateCertificate;}});}}else{var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i0&&typeof selector==='function'){return origGetStats.apply(this,arguments);} @@ -376,123 +502,44 @@ if(browserDetails.version<52){['createOffer','createAnswer'].forEach(function(me return nativeMethod.apply(this,arguments);};});} ['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new((method==='addIceCandidate')?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} return Promise.resolve();} -return nativeAddIceCandidate.apply(this,arguments);};}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:require('./getusermedia')};},{"../utils.js":12,"./getusermedia":5}],5:[function(require,module,exports){'use strict';var utils=require('../utils.js');var logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var constraintsToChrome_=function(c){if(typeof c!=='object'||c.mandatory||c.optional){return c;} +return nativeAddIceCandidate.apply(this,arguments);};}};module.exports={shimMediaStream:chromeShim.shimMediaStream,shimOnTrack:chromeShim.shimOnTrack,shimAddTrackRemoveTrack:chromeShim.shimAddTrackRemoveTrack,shimGetSendersWithDtmf:chromeShim.shimGetSendersWithDtmf,shimSourceObject:chromeShim.shimSourceObject,shimPeerConnection:chromeShim.shimPeerConnection,shimGetUserMedia:require('./getusermedia')};},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){'use strict';var utils=require('../utils.js');var logging=utils.log;module.exports=function(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var constraintsToChrome_=function(c){if(typeof c!=='object'||c.mandatory||c.optional){return c;} var cc={};Object.keys(c).forEach(function(key){if(key==='require'||key==='advanced'||key==='mediaSource'){return;} var r=(typeof c[key]==='object')?c[key]:{ideal:c[key]};if(r.exact!==undefined&&typeof r.exact==='number'){r.min=r.max=r.exact;} var oldname_=function(prefix,name){if(prefix){return prefix+name.charAt(0).toUpperCase()+name.slice(1);} return(name==='deviceId')?'sourceId':name;};if(r.ideal!==undefined){cc.optional=cc.optional||[];var oc={};if(typeof r.ideal==='number'){oc[oldname_('min',key)]=r.ideal;cc.optional.push(oc);oc={};oc[oldname_('max',key)]=r.ideal;cc.optional.push(oc);}else{oc[oldname_('',key)]=r.ideal;cc.optional.push(oc);}} if(r.exact!==undefined&&typeof r.exact!=='number'){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_('',key)]=r.exact;}else{['min','max'].forEach(function(mix){if(r[mix]!==undefined){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_(mix,key)]=r[mix];}});}});if(c.advanced){cc.optional=(cc.optional||[]).concat(c.advanced);} -return cc;};var shimConstraints_=function(constraints,func){constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&typeof constraints.audio==='object'){var remap=function(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} -if(constraints&&typeof constraints.video==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='object')?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<61;if((face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment'))&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} +return cc;};var shimConstraints_=function(constraints,func){if(browserDetails.version>=61){return func(constraints);} +constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&typeof constraints.audio==='object'){var remap=function(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} +if(constraints&&typeof constraints.video==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='object')?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<66;if((face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment'))&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} if(matches){return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return d.kind==='videoinput';});var dev=devices.find(function(d){return matches.some(function(match){return d.label.toLowerCase().indexOf(match)!==-1;});});if(!dev&&devices.length&&matches.indexOf('back')!==-1){dev=devices[devices.length-1];} if(dev){constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId};} constraints.video=constraintsToChrome_(constraints.video);logging('chrome: '+JSON.stringify(constraints));return func(constraints);});}} constraints.video=constraintsToChrome_(constraints.video);} -logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError',InvalidStateError:'NotReadableError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotReadableError',MediaDeviceKillSwitchOn:'NotReadableError'}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){onError(shimError_(e));});});};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject);});};if(!navigator.mediaDevices){navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:'audioinput',video:'videoinput'};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:''};}));});});},getSupportedConstraints:function(){return{deviceId:true,echoCancellation:true,facingMode:true,frameRate:true,height:true,width:true};}};} +logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError',InvalidStateError:'NotReadableError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotReadableError',MediaDeviceKillSwitchOn:'NotReadableError'}[e.name]||e.name,message:e.message,constraint:e.constraintName,toString:function(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){if(onError){onError(shimError_(e));}});});};navigator.getUserMedia=getUserMedia_;var getUserMediaPromise_=function(constraints){return new Promise(function(resolve,reject){navigator.getUserMedia(constraints,resolve,reject);});};if(!navigator.mediaDevices){navigator.mediaDevices={getUserMedia:getUserMediaPromise_,enumerateDevices:function(){return new Promise(function(resolve){var kinds={audio:'audioinput',video:'videoinput'};return window.MediaStreamTrack.getSources(function(devices){resolve(devices.map(function(device){return{label:device.label,kind:kinds[device.kind],deviceId:device.id,groupId:''};}));});});},getSupportedConstraints:function(){return{deviceId:true,echoCancellation:true,facingMode:true,frameRate:true,height:true,width:true};}};} if(!navigator.mediaDevices.getUserMedia){navigator.mediaDevices.getUserMedia=function(constraints){return getUserMediaPromise_(constraints);};}else{var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length){stream.getTracks().forEach(function(track){track.stop();});throw new DOMException('','NotFoundError');} return stream;},function(e){return Promise.reject(shimError_(e));});});};} if(typeof navigator.mediaDevices.addEventListener==='undefined'){navigator.mediaDevices.addEventListener=function(){logging('Dummy mediaDevices.addEventListener called.');};} -if(typeof navigator.mediaDevices.removeEventListener==='undefined'){navigator.mediaDevices.removeEventListener=function(){logging('Dummy mediaDevices.removeEventListener called.');};}};},{"../utils.js":12}],6:[function(require,module,exports){'use strict';var utils=require('../utils');var shimRTCPeerConnection=require('./rtcpeerconnection_shim');module.exports={shimGetUserMedia:require('./getusermedia'),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} +if(typeof navigator.mediaDevices.removeEventListener==='undefined'){navigator.mediaDevices.removeEventListener=function(){logging('Dummy mediaDevices.removeEventListener called.');};}};},{"../utils.js":13}],7:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');var utils=require('./utils');function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(!window.RTCPeerConnection){return;} +var proto=window.RTCPeerConnection.prototype;var nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap){return nativeAddEventListener.apply(this,arguments);} +var wrappedCallback=function(e){cb(wrapper(e));};this._eventMap=this._eventMap||{};this._eventMap[cb]=wrappedCallback;return nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback]);};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb]){return nativeRemoveEventListener.apply(this,arguments);} +var unwrappedCb=this._eventMap[cb];delete this._eventMap[cb];return nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb]);};Object.defineProperty(proto,'on'+eventNameToWrap,{get:function(){return this['_on'+eventNameToWrap];},set:function(cb){if(this['_on'+eventNameToWrap]){this.removeEventListener(eventNameToWrap,this['_on'+eventNameToWrap]);delete this['_on'+eventNameToWrap];} +if(cb){this.addEventListener(eventNameToWrap,this['_on'+eventNameToWrap]=cb);}}});} +module.exports={shimRTCIceCandidate:function(window){if(window.RTCIceCandidate&&'foundation'in +window.RTCIceCandidate.prototype){return;} +var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){if(typeof args==='object'&&args.candidate&&args.candidate.indexOf('a=')===0){args=JSON.parse(JSON.stringify(args));args.candidate=args.candidate.substr(2);} +var nativeCandidate=new NativeRTCIceCandidate(args);var parsedCandidate=SDPUtils.parseCandidate(args.candidate);var augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment,};};return augmentedCandidate;};wrapPeerConnectionEvent(window,'icecandidate',function(e){if(e.candidate){Object.defineProperty(e,'candidate',{value:new window.RTCIceCandidate(e.candidate),writable:'false'});} +return e;});},shimCreateObjectURL:function(window){var URL=window&&window.URL;if(!(typeof window==='object'&&window.HTMLMediaElement&&'srcObject'in window.HTMLMediaElement.prototype&&URL.createObjectURL&&URL.revokeObjectURL)){return undefined;} +var nativeCreateObjectURL=URL.createObjectURL.bind(URL);var nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL);var streams=new Map(),newId=0;URL.createObjectURL=function(stream){if('getTracks'in stream){var url='polyblob:'+(++newId);streams.set(url,stream);utils.deprecated('URL.createObjectURL(stream)','elem.srcObject = stream');return url;} +return nativeCreateObjectURL(stream);};URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url);streams.delete(url);};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,'src');Object.defineProperty(window.HTMLMediaElement.prototype,'src',{get:function(){return dsc.get.apply(this);},set:function(url){this.srcObject=streams.get(url)||null;return dsc.set.apply(this,[url]);}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){if(arguments.length===2&&(''+arguments[0]).toLowerCase()==='src'){this.srcObject=streams.get(arguments[1])||null;} +return nativeSetAttribute.apply(this,arguments);};}};},{"./utils":13,"sdp":2}],8:[function(require,module,exports){'use strict';var utils=require('../utils');var shimRTCPeerConnection=require('rtcpeerconnection-shim');module.exports={shimGetUserMedia:require('./getusermedia'),shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} if(!window.RTCSessionDescription){window.RTCSessionDescription=function(args){return args;};} if(browserDetails.version<15025){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,'enabled');Object.defineProperty(window.MediaStreamTrack.prototype,'enabled',{set:function(value){origMSTEnabled.set.call(this,value);var ev=new Event('enabled');ev.enabled=value;this.dispatchEvent(ev);}});}} -window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version);},shimReplaceTrack:function(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}};},{"../utils":12,"./getusermedia":7,"./rtcpeerconnection_shim":8}],7:[function(require,module,exports){'use strict';module.exports=function(window){var navigator=window&&window.navigator;var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};};},{}],8:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');function sortTracks(tracks){var audioTracks=tracks.filter(function(track){return track.kind==='audio';});var videoTracks=tracks.filter(function(track){return track.kind==='video';});tracks=[];while(audioTracks.length||videoTracks.length){if(audioTracks.length){tracks.push(audioTracks.shift());} -if(videoTracks.length){tracks.push(videoTracks.shift());}} -return tracks;} -function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){console.warn('RTCIceServer.url is deprecated! Use urls instead.');} -var isString=typeof urls==='string';if(isString){urls=[urls];} -urls=urls.filter(function(url){var validTurn=url.indexOf('turn:')===0&&url.indexOf('transport=udp')!==-1&&url.indexOf('turn:[')===-1&&!hasTurn;if(validTurn){hasTurn=true;return true;} -return url.indexOf('stun:')===0&&edgeVersion>=14393;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;} -return false;});} -function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} -this.transceivers.push(transceiver);return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){var transceiver;for(var i=0;i=15025){this.localStreams.push(stream);stream.getTracks().forEach(function(track){self.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){self.addTrack(track,clonedStream);});this.localStreams.push(clonedStream);} -this._maybeFireNegotiationNeeded();};RTCPeerConnection.prototype.removeStream=function(stream){var idx=this.localStreams.indexOf(stream);if(idx>-1){this.localStreams.splice(idx,1);this._maybeFireNegotiationNeeded();}};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(mid,sdpMLineIndex){var self=this;var iceGatherer=new window.RTCIceGatherer(self.iceOptions);iceGatherer.onlocalcandidate=function(evt){var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state===undefined){iceGatherer.state='completed';}}else{cand.component=1;event.candidate.candidate=SDPUtils.writeCandidate(cand);} -var sections=SDPUtils.splitSections(self.localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex+1]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex+1]+='a=end-of-candidates\r\n';} -self.localDescription.sdp=sections.join('');var transceivers=self._pendingOffer?self._pendingOffer:self.transceivers;var complete=transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});switch(self.iceGatheringState){case'new':if(!end){self._localIceCandidatesBuffer.push(event);} -if(end&&complete){self._localIceCandidatesBuffer.push(new Event('icecandidate'));} -break;case'gathering':self._emitBufferedCandidates();if(!end){self.dispatchEvent(event);if(self.onicecandidate!==null){self.onicecandidate(event);}} -if(complete){self.dispatchEvent(new Event('icecandidate'));if(self.onicecandidate!==null){self.onicecandidate(new Event('icecandidate'));} -self.iceGatheringState='complete';self._emitGatheringStateChange();} -break;case'complete':break;default:break;}};return iceGatherer;};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var self=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){self._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){self._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});self._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} -var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} -var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlssttatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} -transceiver.rtpSender.send(params);} -if(recv&&transceiver.rtpReceiver){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} -params.encodings=transceiver.recvEncodingParameters;params.rtcp={cname:transceiver.rtcpParameters.cname,compound:transceiver.rtcpParameters.compound};if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} -transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var self=this;if(!isActionAllowedInSignalingState('setLocalDescription',description.type,this.signalingState)){var e=new Error('Can not set local '+description.type+' in state '+this.signalingState);e.name='InvalidStateError';if(arguments.length>2&&typeof arguments[2]==='function'){window.setTimeout(arguments[2],0,e);} -return Promise.reject(e);} -var sections;var sessionpart;if(description.type==='offer'){if(this._pendingOffer){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);self._pendingOffer[sdpMLineIndex].localCapabilities=caps;});this.transceivers=this._pendingOffer;delete this._pendingOffer;}}else if(description.type==='answer'){sections=SDPUtils.splitSections(self.remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=self.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection);if(!rejected&&!transceiver.isDatachannel){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} -if(!self.usingBundle||sdpMLineIndex===0){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');dtlsTransport.start(remoteDtlsParameters);} -var params=getCommonCapabilities(localCapabilities,remoteCapabilities);self._transceive(transceiver,params.codecs.length>0,false);}});} -this.localDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-local-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} -var hasCallback=arguments.length>1&&typeof arguments[1]==='function';if(hasCallback){var cb=arguments[1];window.setTimeout(function(){cb();if(self.iceGatheringState==='new'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} -self._emitBufferedCandidates();},0);} -var p=Promise.resolve();p.then(function(){if(!hasCallback){if(self.iceGatheringState==='new'){self.iceGatheringState='gathering';self._emitGatheringStateChange();} -window.setTimeout(self._emitBufferedCandidates.bind(self),500);}});return p;};RTCPeerConnection.prototype.setRemoteDescription=function(description){var self=this;if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,this.signalingState)){var e=new Error('Can not set remote '+description.type+' in state '+this.signalingState);e.name='InvalidStateError';if(arguments.length>2&&typeof arguments[2]==='function'){window.setTimeout(arguments[2],0,e);} -return Promise.reject(e);} -var streams={};var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;this.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){this.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{this.canTrickleIceCandidates=false;} -sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection);var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(kind==='application'&&protocol==='DTLS/SCTP'){self.transceivers[sdpMLineIndex]={mid:mid,isDatachannel:true};return;} -var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} -recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component==='1'||cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&self.transceivers[sdpMLineIndex]){self._disposeIceAndDtlsTransports(sdpMLineIndex);self.transceivers[sdpMLineIndex].iceGatherer=self.transceivers[0].iceGatherer;self.transceivers[sdpMLineIndex].iceTransport=self.transceivers[0].iceTransport;self.transceivers[sdpMLineIndex].dtlsTransport=self.transceivers[0].dtlsTransport;if(self.transceivers[sdpMLineIndex].rtpSender){self.transceivers[sdpMLineIndex].rtpSender.setTransport(self.transceivers[0].dtlsTransport);} -if(self.transceivers[sdpMLineIndex].rtpReceiver){self.transceivers[sdpMLineIndex].rtpReceiver.setTransport(self.transceivers[0].dtlsTransport);}} -if(description.type==='offer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex]||self._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=usingBundle&&sdpMLineIndex>0?self.transceivers[0].iceGatherer:self._createIceGatherer(mid,sdpMLineIndex);} -if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);} -localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} -sendEncodingParameters=[{ssrc:(2*sdpMLineIndex+2)*1001}];if(direction==='sendrecv'||direction==='sendonly'){rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} -Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} -streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}} -transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;self._transceive(self.transceivers[sdpMLineIndex],false,direction==='sendrecv'||direction==='sendonly');}else if(description.type==='answer'&&!rejected){transceiver=self.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;self.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;self.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;self.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if((isIceLite||isComplete)&&cands.length){iceTransport.setRemoteCandidates(cands);} -if(!usingBundle||sdpMLineIndex===0){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');dtlsTransport.start(remoteDtlsParameters);} -self._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} -streams[remoteMsid.stream].addTrack(track);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} -streams.default.addTrack(track);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});this.remoteDescription={type:description.type,sdp:description.sdp};switch(description.type){case'offer':this._updateSignalingState('have-remote-offer');break;case'answer':this._updateSignalingState('stable');break;default:throw new TypeError('unsupported type "'+description.type+'"');} -Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){self.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;self.dispatchEvent(event);if(self.onaddstream!==null){window.setTimeout(function(){self.onaddstream(event);},0);} -receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} -var trackEvent=new Event('track');trackEvent.track=track;trackEvent.receiver=receiver;trackEvent.streams=[stream];self.dispatchEvent(trackEvent);if(self.ontrack!==null){window.setTimeout(function(){self.ontrack(trackEvent);},0);}});}});window.setTimeout(function(){if(!(self&&self.transceivers)){return;} -self.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);if(arguments.length>1&&typeof arguments[1]==='function'){window.setTimeout(arguments[1],0);} -return Promise.resolve();};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} -if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} -if(transceiver.rtpSender){transceiver.rtpSender.stop();} -if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this.dispatchEvent(event);if(this.onsignalingstatechange!==null){this.onsignalingstatechange(event);}};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var self=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} -this.needNegotiation=true;window.setTimeout(function(){if(self.needNegotiation===false){return;} -self.needNegotiation=false;var event=new Event('negotiationneeded');self.dispatchEvent(event);if(self.onnegotiationneeded!==null){self.onnegotiationneeded(event);}},0);};RTCPeerConnection.prototype._updateConnectionState=function(){var self=this;var newState;var states={'new':0,closed:0,connecting:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0||states.checking>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0||states.completed>0){newState='connected';} -if(newState!==self.iceConnectionState){self.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this.dispatchEvent(event);if(this.oniceconnectionstatechange!==null){this.oniceconnectionstatechange(event);}}};RTCPeerConnection.prototype.createOffer=function(){var self=this;if(this._pendingOffer){throw new Error('createOffer called while there is a pending offer.');} -var offerOptions;if(arguments.length===1&&typeof arguments[0]!=='function'){offerOptions=arguments[0];}else if(arguments.length===3){offerOptions=arguments[2];} -var numAudioTracks=this.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=this.transceivers.filter(function(t){return t.kind==='video';}).length;if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} -if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} -if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} -this.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){this._createTransceiver('audio');numAudioTracks--;} -if(numVideoTracks>0){this._createTransceiver('video');numVideoTracks--;}} -var transceivers=sortTracks(this.transceivers);var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId);transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=self.usingBundle&&sdpMLineIndex>0?transceivers[0].iceGatherer:self._createIceGatherer(mid,sdpMLineIndex);} -var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} -localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';}});var sendEncodingParameters=[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'){sendEncodingParameters[0].rtx={ssrc:(2*sdpMLineIndex+1)*1001+1};}} -if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} -transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(this._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} -sdp+='a=ice-options:trickle\r\n';transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=SDPUtils.writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream);sdp+='a=rtcp-rsize\r\n';});this._pendingOffer=transceivers;var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});if(arguments.length&&typeof arguments[0]==='function'){window.setTimeout(arguments[0],0,desc);} -return Promise.resolve(desc);};RTCPeerConnection.prototype.createAnswer=function(){var sdp=SDPUtils.writeSessionBoilerplate(this._sdpSessionId);if(this.usingBundle){sdp+='a=group:BUNDLE '+this.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} -this.transceivers.forEach(function(transceiver,sdpMLineIndex){if(transceiver.isDatachannel){sdp+='m=application 0 DTLS/SCTP 5000\r\n'+'c=IN IP4 0.0.0.0\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} -if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} -if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'){transceiver.sendEncodingParameters[0].rtx={ssrc:(2*sdpMLineIndex+2)*1001+1};}}} -var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} -sdp+=SDPUtils.writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});if(arguments.length&&typeof arguments[0]==='function'){window.setTimeout(arguments[0],0,desc);} -return Promise.resolve(desc);};RTCPeerConnection.prototype.addIceCandidate=function(candidate){if(!candidate){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return Promise.resolve();} -if(cand.component&&!(cand.component==='1'||cand.component===1)){return Promise.resolve();} -transceiver.iceTransport.addRemoteCandidate(cand);var sections=SDPUtils.splitSections(this.remoteDescription.sdp);sections[mLineIndex+1]+=(cand.type?candidate.candidate.trim():'a=end-of-candidates')+'\r\n';this.remoteDescription.sdp=sections.join('');}} -if(arguments.length>1&&typeof arguments[1]==='function'){window.setTimeout(arguments[1],0);} -return Promise.resolve();};RTCPeerConnection.prototype.getStats=function(){var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});var cb=arguments.length>1&&typeof arguments[1]==='function'&&arguments[1];var fixStatsType=function(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;};return new Promise(function(resolve){var results=new Map();Promise.all(promises).then(function(res){res.forEach(function(result){Object.keys(result).forEach(function(id){result[id].type=fixStatsType(result[id]);results.set(id,result[id]);});});if(cb){window.setTimeout(cb,0,results);} -resolve(results);});});};return RTCPeerConnection;};},{"sdp":1}],9:[function(require,module,exports){'use strict';var utils=require('../utils');var firefoxShim={shimOnTrack:function(window){if(typeof window==='object'&&window.RTCPeerConnection&&!('ontrack'in +if(window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=new window.RTCDtmfSender(this);}else if(this.track.kind==='video'){this._dtmf=null;}} +return this._dtmf;}});} +window.RTCPeerConnection=shimRTCPeerConnection(window,browserDetails.version);},shimReplaceTrack:function(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}};},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){'use strict';module.exports=function(window){var navigator=window&&window.navigator;var shimError_=function(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};};},{}],10:[function(require,module,exports){'use strict';var utils=require('../utils');var firefoxShim={shimOnTrack:function(window){if(typeof window==='object'&&window.RTCPeerConnection&&!('ontrack'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'ontrack',{get:function(){return this._ontrack;},set:function(f){if(this._ontrack){this.removeEventListener('track',this._ontrack);this.removeEventListener('addstream',this._ontrackpoly);} -this.addEventListener('track',this._ontrack=f);this.addEventListener('addstream',this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event('track');event.track=track;event.receiver={track:track};event.streams=[e.stream];this.dispatchEvent(event);}.bind(this));}.bind(this));}});}},shimSourceObject:function(window){if(typeof window==='object'){if(window.HTMLMediaElement&&!('srcObject'in window.HTMLMediaElement.prototype)){Object.defineProperty(window.HTMLMediaElement.prototype,'srcObject',{get:function(){return this.mozSrcObject;},set:function(stream){this.mozSrcObject=stream;}});}}},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(typeof window!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} +this.addEventListener('track',this._ontrack=f);this.addEventListener('addstream',this._ontrackpoly=function(e){e.stream.getTracks().forEach(function(track){var event=new Event('track');event.track=track;event.receiver={track:track};event.transceiver={receiver:event.receiver};event.streams=[e.stream];this.dispatchEvent(event);}.bind(this));}.bind(this));}});} +if(typeof window==='object'&&window.RTCTrackEvent&&('receiver'in window.RTCTrackEvent.prototype)&&!('transceiver'in window.RTCTrackEvent.prototype)){Object.defineProperty(window.RTCTrackEvent.prototype,'transceiver',{get:function(){return{receiver:this.receiver};}});}},shimSourceObject:function(window){if(typeof window==='object'){if(window.HTMLMediaElement&&!('srcObject'in window.HTMLMediaElement.prototype)){Object.defineProperty(window.HTMLMediaElement.prototype,'srcObject',{get:function(){return this.mozSrcObject;},set:function(stream){this.mozSrcObject=stream;}});}}},shimPeerConnection:function(window){var browserDetails=utils.detectBrowser(window);if(typeof window!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} if(!window.RTCPeerConnection){window.RTCPeerConnection=function(pcConfig,pcConstraints){if(browserDetails.version<38){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i=pos&&parseInt(match[pos],10);},detectBrowser:function(window){var navigator=window&&window.navigator;var result={};result.browser=null;result.version=null;if(typeof window==='undefined'||!window.navigator){result.browser='Not a browser.';return result;} if(navigator.mozGetUserMedia){result.browser='firefox';result.version=this.extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);}else if(navigator.webkitGetUserMedia){if(window.webkitRTCPeerConnection){result.browser='chrome';result.version=this.extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);}else{if(navigator.userAgent.match(/Version\/(\d+).(\d+)/)){result.browser='safari';result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Unsupported webkit-based browser '+'with GUM support but no WebRTC support.';return result;}}}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)){result.browser='edge';result.version=this.extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);}else if(navigator.mediaDevices&&navigator.userAgent.match(/AppleWebKit\/(\d+)\./)){result.browser='safari';result.version=this.extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Not a supported browser.';return result;} -return result;},shimCreateObjectURL:function(window){var URL=window&&window.URL;if(!(typeof window==='object'&&window.HTMLMediaElement&&'srcObject'in window.HTMLMediaElement.prototype)){return undefined;} -var nativeCreateObjectURL=URL.createObjectURL.bind(URL);var nativeRevokeObjectURL=URL.revokeObjectURL.bind(URL);var streams=new Map(),newId=0;URL.createObjectURL=function(stream){if('getTracks'in stream){var url='polyblob:'+(++newId);streams.set(url,stream);utils.deprecated('URL.createObjectURL(stream)','elem.srcObject = stream');return url;} -return nativeCreateObjectURL(stream);};URL.revokeObjectURL=function(url){nativeRevokeObjectURL(url);streams.delete(url);};var dsc=Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype,'src');Object.defineProperty(window.HTMLMediaElement.prototype,'src',{get:function(){return dsc.get.apply(this);},set:function(url){this.srcObject=streams.get(url)||null;return dsc.set.apply(this,[url]);}});var nativeSetAttribute=window.HTMLMediaElement.prototype.setAttribute;window.HTMLMediaElement.prototype.setAttribute=function(){if(arguments.length===2&&(''+arguments[0]).toLowerCase()==='src'){this.srcObject=streams.get(arguments[1])||null;} -return nativeSetAttribute.apply(this,arguments);};}};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)};},{}]},{},[2])(2)}); \ No newline at end of file +return result;},};module.exports={log:utils.log,deprecated:utils.deprecated,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings,extractVersion:utils.extractVersion,shimCreateObjectURL:utils.shimCreateObjectURL,detectBrowser:utils.detectBrowser.bind(utils)};},{}]},{},[3])(3)}); \ No newline at end of file