You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							3514 lines
						
					
					
						
							127 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							3514 lines
						
					
					
						
							127 KiB
						
					
					
				| (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(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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 _adapter_factory = require('./adapter_factory.js'); | |
| 
 | |
| var adapter = (0, _adapter_factory.adapterFactory)({ window: typeof window === 'undefined' ? undefined : window }); | |
| module.exports = adapter; // this is the difference from adapter_core. | |
|  | |
| },{"./adapter_factory.js":2}],2:[function(require,module,exports){ | |
| 'use strict'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| exports.adapterFactory = adapterFactory; | |
| 
 | |
| var _utils = require('./utils'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| var _chrome_shim = require('./chrome/chrome_shim'); | |
| 
 | |
| var chromeShim = _interopRequireWildcard(_chrome_shim); | |
| 
 | |
| var _firefox_shim = require('./firefox/firefox_shim'); | |
| 
 | |
| var firefoxShim = _interopRequireWildcard(_firefox_shim); | |
| 
 | |
| var _safari_shim = require('./safari/safari_shim'); | |
| 
 | |
| var safariShim = _interopRequireWildcard(_safari_shim); | |
| 
 | |
| var _common_shim = require('./common_shim'); | |
| 
 | |
| var commonShim = _interopRequireWildcard(_common_shim); | |
| 
 | |
| var _sdp = require('sdp'); | |
| 
 | |
| var sdp = _interopRequireWildcard(_sdp); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| // Shimming starts here. | |
| /* | |
|  *  Copyright (c) 2016 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. | |
|  */ | |
| function adapterFactory() { | |
|   var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | |
|       window = _ref.window; | |
| 
 | |
|   var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { | |
|     shimChrome: true, | |
|     shimFirefox: true, | |
|     shimSafari: true | |
|   }; | |
| 
 | |
|   // Utils. | |
|   var logging = utils.log; | |
|   var browserDetails = utils.detectBrowser(window); | |
| 
 | |
|   var adapter = { | |
|     browserDetails: browserDetails, | |
|     commonShim: commonShim, | |
|     extractVersion: utils.extractVersion, | |
|     disableLog: utils.disableLog, | |
|     disableWarnings: utils.disableWarnings, | |
|     // Expose sdp as a convenience. For production apps include directly. | |
|     sdp: sdp | |
|   }; | |
| 
 | |
|   // Shim browser if found. | |
|   switch (browserDetails.browser) { | |
|     case 'chrome': | |
|       if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { | |
|         logging('Chrome shim is not included in this adapter release.'); | |
|         return adapter; | |
|       } | |
|       if (browserDetails.version === null) { | |
|         logging('Chrome shim can not determine version, not shimming.'); | |
|         return adapter; | |
|       } | |
|       logging('adapter.js shimming chrome.'); | |
|       // Export to the adapter global object visible in the browser. | |
|       adapter.browserShim = chromeShim; | |
| 
 | |
|       // Must be called before shimPeerConnection. | |
|       commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails); | |
|       commonShim.shimParameterlessSetLocalDescription(window, browserDetails); | |
| 
 | |
|       chromeShim.shimGetUserMedia(window, browserDetails); | |
|       chromeShim.shimMediaStream(window, browserDetails); | |
|       chromeShim.shimPeerConnection(window, browserDetails); | |
|       chromeShim.shimOnTrack(window, browserDetails); | |
|       chromeShim.shimAddTrackRemoveTrack(window, browserDetails); | |
|       chromeShim.shimGetSendersWithDtmf(window, browserDetails); | |
|       chromeShim.shimGetStats(window, browserDetails); | |
|       chromeShim.shimSenderReceiverGetStats(window, browserDetails); | |
|       chromeShim.fixNegotiationNeeded(window, browserDetails); | |
| 
 | |
|       commonShim.shimRTCIceCandidate(window, browserDetails); | |
|       commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails); | |
|       commonShim.shimConnectionState(window, browserDetails); | |
|       commonShim.shimMaxMessageSize(window, browserDetails); | |
|       commonShim.shimSendThrowTypeError(window, browserDetails); | |
|       commonShim.removeExtmapAllowMixed(window, browserDetails); | |
|       break; | |
|     case 'firefox': | |
|       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; | |
| 
 | |
|       // Must be called before shimPeerConnection. | |
|       commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails); | |
|       commonShim.shimParameterlessSetLocalDescription(window, browserDetails); | |
| 
 | |
|       firefoxShim.shimGetUserMedia(window, browserDetails); | |
|       firefoxShim.shimPeerConnection(window, browserDetails); | |
|       firefoxShim.shimOnTrack(window, browserDetails); | |
|       firefoxShim.shimRemoveStream(window, browserDetails); | |
|       firefoxShim.shimSenderGetStats(window, browserDetails); | |
|       firefoxShim.shimReceiverGetStats(window, browserDetails); | |
|       firefoxShim.shimRTCDataChannel(window, browserDetails); | |
|       firefoxShim.shimAddTransceiver(window, browserDetails); | |
|       firefoxShim.shimGetParameters(window, browserDetails); | |
|       firefoxShim.shimCreateOffer(window, browserDetails); | |
|       firefoxShim.shimCreateAnswer(window, browserDetails); | |
| 
 | |
|       commonShim.shimRTCIceCandidate(window, browserDetails); | |
|       commonShim.shimConnectionState(window, browserDetails); | |
|       commonShim.shimMaxMessageSize(window, browserDetails); | |
|       commonShim.shimSendThrowTypeError(window, browserDetails); | |
|       break; | |
|     case 'safari': | |
|       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; | |
| 
 | |
|       // Must be called before shimCallbackAPI. | |
|       commonShim.shimAddIceCandidateNullOrEmpty(window, browserDetails); | |
|       commonShim.shimParameterlessSetLocalDescription(window, browserDetails); | |
| 
 | |
|       safariShim.shimRTCIceServerUrls(window, browserDetails); | |
|       safariShim.shimCreateOfferLegacy(window, browserDetails); | |
|       safariShim.shimCallbacksAPI(window, browserDetails); | |
|       safariShim.shimLocalStreamsAPI(window, browserDetails); | |
|       safariShim.shimRemoteStreamsAPI(window, browserDetails); | |
|       safariShim.shimTrackEventTransceiver(window, browserDetails); | |
|       safariShim.shimGetUserMedia(window, browserDetails); | |
|       safariShim.shimAudioContext(window, browserDetails); | |
| 
 | |
|       commonShim.shimRTCIceCandidate(window, browserDetails); | |
|       commonShim.shimRTCIceCandidateRelayProtocol(window, browserDetails); | |
|       commonShim.shimMaxMessageSize(window, browserDetails); | |
|       commonShim.shimSendThrowTypeError(window, browserDetails); | |
|       commonShim.removeExtmapAllowMixed(window, browserDetails); | |
|       break; | |
|     default: | |
|       logging('Unsupported browser!'); | |
|       break; | |
|   } | |
| 
 | |
|   return adapter; | |
| } | |
| 
 | |
| // Browser shims. | |
|  | |
| },{"./chrome/chrome_shim":3,"./common_shim":6,"./firefox/firefox_shim":7,"./safari/safari_shim":10,"./utils":11,"sdp":12}],3:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| var _getusermedia = require('./getusermedia'); | |
| 
 | |
| Object.defineProperty(exports, 'shimGetUserMedia', { | |
|   enumerable: true, | |
|   get: function get() { | |
|     return _getusermedia.shimGetUserMedia; | |
|   } | |
| }); | |
| 
 | |
| var _getdisplaymedia = require('./getdisplaymedia'); | |
| 
 | |
| Object.defineProperty(exports, 'shimGetDisplayMedia', { | |
|   enumerable: true, | |
|   get: function get() { | |
|     return _getdisplaymedia.shimGetDisplayMedia; | |
|   } | |
| }); | |
| exports.shimMediaStream = shimMediaStream; | |
| exports.shimOnTrack = shimOnTrack; | |
| exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf; | |
| exports.shimGetStats = shimGetStats; | |
| exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats; | |
| exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative; | |
| exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack; | |
| exports.shimPeerConnection = shimPeerConnection; | |
| exports.fixNegotiationNeeded = fixNegotiationNeeded; | |
| 
 | |
| var _utils = require('../utils.js'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | |
| 
 | |
| function shimMediaStream(window) { | |
|   window.MediaStream = window.MediaStream || window.webkitMediaStream; | |
| } | |
| 
 | |
| function shimOnTrack(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { | |
|     Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { | |
|       get: function get() { | |
|         return this._ontrack; | |
|       }, | |
|       set: function set(f) { | |
|         if (this._ontrack) { | |
|           this.removeEventListener('track', this._ontrack); | |
|         } | |
|         this.addEventListener('track', this._ontrack = f); | |
|       }, | |
| 
 | |
|       enumerable: true, | |
|       configurable: true | |
|     }); | |
|     var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; | |
|     window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { | |
|       var _this = this; | |
| 
 | |
|       if (!this._ontrackpoly) { | |
|         this._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 = void 0; | |
|             if (window.RTCPeerConnection.prototype.getReceivers) { | |
|               receiver = _this.getReceivers().find(function (r) { | |
|                 return r.track && r.track.id === te.track.id; | |
|               }); | |
|             } else { | |
|               receiver = { track: te.track }; | |
|             } | |
| 
 | |
|             var event = new Event('track'); | |
|             event.track = te.track; | |
|             event.receiver = receiver; | |
|             event.transceiver = { receiver: receiver }; | |
|             event.streams = [e.stream]; | |
|             _this.dispatchEvent(event); | |
|           }); | |
|           e.stream.getTracks().forEach(function (track) { | |
|             var receiver = void 0; | |
|             if (window.RTCPeerConnection.prototype.getReceivers) { | |
|               receiver = _this.getReceivers().find(function (r) { | |
|                 return r.track && r.track.id === track.id; | |
|               }); | |
|             } else { | |
|               receiver = { track: track }; | |
|             } | |
|             var event = new Event('track'); | |
|             event.track = track; | |
|             event.receiver = receiver; | |
|             event.transceiver = { receiver: receiver }; | |
|             event.streams = [e.stream]; | |
|             _this.dispatchEvent(event); | |
|           }); | |
|         }; | |
|         this.addEventListener('addstream', this._ontrackpoly); | |
|       } | |
|       return origSetRemoteDescription.apply(this, arguments); | |
|     }; | |
|   } else { | |
|     // even if RTCRtpTransceiver is in window, it is only used and | |
|     // emitted in unified-plan. Unfortunately this means we need | |
|     // to unconditionally wrap the event. | |
|     utils.wrapPeerConnectionEvent(window, 'track', function (e) { | |
|       if (!e.transceiver) { | |
|         Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); | |
|       } | |
|       return e; | |
|     }); | |
|   } | |
| } | |
| 
 | |
| function shimGetSendersWithDtmf(window) { | |
|   // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { | |
|     var shimSenderWithDtmf = function shimSenderWithDtmf(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 | |
|       }; | |
|     }; | |
| 
 | |
|     // augment addTrack when getSenders is not available. | |
|     if (!window.RTCPeerConnection.prototype.getSenders) { | |
|       window.RTCPeerConnection.prototype.getSenders = function getSenders() { | |
|         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 addTrack(track, stream) { | |
|         var sender = origAddTrack.apply(this, arguments); | |
|         if (!sender) { | |
|           sender = shimSenderWithDtmf(this, track); | |
|           this._senders.push(sender); | |
|         } | |
|         return sender; | |
|       }; | |
| 
 | |
|       var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; | |
|       window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { | |
|         origRemoveTrack.apply(this, arguments); | |
|         var idx = this._senders.indexOf(sender); | |
|         if (idx !== -1) { | |
|           this._senders.splice(idx, 1); | |
|         } | |
|       }; | |
|     } | |
|     var origAddStream = window.RTCPeerConnection.prototype.addStream; | |
|     window.RTCPeerConnection.prototype.addStream = function addStream(stream) { | |
|       var _this2 = this; | |
| 
 | |
|       this._senders = this._senders || []; | |
|       origAddStream.apply(this, [stream]); | |
|       stream.getTracks().forEach(function (track) { | |
|         _this2._senders.push(shimSenderWithDtmf(_this2, track)); | |
|       }); | |
|     }; | |
| 
 | |
|     var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; | |
|     window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { | |
|       var _this3 = this; | |
| 
 | |
|       this._senders = this._senders || []; | |
|       origRemoveStream.apply(this, [stream]); | |
| 
 | |
|       stream.getTracks().forEach(function (track) { | |
|         var sender = _this3._senders.find(function (s) { | |
|           return s.track === track; | |
|         }); | |
|         if (sender) { | |
|           // remove sender | |
|           _this3._senders.splice(_this3._senders.indexOf(sender), 1); | |
|         } | |
|       }); | |
|     }; | |
|   } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { | |
|     var origGetSenders = window.RTCPeerConnection.prototype.getSenders; | |
|     window.RTCPeerConnection.prototype.getSenders = function getSenders() { | |
|       var _this4 = this; | |
| 
 | |
|       var senders = origGetSenders.apply(this, []); | |
|       senders.forEach(function (sender) { | |
|         return sender._pc = _this4; | |
|       }); | |
|       return senders; | |
|     }; | |
| 
 | |
|     Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { | |
|       get: function get() { | |
|         if (this._dtmf === undefined) { | |
|           if (this.track.kind === 'audio') { | |
|             this._dtmf = this._pc.createDTMFSender(this.track); | |
|           } else { | |
|             this._dtmf = null; | |
|           } | |
|         } | |
|         return this._dtmf; | |
|       } | |
|     }); | |
|   } | |
| } | |
| 
 | |
| function shimGetStats(window) { | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
| 
 | |
|   var origGetStats = window.RTCPeerConnection.prototype.getStats; | |
|   window.RTCPeerConnection.prototype.getStats = function getStats() { | |
|     var _this5 = this; | |
| 
 | |
|     var _arguments = Array.prototype.slice.call(arguments), | |
|         selector = _arguments[0], | |
|         onSucc = _arguments[1], | |
|         onErr = _arguments[2]; | |
| 
 | |
|     // If selector is a function then we are in the old style stats so just | |
|     // pass back the original getStats format to avoid breaking old users. | |
|  | |
| 
 | |
|     if (arguments.length > 0 && typeof selector === 'function') { | |
|       return origGetStats.apply(this, arguments); | |
|     } | |
| 
 | |
|     // When spec-style getStats is supported, return those when called with | |
|     // either no arguments or the selector argument is null. | |
|     if (origGetStats.length === 0 && (arguments.length === 0 || typeof selector !== 'function')) { | |
|       return origGetStats.apply(this, []); | |
|     } | |
| 
 | |
|     var fixChromeStats_ = function fixChromeStats_(response) { | |
|       var standardReport = {}; | |
|       var reports = response.result(); | |
|       reports.forEach(function (report) { | |
|         var standardStats = { | |
|           id: report.id, | |
|           timestamp: report.timestamp, | |
|           type: { | |
|             localcandidate: 'local-candidate', | |
|             remotecandidate: 'remote-candidate' | |
|           }[report.type] || report.type | |
|         }; | |
|         report.names().forEach(function (name) { | |
|           standardStats[name] = report.stat(name); | |
|         }); | |
|         standardReport[standardStats.id] = standardStats; | |
|       }); | |
| 
 | |
|       return standardReport; | |
|     }; | |
| 
 | |
|     // shim getStats with maplike support | |
|     var makeMapStats = function makeMapStats(stats) { | |
|       return new Map(Object.keys(stats).map(function (key) { | |
|         return [key, stats[key]]; | |
|       })); | |
|     }; | |
| 
 | |
|     if (arguments.length >= 2) { | |
|       var successCallbackWrapper_ = function successCallbackWrapper_(response) { | |
|         onSucc(makeMapStats(fixChromeStats_(response))); | |
|       }; | |
| 
 | |
|       return origGetStats.apply(this, [successCallbackWrapper_, selector]); | |
|     } | |
| 
 | |
|     // promise-support | |
|     return new Promise(function (resolve, reject) { | |
|       origGetStats.apply(_this5, [function (response) { | |
|         resolve(makeMapStats(fixChromeStats_(response))); | |
|       }, reject]); | |
|     }).then(onSucc, onErr); | |
|   }; | |
| } | |
| 
 | |
| function shimSenderReceiverGetStats(window) { | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { | |
|     return; | |
|   } | |
| 
 | |
|   // shim sender stats. | |
|   if (!('getStats' in window.RTCRtpSender.prototype)) { | |
|     var origGetSenders = window.RTCPeerConnection.prototype.getSenders; | |
|     if (origGetSenders) { | |
|       window.RTCPeerConnection.prototype.getSenders = function getSenders() { | |
|         var _this6 = this; | |
| 
 | |
|         var senders = origGetSenders.apply(this, []); | |
|         senders.forEach(function (sender) { | |
|           return sender._pc = _this6; | |
|         }); | |
|         return senders; | |
|       }; | |
|     } | |
| 
 | |
|     var origAddTrack = window.RTCPeerConnection.prototype.addTrack; | |
|     if (origAddTrack) { | |
|       window.RTCPeerConnection.prototype.addTrack = function addTrack() { | |
|         var sender = origAddTrack.apply(this, arguments); | |
|         sender._pc = this; | |
|         return sender; | |
|       }; | |
|     } | |
|     window.RTCRtpSender.prototype.getStats = function getStats() { | |
|       var sender = this; | |
|       return this._pc.getStats().then(function (result) { | |
|         return ( | |
|           /* Note: this will include stats of all senders that | |
|            *   send a track with the same id as sender.track as | |
|            *   it is not possible to identify the RTCRtpSender. | |
|            */ | |
|           utils.filterStats(result, sender.track, true) | |
|         ); | |
|       }); | |
|     }; | |
|   } | |
| 
 | |
|   // shim receiver stats. | |
|   if (!('getStats' in window.RTCRtpReceiver.prototype)) { | |
|     var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; | |
|     if (origGetReceivers) { | |
|       window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { | |
|         var _this7 = this; | |
| 
 | |
|         var receivers = origGetReceivers.apply(this, []); | |
|         receivers.forEach(function (receiver) { | |
|           return receiver._pc = _this7; | |
|         }); | |
|         return receivers; | |
|       }; | |
|     } | |
|     utils.wrapPeerConnectionEvent(window, 'track', function (e) { | |
|       e.receiver._pc = e.srcElement; | |
|       return e; | |
|     }); | |
|     window.RTCRtpReceiver.prototype.getStats = function getStats() { | |
|       var receiver = this; | |
|       return this._pc.getStats().then(function (result) { | |
|         return utils.filterStats(result, receiver.track, false); | |
|       }); | |
|     }; | |
|   } | |
| 
 | |
|   if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { | |
|     return; | |
|   } | |
| 
 | |
|   // shim RTCPeerConnection.getStats(track). | |
|   var origGetStats = window.RTCPeerConnection.prototype.getStats; | |
|   window.RTCPeerConnection.prototype.getStats = function getStats() { | |
|     if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { | |
|       var track = arguments[0]; | |
|       var sender = void 0; | |
|       var receiver = void 0; | |
|       var err = void 0; | |
|       this.getSenders().forEach(function (s) { | |
|         if (s.track === track) { | |
|           if (sender) { | |
|             err = true; | |
|           } else { | |
|             sender = s; | |
|           } | |
|         } | |
|       }); | |
|       this.getReceivers().forEach(function (r) { | |
|         if (r.track === track) { | |
|           if (receiver) { | |
|             err = true; | |
|           } else { | |
|             receiver = r; | |
|           } | |
|         } | |
|         return r.track === track; | |
|       }); | |
|       if (err || sender && receiver) { | |
|         return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); | |
|       } else if (sender) { | |
|         return sender.getStats(); | |
|       } else if (receiver) { | |
|         return receiver.getStats(); | |
|       } | |
|       return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); | |
|     } | |
|     return origGetStats.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimAddTrackRemoveTrackWithNative(window) { | |
|   // shim addTrack/removeTrack with native variants in order to make | |
|   // the interactions with legacy getLocalStreams behave as in other browsers. | |
|   // Keeps a mapping stream.id => [stream, rtpsenders...] | |
|   window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { | |
|     var _this8 = this; | |
| 
 | |
|     this._shimmedLocalStreams = this._shimmedLocalStreams || {}; | |
|     return Object.keys(this._shimmedLocalStreams).map(function (streamId) { | |
|       return _this8._shimmedLocalStreams[streamId][0]; | |
|     }); | |
|   }; | |
| 
 | |
|   var origAddTrack = window.RTCPeerConnection.prototype.addTrack; | |
|   window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { | |
|     if (!stream) { | |
|       return origAddTrack.apply(this, arguments); | |
|     } | |
|     this._shimmedLocalStreams = this._shimmedLocalStreams || {}; | |
| 
 | |
|     var sender = origAddTrack.apply(this, arguments); | |
|     if (!this._shimmedLocalStreams[stream.id]) { | |
|       this._shimmedLocalStreams[stream.id] = [stream, sender]; | |
|     } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { | |
|       this._shimmedLocalStreams[stream.id].push(sender); | |
|     } | |
|     return sender; | |
|   }; | |
| 
 | |
|   var origAddStream = window.RTCPeerConnection.prototype.addStream; | |
|   window.RTCPeerConnection.prototype.addStream = function addStream(stream) { | |
|     var _this9 = this; | |
| 
 | |
|     this._shimmedLocalStreams = this._shimmedLocalStreams || {}; | |
| 
 | |
|     stream.getTracks().forEach(function (track) { | |
|       var alreadyExists = _this9.getSenders().find(function (s) { | |
|         return s.track === track; | |
|       }); | |
|       if (alreadyExists) { | |
|         throw new DOMException('Track already exists.', 'InvalidAccessError'); | |
|       } | |
|     }); | |
|     var existingSenders = this.getSenders(); | |
|     origAddStream.apply(this, arguments); | |
|     var newSenders = this.getSenders().filter(function (newSender) { | |
|       return existingSenders.indexOf(newSender) === -1; | |
|     }); | |
|     this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); | |
|   }; | |
| 
 | |
|   var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; | |
|   window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { | |
|     this._shimmedLocalStreams = this._shimmedLocalStreams || {}; | |
|     delete this._shimmedLocalStreams[stream.id]; | |
|     return origRemoveStream.apply(this, arguments); | |
|   }; | |
| 
 | |
|   var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; | |
|   window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { | |
|     var _this10 = this; | |
| 
 | |
|     this._shimmedLocalStreams = this._shimmedLocalStreams || {}; | |
|     if (sender) { | |
|       Object.keys(this._shimmedLocalStreams).forEach(function (streamId) { | |
|         var idx = _this10._shimmedLocalStreams[streamId].indexOf(sender); | |
|         if (idx !== -1) { | |
|           _this10._shimmedLocalStreams[streamId].splice(idx, 1); | |
|         } | |
|         if (_this10._shimmedLocalStreams[streamId].length === 1) { | |
|           delete _this10._shimmedLocalStreams[streamId]; | |
|         } | |
|       }); | |
|     } | |
|     return origRemoveTrack.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimAddTrackRemoveTrack(window, browserDetails) { | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   // shim addTrack and removeTrack. | |
|   if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { | |
|     return shimAddTrackRemoveTrackWithNative(window); | |
|   } | |
| 
 | |
|   // also shim pc.getLocalStreams when addTrack is shimmed | |
|   // to return the original streams. | |
|   var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; | |
|   window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { | |
|     var _this11 = this; | |
| 
 | |
|     var nativeStreams = origGetLocalStreams.apply(this); | |
|     this._reverseStreams = this._reverseStreams || {}; | |
|     return nativeStreams.map(function (stream) { | |
|       return _this11._reverseStreams[stream.id]; | |
|     }); | |
|   }; | |
| 
 | |
|   var origAddStream = window.RTCPeerConnection.prototype.addStream; | |
|   window.RTCPeerConnection.prototype.addStream = function addStream(stream) { | |
|     var _this12 = this; | |
| 
 | |
|     this._streams = this._streams || {}; | |
|     this._reverseStreams = this._reverseStreams || {}; | |
| 
 | |
|     stream.getTracks().forEach(function (track) { | |
|       var alreadyExists = _this12.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 (!this._reverseStreams[stream.id]) { | |
|       var newStream = new window.MediaStream(stream.getTracks()); | |
|       this._streams[stream.id] = newStream; | |
|       this._reverseStreams[newStream.id] = stream; | |
|       stream = newStream; | |
|     } | |
|     origAddStream.apply(this, [stream]); | |
|   }; | |
| 
 | |
|   var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; | |
|   window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { | |
|     this._streams = this._streams || {}; | |
|     this._reverseStreams = this._reverseStreams || {}; | |
| 
 | |
|     origRemoveStream.apply(this, [this._streams[stream.id] || stream]); | |
|     delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; | |
|     delete this._streams[stream.id]; | |
|   }; | |
| 
 | |
|   window.RTCPeerConnection.prototype.addTrack = function addTrack(track, stream) { | |
|     var _this13 = this; | |
| 
 | |
|     if (this.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 = this.getSenders().find(function (s) { | |
|       return s.track === track; | |
|     }); | |
|     if (alreadyExists) { | |
|       throw new DOMException('Track already exists.', 'InvalidAccessError'); | |
|     } | |
| 
 | |
|     this._streams = this._streams || {}; | |
|     this._reverseStreams = this._reverseStreams || {}; | |
|     var oldStream = this._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 () { | |
|         _this13.dispatchEvent(new Event('negotiationneeded')); | |
|       }); | |
|     } else { | |
|       var newStream = new window.MediaStream([track]); | |
|       this._streams[stream.id] = newStream; | |
|       this._reverseStreams[newStream.id] = stream; | |
|       this.addStream(newStream); | |
|     } | |
|     return this.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]; | |
|     var methodObj = _defineProperty({}, method, function () { | |
|       var _this14 = this; | |
| 
 | |
|       var args = arguments; | |
|       var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; | |
|       if (isLegacyCall) { | |
|         return nativeMethod.apply(this, [function (description) { | |
|           var desc = replaceInternalStreamId(_this14, description); | |
|           args[0].apply(null, [desc]); | |
|         }, function (err) { | |
|           if (args[1]) { | |
|             args[1].apply(null, err); | |
|           } | |
|         }, arguments[2]]); | |
|       } | |
|       return nativeMethod.apply(this, arguments).then(function (description) { | |
|         return replaceInternalStreamId(_this14, description); | |
|       }); | |
|     }); | |
|     window.RTCPeerConnection.prototype[method] = methodObj[method]; | |
|   }); | |
| 
 | |
|   var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; | |
|   window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { | |
|     if (!arguments.length || !arguments[0].type) { | |
|       return origSetLocalDescription.apply(this, arguments); | |
|     } | |
|     arguments[0] = replaceExternalStreamId(this, arguments[0]); | |
|     return origSetLocalDescription.apply(this, 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 get() { | |
|       var description = origLocalDescription.get.apply(this); | |
|       if (description.type === '') { | |
|         return description; | |
|       } | |
|       return replaceInternalStreamId(this, description); | |
|     } | |
|   }); | |
| 
 | |
|   window.RTCPeerConnection.prototype.removeTrack = function removeTrack(sender) { | |
|     var _this15 = this; | |
| 
 | |
|     if (this.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 === this; | |
|     if (!isLocal) { | |
|       throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); | |
|     } | |
| 
 | |
|     // Search for the native stream the senders track belongs to. | |
|     this._streams = this._streams || {}; | |
|     var stream = void 0; | |
|     Object.keys(this._streams).forEach(function (streamid) { | |
|       var hasTrack = _this15._streams[streamid].getTracks().find(function (track) { | |
|         return sender.track === track; | |
|       }); | |
|       if (hasTrack) { | |
|         stream = _this15._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. | |
|         this.removeStream(this._reverseStreams[stream.id]); | |
|       } else { | |
|         // relying on the same odd chrome behaviour as above. | |
|         stream.removeTrack(sender.track); | |
|       } | |
|       this.dispatchEvent(new Event('negotiationneeded')); | |
|     } | |
|   }; | |
| } | |
| 
 | |
| function shimPeerConnection(window, browserDetails) { | |
|   if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { | |
|     // very basic support for old versions. | |
|     window.RTCPeerConnection = window.webkitRTCPeerConnection; | |
|   } | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
| 
 | |
|   // shim implicit creation of RTCSessionDescription/RTCIceCandidate | |
|   if (browserDetails.version < 53) { | |
|     ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { | |
|       var nativeMethod = window.RTCPeerConnection.prototype[method]; | |
|       var methodObj = _defineProperty({}, method, function () { | |
|         arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); | |
|         return nativeMethod.apply(this, arguments); | |
|       }); | |
|       window.RTCPeerConnection.prototype[method] = methodObj[method]; | |
|     }); | |
|   } | |
| } | |
| 
 | |
| // Attempt to fix ONN in plan-b mode. | |
| function fixNegotiationNeeded(window, browserDetails) { | |
|   utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) { | |
|     var pc = e.target; | |
|     if (browserDetails.version < 72 || pc.getConfiguration && pc.getConfiguration().sdpSemantics === 'plan-b') { | |
|       if (pc.signalingState !== 'stable') { | |
|         return; | |
|       } | |
|     } | |
|     return e; | |
|   }); | |
| } | |
| 
 | |
| },{"../utils.js":11,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2018 The adapter.js 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| exports.shimGetDisplayMedia = shimGetDisplayMedia; | |
| function shimGetDisplayMedia(window, getSourceId) { | |
|   if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { | |
|     return; | |
|   } | |
|   if (!window.navigator.mediaDevices) { | |
|     return; | |
|   } | |
|   // getSourceId is a function that returns a promise resolving with | |
|   // the sourceId of the screen/window/tab to be shared. | |
|   if (typeof getSourceId !== 'function') { | |
|     console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); | |
|     return; | |
|   } | |
|   window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { | |
|     return getSourceId(constraints).then(function (sourceId) { | |
|       var widthSpecified = constraints.video && constraints.video.width; | |
|       var heightSpecified = constraints.video && constraints.video.height; | |
|       var frameRateSpecified = constraints.video && constraints.video.frameRate; | |
|       constraints.video = { | |
|         mandatory: { | |
|           chromeMediaSource: 'desktop', | |
|           chromeMediaSourceId: sourceId, | |
|           maxFrameRate: frameRateSpecified || 3 | |
|         } | |
|       }; | |
|       if (widthSpecified) { | |
|         constraints.video.mandatory.maxWidth = widthSpecified; | |
|       } | |
|       if (heightSpecified) { | |
|         constraints.video.mandatory.maxHeight = heightSpecified; | |
|       } | |
|       return window.navigator.mediaDevices.getUserMedia(constraints); | |
|     }); | |
|   }; | |
| } | |
| 
 | |
| },{}],5:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| exports.shimGetUserMedia = shimGetUserMedia; | |
| 
 | |
| var _utils = require('../utils.js'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| var logging = utils.log; | |
| 
 | |
| function shimGetUserMedia(window, browserDetails) { | |
|   var navigator = window && window.navigator; | |
| 
 | |
|   if (!navigator.mediaDevices) { | |
|     return; | |
|   } | |
| 
 | |
|   var constraintsToChrome_ = function constraintsToChrome_(c) { | |
|     if ((typeof c === 'undefined' ? 'undefined' : _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 oldname_(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 shimConstraints_(constraints, func) { | |
|     if (browserDetails.version >= 61) { | |
|       return func(constraints); | |
|     } | |
|     constraints = JSON.parse(JSON.stringify(constraints)); | |
|     if (constraints && _typeof(constraints.audio) === 'object') { | |
|       var remap = function remap(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') { | |
|       // Shim facingMode for mobile & surface pro. | |
|       var face = constraints.video.facingMode; | |
|       face = face && ((typeof face === 'undefined' ? 'undefined' : _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 = void 0; | |
|         if (face.exact === 'environment' || face.ideal === 'environment') { | |
|           matches = ['back', 'rear']; | |
|         } else if (face.exact === 'user' || face.ideal === 'user') { | |
|           matches = ['front']; | |
|         } | |
|         if (matches) { | |
|           // Look for matches in label, or use last cam for back (typical). | |
|           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().includes(match); | |
|               }); | |
|             }); | |
|             if (!dev && devices.length && matches.includes('back')) { | |
|               dev = devices[devices.length - 1]; // more likely the back cam | |
|             } | |
|             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 shimError_(e) { | |
|     if (browserDetails.version >= 64) { | |
|       return e; | |
|     } | |
|     return { | |
|       name: { | |
|         PermissionDeniedError: 'NotAllowedError', | |
|         PermissionDismissedError: 'NotAllowedError', | |
|         InvalidStateError: 'NotAllowedError', | |
|         DevicesNotFoundError: 'NotFoundError', | |
|         ConstraintNotSatisfiedError: 'OverconstrainedError', | |
|         TrackStartError: 'NotReadableError', | |
|         MediaDeviceFailedDueToShutdown: 'NotAllowedError', | |
|         MediaDeviceKillSwitchOn: 'NotAllowedError', | |
|         TabCaptureError: 'AbortError', | |
|         ScreenCaptureError: 'AbortError', | |
|         DeviceCaptureError: 'AbortError' | |
|       }[e.name] || e.name, | |
|       message: e.message, | |
|       constraint: e.constraint || e.constraintName, | |
|       toString: function toString() { | |
|         return this.name + (this.message && ': ') + this.message; | |
|       } | |
|     }; | |
|   }; | |
| 
 | |
|   var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) { | |
|     shimConstraints_(constraints, function (c) { | |
|       navigator.webkitGetUserMedia(c, onSuccess, function (e) { | |
|         if (onError) { | |
|           onError(shimError_(e)); | |
|         } | |
|       }); | |
|     }); | |
|   }; | |
|   navigator.getUserMedia = getUserMedia_.bind(navigator); | |
| 
 | |
|   // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia | |
|   // function which returns a Promise, it does not accept spec-style | |
|   // constraints. | |
|   if (navigator.mediaDevices.getUserMedia) { | |
|     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)); | |
|         }); | |
|       }); | |
|     }; | |
|   } | |
| } | |
| 
 | |
| },{"../utils.js":11}],6:[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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| exports.shimRTCIceCandidate = shimRTCIceCandidate; | |
| exports.shimRTCIceCandidateRelayProtocol = shimRTCIceCandidateRelayProtocol; | |
| exports.shimMaxMessageSize = shimMaxMessageSize; | |
| exports.shimSendThrowTypeError = shimSendThrowTypeError; | |
| exports.shimConnectionState = shimConnectionState; | |
| exports.removeExtmapAllowMixed = removeExtmapAllowMixed; | |
| exports.shimAddIceCandidateNullOrEmpty = shimAddIceCandidateNullOrEmpty; | |
| exports.shimParameterlessSetLocalDescription = shimParameterlessSetLocalDescription; | |
| 
 | |
| var _sdp = require('sdp'); | |
| 
 | |
| var _sdp2 = _interopRequireDefault(_sdp); | |
| 
 | |
| var _utils = require('./utils'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | |
| 
 | |
| function shimRTCIceCandidate(window) { | |
|   // foundation is arbitrarily chosen as an indicator for full support for | |
|   // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface | |
|   if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { | |
|     return; | |
|   } | |
| 
 | |
|   var NativeRTCIceCandidate = window.RTCIceCandidate; | |
|   window.RTCIceCandidate = function RTCIceCandidate(args) { | |
|     // Remove the a= which shouldn't be part of the candidate string. | |
|     if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { | |
|       args = JSON.parse(JSON.stringify(args)); | |
|       args.candidate = args.candidate.substr(2); | |
|     } | |
| 
 | |
|     if (args.candidate && args.candidate.length) { | |
|       // Augment the native candidate with the parsed fields. | |
|       var nativeCandidate = new NativeRTCIceCandidate(args); | |
|       var parsedCandidate = _sdp2.default.parseCandidate(args.candidate); | |
|       var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); | |
| 
 | |
|       // Add a serializer that does not serialize the extra attributes. | |
|       augmentedCandidate.toJSON = function toJSON() { | |
|         return { | |
|           candidate: augmentedCandidate.candidate, | |
|           sdpMid: augmentedCandidate.sdpMid, | |
|           sdpMLineIndex: augmentedCandidate.sdpMLineIndex, | |
|           usernameFragment: augmentedCandidate.usernameFragment | |
|         }; | |
|       }; | |
|       return augmentedCandidate; | |
|     } | |
|     return new NativeRTCIceCandidate(args); | |
|   }; | |
|   window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; | |
| 
 | |
|   // Hook up the augmented candidate in onicecandidate and | |
|   // addEventListener('icecandidate', ...) | |
|   utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { | |
|     if (e.candidate) { | |
|       Object.defineProperty(e, 'candidate', { | |
|         value: new window.RTCIceCandidate(e.candidate), | |
|         writable: 'false' | |
|       }); | |
|     } | |
|     return e; | |
|   }); | |
| } | |
| 
 | |
| function shimRTCIceCandidateRelayProtocol(window) { | |
|   if (!window.RTCIceCandidate || window.RTCIceCandidate && 'relayProtocol' in window.RTCIceCandidate.prototype) { | |
|     return; | |
|   } | |
| 
 | |
|   // Hook up the augmented candidate in onicecandidate and | |
|   // addEventListener('icecandidate', ...) | |
|   utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { | |
|     if (e.candidate) { | |
|       var parsedCandidate = _sdp2.default.parseCandidate(e.candidate.candidate); | |
|       if (parsedCandidate.type === 'relay') { | |
|         // This is a libwebrtc-specific mapping of local type preference | |
|         // to relayProtocol. | |
|         e.candidate.relayProtocol = { | |
|           0: 'tls', | |
|           1: 'tcp', | |
|           2: 'udp' | |
|         }[parsedCandidate.priority >> 24]; | |
|       } | |
|     } | |
|     return e; | |
|   }); | |
| } | |
| 
 | |
| function shimMaxMessageSize(window, browserDetails) { | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
| 
 | |
|   if (!('sctp' in window.RTCPeerConnection.prototype)) { | |
|     Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { | |
|       get: function get() { | |
|         return typeof this._sctp === 'undefined' ? null : this._sctp; | |
|       } | |
|     }); | |
|   } | |
| 
 | |
|   var sctpInDescription = function sctpInDescription(description) { | |
|     if (!description || !description.sdp) { | |
|       return false; | |
|     } | |
|     var sections = _sdp2.default.splitSections(description.sdp); | |
|     sections.shift(); | |
|     return sections.some(function (mediaSection) { | |
|       var mLine = _sdp2.default.parseMLine(mediaSection); | |
|       return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; | |
|     }); | |
|   }; | |
| 
 | |
|   var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) { | |
|     // TODO: Is there a better solution for detecting Firefox? | |
|     var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); | |
|     if (match === null || match.length < 2) { | |
|       return -1; | |
|     } | |
|     var version = parseInt(match[1], 10); | |
|     // Test for NaN (yes, this is ugly) | |
|     return version !== version ? -1 : version; | |
|   }; | |
| 
 | |
|   var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) { | |
|     // Every implementation we know can send at least 64 KiB. | |
|     // Note: Although Chrome is technically able to send up to 256 KiB, the | |
|     //       data does not reach the other peer reliably. | |
|     //       See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 | |
|     var canSendMaxMessageSize = 65536; | |
|     if (browserDetails.browser === 'firefox') { | |
|       if (browserDetails.version < 57) { | |
|         if (remoteIsFirefox === -1) { | |
|           // FF < 57 will send in 16 KiB chunks using the deprecated PPID | |
|           // fragmentation. | |
|           canSendMaxMessageSize = 16384; | |
|         } else { | |
|           // However, other FF (and RAWRTC) can reassemble PPID-fragmented | |
|           // messages. Thus, supporting ~2 GiB when sending. | |
|           canSendMaxMessageSize = 2147483637; | |
|         } | |
|       } else if (browserDetails.version < 60) { | |
|         // Currently, all FF >= 57 will reset the remote maximum message size | |
|         // to the default value when a data channel is created at a later | |
|         // stage. :( | |
|         // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 | |
|         canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; | |
|       } else { | |
|         // FF >= 60 supports sending ~2 GiB | |
|         canSendMaxMessageSize = 2147483637; | |
|       } | |
|     } | |
|     return canSendMaxMessageSize; | |
|   }; | |
| 
 | |
|   var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) { | |
|     // Note: 65536 bytes is the default value from the SDP spec. Also, | |
|     //       every implementation we know supports receiving 65536 bytes. | |
|     var maxMessageSize = 65536; | |
| 
 | |
|     // FF 57 has a slightly incorrect default remote max message size, so | |
|     // we need to adjust it here to avoid a failure when sending. | |
|     // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 | |
|     if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { | |
|       maxMessageSize = 65535; | |
|     } | |
| 
 | |
|     var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:'); | |
|     if (match.length > 0) { | |
|       maxMessageSize = parseInt(match[0].substr(19), 10); | |
|     } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { | |
|       // If the maximum message size is not present in the remote SDP and | |
|       // both local and remote are Firefox, the remote peer can receive | |
|       // ~2 GiB. | |
|       maxMessageSize = 2147483637; | |
|     } | |
|     return maxMessageSize; | |
|   }; | |
| 
 | |
|   var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; | |
|   window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { | |
|     this._sctp = null; | |
|     // Chrome decided to not expose .sctp in plan-b mode. | |
|     // As usual, adapter.js has to do an 'ugly worakaround' | |
|     // to cover up the mess. | |
|     if (browserDetails.browser === 'chrome' && browserDetails.version >= 76) { | |
|       var _getConfiguration = this.getConfiguration(), | |
|           sdpSemantics = _getConfiguration.sdpSemantics; | |
| 
 | |
|       if (sdpSemantics === 'plan-b') { | |
|         Object.defineProperty(this, 'sctp', { | |
|           get: function get() { | |
|             return typeof this._sctp === 'undefined' ? null : this._sctp; | |
|           }, | |
| 
 | |
|           enumerable: true, | |
|           configurable: true | |
|         }); | |
|       } | |
|     } | |
| 
 | |
|     if (sctpInDescription(arguments[0])) { | |
|       // Check if the remote is FF. | |
|       var isFirefox = getRemoteFirefoxVersion(arguments[0]); | |
| 
 | |
|       // Get the maximum message size the local peer is capable of sending | |
|       var canSendMMS = getCanSendMaxMessageSize(isFirefox); | |
| 
 | |
|       // Get the maximum message size of the remote peer. | |
|       var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); | |
| 
 | |
|       // Determine final maximum message size | |
|       var maxMessageSize = void 0; | |
|       if (canSendMMS === 0 && remoteMMS === 0) { | |
|         maxMessageSize = Number.POSITIVE_INFINITY; | |
|       } else if (canSendMMS === 0 || remoteMMS === 0) { | |
|         maxMessageSize = Math.max(canSendMMS, remoteMMS); | |
|       } else { | |
|         maxMessageSize = Math.min(canSendMMS, remoteMMS); | |
|       } | |
| 
 | |
|       // Create a dummy RTCSctpTransport object and the 'maxMessageSize' | |
|       // attribute. | |
|       var sctp = {}; | |
|       Object.defineProperty(sctp, 'maxMessageSize', { | |
|         get: function get() { | |
|           return maxMessageSize; | |
|         } | |
|       }); | |
|       this._sctp = sctp; | |
|     } | |
| 
 | |
|     return origSetRemoteDescription.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimSendThrowTypeError(window) { | |
|   if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { | |
|     return; | |
|   } | |
| 
 | |
|   // Note: Although Firefox >= 57 has a native implementation, the maximum | |
|   //       message size can be reset for all data channels at a later stage. | |
|   //       See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 | |
|  | |
|   function wrapDcSend(dc, pc) { | |
|     var origDataChannelSend = dc.send; | |
|     dc.send = function send() { | |
|       var data = arguments[0]; | |
|       var length = data.length || data.size || data.byteLength; | |
|       if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { | |
|         throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); | |
|       } | |
|       return origDataChannelSend.apply(dc, arguments); | |
|     }; | |
|   } | |
|   var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; | |
|   window.RTCPeerConnection.prototype.createDataChannel = function createDataChannel() { | |
|     var dataChannel = origCreateDataChannel.apply(this, arguments); | |
|     wrapDcSend(dataChannel, this); | |
|     return dataChannel; | |
|   }; | |
|   utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) { | |
|     wrapDcSend(e.channel, e.target); | |
|     return e; | |
|   }); | |
| } | |
| 
 | |
| /* shims RTCConnectionState by pretending it is the same as iceConnectionState. | |
|  * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 | |
|  * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect | |
|  * since DTLS failures would be hidden. See | |
|  * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 | |
|  * for the Firefox tracking bug. | |
|  */ | |
| function shimConnectionState(window) { | |
|   if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { | |
|     return; | |
|   } | |
|   var proto = window.RTCPeerConnection.prototype; | |
|   Object.defineProperty(proto, 'connectionState', { | |
|     get: function get() { | |
|       return { | |
|         completed: 'connected', | |
|         checking: 'connecting' | |
|       }[this.iceConnectionState] || this.iceConnectionState; | |
|     }, | |
| 
 | |
|     enumerable: true, | |
|     configurable: true | |
|   }); | |
|   Object.defineProperty(proto, 'onconnectionstatechange', { | |
|     get: function get() { | |
|       return this._onconnectionstatechange || null; | |
|     }, | |
|     set: function set(cb) { | |
|       if (this._onconnectionstatechange) { | |
|         this.removeEventListener('connectionstatechange', this._onconnectionstatechange); | |
|         delete this._onconnectionstatechange; | |
|       } | |
|       if (cb) { | |
|         this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); | |
|       } | |
|     }, | |
| 
 | |
|     enumerable: true, | |
|     configurable: true | |
|   }); | |
| 
 | |
|   ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) { | |
|     var origMethod = proto[method]; | |
|     proto[method] = function () { | |
|       if (!this._connectionstatechangepoly) { | |
|         this._connectionstatechangepoly = function (e) { | |
|           var pc = e.target; | |
|           if (pc._lastConnectionState !== pc.connectionState) { | |
|             pc._lastConnectionState = pc.connectionState; | |
|             var newEvent = new Event('connectionstatechange', e); | |
|             pc.dispatchEvent(newEvent); | |
|           } | |
|           return e; | |
|         }; | |
|         this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); | |
|       } | |
|       return origMethod.apply(this, arguments); | |
|     }; | |
|   }); | |
| } | |
| 
 | |
| function removeExtmapAllowMixed(window, browserDetails) { | |
|   /* remove a=extmap-allow-mixed for webrtc.org < M71 */ | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { | |
|     return; | |
|   } | |
|   if (browserDetails.browser === 'safari' && browserDetails.version >= 605) { | |
|     return; | |
|   } | |
|   var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; | |
|   window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription(desc) { | |
|     if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { | |
|       var sdp = desc.sdp.split('\n').filter(function (line) { | |
|         return line.trim() !== 'a=extmap-allow-mixed'; | |
|       }).join('\n'); | |
|       // Safari enforces read-only-ness of RTCSessionDescription fields. | |
|       if (window.RTCSessionDescription && desc instanceof window.RTCSessionDescription) { | |
|         arguments[0] = new window.RTCSessionDescription({ | |
|           type: desc.type, | |
|           sdp: sdp | |
|         }); | |
|       } else { | |
|         desc.sdp = sdp; | |
|       } | |
|     } | |
|     return nativeSRD.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimAddIceCandidateNullOrEmpty(window, browserDetails) { | |
|   // Support for addIceCandidate(null or undefined) | |
|   // as well as addIceCandidate({candidate: "", ...}) | |
|   // https://bugs.chromium.org/p/chromium/issues/detail?id=978582 | |
|   // Note: must be called before other polyfills which change the signature. | |
|   if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { | |
|     return; | |
|   } | |
|   var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; | |
|   if (!nativeAddIceCandidate || nativeAddIceCandidate.length === 0) { | |
|     return; | |
|   } | |
|   window.RTCPeerConnection.prototype.addIceCandidate = function addIceCandidate() { | |
|     if (!arguments[0]) { | |
|       if (arguments[1]) { | |
|         arguments[1].apply(null); | |
|       } | |
|       return Promise.resolve(); | |
|     } | |
|     // Firefox 68+ emits and processes {candidate: "", ...}, ignore | |
|     // in older versions. | |
|     // Native support for ignoring exists for Chrome M77+. | |
|     // Safari ignores as well, exact version unknown but works in the same | |
|     // version that also ignores addIceCandidate(null). | |
|     if ((browserDetails.browser === 'chrome' && browserDetails.version < 78 || browserDetails.browser === 'firefox' && browserDetails.version < 68 || browserDetails.browser === 'safari') && arguments[0] && arguments[0].candidate === '') { | |
|       return Promise.resolve(); | |
|     } | |
|     return nativeAddIceCandidate.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| // Note: Make sure to call this ahead of APIs that modify | |
| // setLocalDescription.length | |
| function shimParameterlessSetLocalDescription(window, browserDetails) { | |
|   if (!(window.RTCPeerConnection && window.RTCPeerConnection.prototype)) { | |
|     return; | |
|   } | |
|   var nativeSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; | |
|   if (!nativeSetLocalDescription || nativeSetLocalDescription.length === 0) { | |
|     return; | |
|   } | |
|   window.RTCPeerConnection.prototype.setLocalDescription = function setLocalDescription() { | |
|     var _this = this; | |
| 
 | |
|     var desc = arguments[0] || {}; | |
|     if ((typeof desc === 'undefined' ? 'undefined' : _typeof(desc)) !== 'object' || desc.type && desc.sdp) { | |
|       return nativeSetLocalDescription.apply(this, arguments); | |
|     } | |
|     // The remaining steps should technically happen when SLD comes off the | |
|     // RTCPeerConnection's operations chain (not ahead of going on it), but | |
|     // this is too difficult to shim. Instead, this shim only covers the | |
|     // common case where the operations chain is empty. This is imperfect, but | |
|     // should cover many cases. Rationale: Even if we can't reduce the glare | |
|     // window to zero on imperfect implementations, there's value in tapping | |
|     // into the perfect negotiation pattern that several browsers support. | |
|     desc = { type: desc.type, sdp: desc.sdp }; | |
|     if (!desc.type) { | |
|       switch (this.signalingState) { | |
|         case 'stable': | |
|         case 'have-local-offer': | |
|         case 'have-remote-pranswer': | |
|           desc.type = 'offer'; | |
|           break; | |
|         default: | |
|           desc.type = 'answer'; | |
|           break; | |
|       } | |
|     } | |
|     if (desc.sdp || desc.type !== 'offer' && desc.type !== 'answer') { | |
|       return nativeSetLocalDescription.apply(this, [desc]); | |
|     } | |
|     var func = desc.type === 'offer' ? this.createOffer : this.createAnswer; | |
|     return func.apply(this).then(function (d) { | |
|       return nativeSetLocalDescription.apply(_this, [d]); | |
|     }); | |
|   }; | |
| } | |
| 
 | |
| },{"./utils":11,"sdp":12}],7:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| var _getusermedia = require('./getusermedia'); | |
| 
 | |
| Object.defineProperty(exports, 'shimGetUserMedia', { | |
|   enumerable: true, | |
|   get: function get() { | |
|     return _getusermedia.shimGetUserMedia; | |
|   } | |
| }); | |
| 
 | |
| var _getdisplaymedia = require('./getdisplaymedia'); | |
| 
 | |
| Object.defineProperty(exports, 'shimGetDisplayMedia', { | |
|   enumerable: true, | |
|   get: function get() { | |
|     return _getdisplaymedia.shimGetDisplayMedia; | |
|   } | |
| }); | |
| exports.shimOnTrack = shimOnTrack; | |
| exports.shimPeerConnection = shimPeerConnection; | |
| exports.shimSenderGetStats = shimSenderGetStats; | |
| exports.shimReceiverGetStats = shimReceiverGetStats; | |
| exports.shimRemoveStream = shimRemoveStream; | |
| exports.shimRTCDataChannel = shimRTCDataChannel; | |
| exports.shimAddTransceiver = shimAddTransceiver; | |
| exports.shimGetParameters = shimGetParameters; | |
| exports.shimCreateOffer = shimCreateOffer; | |
| exports.shimCreateAnswer = shimCreateAnswer; | |
| 
 | |
| var _utils = require('../utils'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | |
| 
 | |
| function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | |
| 
 | |
| function shimOnTrack(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { | |
|     Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { | |
|       get: function get() { | |
|         return { receiver: this.receiver }; | |
|       } | |
|     }); | |
|   } | |
| } | |
| 
 | |
| function shimPeerConnection(window, browserDetails) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { | |
|     return; // probably media.peerconnection.enabled=false in about:config | |
|   } | |
|   if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { | |
|     // very basic support for old versions. | |
|     window.RTCPeerConnection = window.mozRTCPeerConnection; | |
|   } | |
| 
 | |
|   if (browserDetails.version < 53) { | |
|     // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. | |
|     ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { | |
|       var nativeMethod = window.RTCPeerConnection.prototype[method]; | |
|       var methodObj = _defineProperty({}, method, function () { | |
|         arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); | |
|         return nativeMethod.apply(this, arguments); | |
|       }); | |
|       window.RTCPeerConnection.prototype[method] = methodObj[method]; | |
|     }); | |
|   } | |
| 
 | |
|   var modernStatsTypes = { | |
|     inboundrtp: 'inbound-rtp', | |
|     outboundrtp: 'outbound-rtp', | |
|     candidatepair: 'candidate-pair', | |
|     localcandidate: 'local-candidate', | |
|     remotecandidate: 'remote-candidate' | |
|   }; | |
| 
 | |
|   var nativeGetStats = window.RTCPeerConnection.prototype.getStats; | |
|   window.RTCPeerConnection.prototype.getStats = function getStats() { | |
|     var _arguments = Array.prototype.slice.call(arguments), | |
|         selector = _arguments[0], | |
|         onSucc = _arguments[1], | |
|         onErr = _arguments[2]; | |
| 
 | |
|     return nativeGetStats.apply(this, [selector || null]).then(function (stats) { | |
|       if (browserDetails.version < 53 && !onSucc) { | |
|         // Shim only promise getStats with spec-hyphens in type names | |
|         // Leave callback version alone; misc old uses of forEach before Map | |
|         try { | |
|           stats.forEach(function (stat) { | |
|             stat.type = modernStatsTypes[stat.type] || stat.type; | |
|           }); | |
|         } catch (e) { | |
|           if (e.name !== 'TypeError') { | |
|             throw e; | |
|           } | |
|           // Avoid TypeError: "type" is read-only, in old versions. 34-43ish | |
|           stats.forEach(function (stat, i) { | |
|             stats.set(i, Object.assign({}, stat, { | |
|               type: modernStatsTypes[stat.type] || stat.type | |
|             })); | |
|           }); | |
|         } | |
|       } | |
|       return stats; | |
|     }).then(onSucc, onErr); | |
|   }; | |
| } | |
| 
 | |
| function shimSenderGetStats(window) { | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { | |
|     return; | |
|   } | |
|   if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { | |
|     return; | |
|   } | |
|   var origGetSenders = window.RTCPeerConnection.prototype.getSenders; | |
|   if (origGetSenders) { | |
|     window.RTCPeerConnection.prototype.getSenders = function getSenders() { | |
|       var _this = this; | |
| 
 | |
|       var senders = origGetSenders.apply(this, []); | |
|       senders.forEach(function (sender) { | |
|         return sender._pc = _this; | |
|       }); | |
|       return senders; | |
|     }; | |
|   } | |
| 
 | |
|   var origAddTrack = window.RTCPeerConnection.prototype.addTrack; | |
|   if (origAddTrack) { | |
|     window.RTCPeerConnection.prototype.addTrack = function addTrack() { | |
|       var sender = origAddTrack.apply(this, arguments); | |
|       sender._pc = this; | |
|       return sender; | |
|     }; | |
|   } | |
|   window.RTCRtpSender.prototype.getStats = function getStats() { | |
|     return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); | |
|   }; | |
| } | |
| 
 | |
| function shimReceiverGetStats(window) { | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { | |
|     return; | |
|   } | |
|   if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { | |
|     return; | |
|   } | |
|   var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; | |
|   if (origGetReceivers) { | |
|     window.RTCPeerConnection.prototype.getReceivers = function getReceivers() { | |
|       var _this2 = this; | |
| 
 | |
|       var receivers = origGetReceivers.apply(this, []); | |
|       receivers.forEach(function (receiver) { | |
|         return receiver._pc = _this2; | |
|       }); | |
|       return receivers; | |
|     }; | |
|   } | |
|   utils.wrapPeerConnectionEvent(window, 'track', function (e) { | |
|     e.receiver._pc = e.srcElement; | |
|     return e; | |
|   }); | |
|   window.RTCRtpReceiver.prototype.getStats = function getStats() { | |
|     return this._pc.getStats(this.track); | |
|   }; | |
| } | |
| 
 | |
| function shimRemoveStream(window) { | |
|   if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { | |
|     return; | |
|   } | |
|   window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { | |
|     var _this3 = this; | |
| 
 | |
|     utils.deprecated('removeStream', 'removeTrack'); | |
|     this.getSenders().forEach(function (sender) { | |
|       if (sender.track && stream.getTracks().includes(sender.track)) { | |
|         _this3.removeTrack(sender); | |
|       } | |
|     }); | |
|   }; | |
| } | |
| 
 | |
| function shimRTCDataChannel(window) { | |
|   // rename DataChannel to RTCDataChannel (native fix in FF60): | |
|   // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 | |
|   if (window.DataChannel && !window.RTCDataChannel) { | |
|     window.RTCDataChannel = window.DataChannel; | |
|   } | |
| } | |
| 
 | |
| function shimAddTransceiver(window) { | |
|   // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 | |
|   // Firefox ignores the init sendEncodings options passed to addTransceiver | |
|   // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { | |
|     return; | |
|   } | |
|   var origAddTransceiver = window.RTCPeerConnection.prototype.addTransceiver; | |
|   if (origAddTransceiver) { | |
|     window.RTCPeerConnection.prototype.addTransceiver = function addTransceiver() { | |
|       this.setParametersPromises = []; | |
|       // WebIDL input coercion and validation | |
|       var sendEncodings = arguments[1] && arguments[1].sendEncodings; | |
|       if (sendEncodings === undefined) { | |
|         sendEncodings = []; | |
|       } | |
|       sendEncodings = [].concat(_toConsumableArray(sendEncodings)); | |
|       var shouldPerformCheck = sendEncodings.length > 0; | |
|       if (shouldPerformCheck) { | |
|         // If sendEncodings params are provided, validate grammar | |
|         sendEncodings.forEach(function (encodingParam) { | |
|           if ('rid' in encodingParam) { | |
|             var ridRegex = /^[a-z0-9]{0,16}$/i; | |
|             if (!ridRegex.test(encodingParam.rid)) { | |
|               throw new TypeError('Invalid RID value provided.'); | |
|             } | |
|           } | |
|           if ('scaleResolutionDownBy' in encodingParam) { | |
|             if (!(parseFloat(encodingParam.scaleResolutionDownBy) >= 1.0)) { | |
|               throw new RangeError('scale_resolution_down_by must be >= 1.0'); | |
|             } | |
|           } | |
|           if ('maxFramerate' in encodingParam) { | |
|             if (!(parseFloat(encodingParam.maxFramerate) >= 0)) { | |
|               throw new RangeError('max_framerate must be >= 0.0'); | |
|             } | |
|           } | |
|         }); | |
|       } | |
|       var transceiver = origAddTransceiver.apply(this, arguments); | |
|       if (shouldPerformCheck) { | |
|         // Check if the init options were applied. If not we do this in an | |
|         // asynchronous way and save the promise reference in a global object. | |
|         // This is an ugly hack, but at the same time is way more robust than | |
|         // checking the sender parameters before and after the createOffer | |
|         // Also note that after the createoffer we are not 100% sure that | |
|         // the params were asynchronously applied so we might miss the | |
|         // opportunity to recreate offer. | |
|         var sender = transceiver.sender; | |
| 
 | |
|         var params = sender.getParameters(); | |
|         if (!('encodings' in params) || | |
|         // Avoid being fooled by patched getParameters() below. | |
|         params.encodings.length === 1 && Object.keys(params.encodings[0]).length === 0) { | |
|           params.encodings = sendEncodings; | |
|           sender.sendEncodings = sendEncodings; | |
|           this.setParametersPromises.push(sender.setParameters(params).then(function () { | |
|             delete sender.sendEncodings; | |
|           }).catch(function () { | |
|             delete sender.sendEncodings; | |
|           })); | |
|         } | |
|       } | |
|       return transceiver; | |
|     }; | |
|   } | |
| } | |
| 
 | |
| function shimGetParameters(window) { | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCRtpSender)) { | |
|     return; | |
|   } | |
|   var origGetParameters = window.RTCRtpSender.prototype.getParameters; | |
|   if (origGetParameters) { | |
|     window.RTCRtpSender.prototype.getParameters = function getParameters() { | |
|       var params = origGetParameters.apply(this, arguments); | |
|       if (!('encodings' in params)) { | |
|         params.encodings = [].concat(this.sendEncodings || [{}]); | |
|       } | |
|       return params; | |
|     }; | |
|   } | |
| } | |
| 
 | |
| function shimCreateOffer(window) { | |
|   // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 | |
|   // Firefox ignores the init sendEncodings options passed to addTransceiver | |
|   // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { | |
|     return; | |
|   } | |
|   var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; | |
|   window.RTCPeerConnection.prototype.createOffer = function createOffer() { | |
|     var _this4 = this, | |
|         _arguments2 = arguments; | |
| 
 | |
|     if (this.setParametersPromises && this.setParametersPromises.length) { | |
|       return Promise.all(this.setParametersPromises).then(function () { | |
|         return origCreateOffer.apply(_this4, _arguments2); | |
|       }).finally(function () { | |
|         _this4.setParametersPromises = []; | |
|       }); | |
|     } | |
|     return origCreateOffer.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimCreateAnswer(window) { | |
|   // https://github.com/webrtcHacks/adapter/issues/998#issuecomment-516921647 | |
|   // Firefox ignores the init sendEncodings options passed to addTransceiver | |
|   // https://bugzilla.mozilla.org/show_bug.cgi?id=1396918 | |
|   if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection)) { | |
|     return; | |
|   } | |
|   var origCreateAnswer = window.RTCPeerConnection.prototype.createAnswer; | |
|   window.RTCPeerConnection.prototype.createAnswer = function createAnswer() { | |
|     var _this5 = this, | |
|         _arguments3 = arguments; | |
| 
 | |
|     if (this.setParametersPromises && this.setParametersPromises.length) { | |
|       return Promise.all(this.setParametersPromises).then(function () { | |
|         return origCreateAnswer.apply(_this5, _arguments3); | |
|       }).finally(function () { | |
|         _this5.setParametersPromises = []; | |
|       }); | |
|     } | |
|     return origCreateAnswer.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| },{"../utils":11,"./getdisplaymedia":8,"./getusermedia":9}],8:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2018 The adapter.js 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| exports.shimGetDisplayMedia = shimGetDisplayMedia; | |
| function shimGetDisplayMedia(window, preferredMediaSource) { | |
|   if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { | |
|     return; | |
|   } | |
|   if (!window.navigator.mediaDevices) { | |
|     return; | |
|   } | |
|   window.navigator.mediaDevices.getDisplayMedia = function getDisplayMedia(constraints) { | |
|     if (!(constraints && constraints.video)) { | |
|       var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); | |
|       err.name = 'NotFoundError'; | |
|       // from https://heycam.github.io/webidl/#idl-DOMException-error-names | |
|       err.code = 8; | |
|       return Promise.reject(err); | |
|     } | |
|     if (constraints.video === true) { | |
|       constraints.video = { mediaSource: preferredMediaSource }; | |
|     } else { | |
|       constraints.video.mediaSource = preferredMediaSource; | |
|     } | |
|     return window.navigator.mediaDevices.getUserMedia(constraints); | |
|   }; | |
| } | |
| 
 | |
| },{}],9:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| exports.shimGetUserMedia = shimGetUserMedia; | |
| 
 | |
| var _utils = require('../utils'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| function shimGetUserMedia(window, browserDetails) { | |
|   var navigator = window && window.navigator; | |
|   var MediaStreamTrack = window && window.MediaStreamTrack; | |
| 
 | |
|   navigator.getUserMedia = function (constraints, onSuccess, onError) { | |
|     // Replace Firefox 44+'s deprecation warning with unprefixed version. | |
|     utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); | |
|     navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); | |
|   }; | |
| 
 | |
|   if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { | |
|     var remap = function remap(obj, a, b) { | |
|       if (a in obj && !(b in obj)) { | |
|         obj[b] = obj[a]; | |
|         delete obj[a]; | |
|       } | |
|     }; | |
| 
 | |
|     var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); | |
|     navigator.mediaDevices.getUserMedia = function (c) { | |
|       if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') { | |
|         c = JSON.parse(JSON.stringify(c)); | |
|         remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); | |
|         remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); | |
|       } | |
|       return nativeGetUserMedia(c); | |
|     }; | |
| 
 | |
|     if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { | |
|       var nativeGetSettings = MediaStreamTrack.prototype.getSettings; | |
|       MediaStreamTrack.prototype.getSettings = function () { | |
|         var obj = nativeGetSettings.apply(this, arguments); | |
|         remap(obj, 'mozAutoGainControl', 'autoGainControl'); | |
|         remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); | |
|         return obj; | |
|       }; | |
|     } | |
| 
 | |
|     if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { | |
|       var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; | |
|       MediaStreamTrack.prototype.applyConstraints = function (c) { | |
|         if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') { | |
|           c = JSON.parse(JSON.stringify(c)); | |
|           remap(c, 'autoGainControl', 'mozAutoGainControl'); | |
|           remap(c, 'noiseSuppression', 'mozNoiseSuppression'); | |
|         } | |
|         return nativeApplyConstraints.apply(this, [c]); | |
|       }; | |
|     } | |
|   } | |
| } | |
| 
 | |
| },{"../utils":11}],10:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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. | |
|  */ | |
| 'use strict'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| exports.shimLocalStreamsAPI = shimLocalStreamsAPI; | |
| exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI; | |
| exports.shimCallbacksAPI = shimCallbacksAPI; | |
| exports.shimGetUserMedia = shimGetUserMedia; | |
| exports.shimConstraints = shimConstraints; | |
| exports.shimRTCIceServerUrls = shimRTCIceServerUrls; | |
| exports.shimTrackEventTransceiver = shimTrackEventTransceiver; | |
| exports.shimCreateOfferLegacy = shimCreateOfferLegacy; | |
| exports.shimAudioContext = shimAudioContext; | |
| 
 | |
| var _utils = require('../utils'); | |
| 
 | |
| var utils = _interopRequireWildcard(_utils); | |
| 
 | |
| function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | |
| 
 | |
| function shimLocalStreamsAPI(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { | |
|     window.RTCPeerConnection.prototype.getLocalStreams = function getLocalStreams() { | |
|       if (!this._localStreams) { | |
|         this._localStreams = []; | |
|       } | |
|       return this._localStreams; | |
|     }; | |
|   } | |
|   if (!('addStream' in window.RTCPeerConnection.prototype)) { | |
|     var _addTrack = window.RTCPeerConnection.prototype.addTrack; | |
|     window.RTCPeerConnection.prototype.addStream = function addStream(stream) { | |
|       var _this = this; | |
| 
 | |
|       if (!this._localStreams) { | |
|         this._localStreams = []; | |
|       } | |
|       if (!this._localStreams.includes(stream)) { | |
|         this._localStreams.push(stream); | |
|       } | |
|       // Try to emulate Chrome's behaviour of adding in audio-video order. | |
|       // Safari orders by track id. | |
|       stream.getAudioTracks().forEach(function (track) { | |
|         return _addTrack.call(_this, track, stream); | |
|       }); | |
|       stream.getVideoTracks().forEach(function (track) { | |
|         return _addTrack.call(_this, track, stream); | |
|       }); | |
|     }; | |
| 
 | |
|     window.RTCPeerConnection.prototype.addTrack = function addTrack(track) { | |
|       var _this2 = this; | |
| 
 | |
|       for (var _len = arguments.length, streams = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { | |
|         streams[_key - 1] = arguments[_key]; | |
|       } | |
| 
 | |
|       if (streams) { | |
|         streams.forEach(function (stream) { | |
|           if (!_this2._localStreams) { | |
|             _this2._localStreams = [stream]; | |
|           } else if (!_this2._localStreams.includes(stream)) { | |
|             _this2._localStreams.push(stream); | |
|           } | |
|         }); | |
|       } | |
|       return _addTrack.apply(this, arguments); | |
|     }; | |
|   } | |
|   if (!('removeStream' in window.RTCPeerConnection.prototype)) { | |
|     window.RTCPeerConnection.prototype.removeStream = function removeStream(stream) { | |
|       var _this3 = this; | |
| 
 | |
|       if (!this._localStreams) { | |
|         this._localStreams = []; | |
|       } | |
|       var index = this._localStreams.indexOf(stream); | |
|       if (index === -1) { | |
|         return; | |
|       } | |
|       this._localStreams.splice(index, 1); | |
|       var tracks = stream.getTracks(); | |
|       this.getSenders().forEach(function (sender) { | |
|         if (tracks.includes(sender.track)) { | |
|           _this3.removeTrack(sender); | |
|         } | |
|       }); | |
|     }; | |
|   } | |
| } | |
| 
 | |
| function shimRemoteStreamsAPI(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { | |
|     window.RTCPeerConnection.prototype.getRemoteStreams = function getRemoteStreams() { | |
|       return this._remoteStreams ? this._remoteStreams : []; | |
|     }; | |
|   } | |
|   if (!('onaddstream' in window.RTCPeerConnection.prototype)) { | |
|     Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { | |
|       get: function get() { | |
|         return this._onaddstream; | |
|       }, | |
|       set: function set(f) { | |
|         var _this4 = this; | |
| 
 | |
|         if (this._onaddstream) { | |
|           this.removeEventListener('addstream', this._onaddstream); | |
|           this.removeEventListener('track', this._onaddstreampoly); | |
|         } | |
|         this.addEventListener('addstream', this._onaddstream = f); | |
|         this.addEventListener('track', this._onaddstreampoly = function (e) { | |
|           e.streams.forEach(function (stream) { | |
|             if (!_this4._remoteStreams) { | |
|               _this4._remoteStreams = []; | |
|             } | |
|             if (_this4._remoteStreams.includes(stream)) { | |
|               return; | |
|             } | |
|             _this4._remoteStreams.push(stream); | |
|             var event = new Event('addstream'); | |
|             event.stream = stream; | |
|             _this4.dispatchEvent(event); | |
|           }); | |
|         }); | |
|       } | |
|     }); | |
|     var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; | |
|     window.RTCPeerConnection.prototype.setRemoteDescription = function setRemoteDescription() { | |
|       var pc = this; | |
|       if (!this._onaddstreampoly) { | |
|         this.addEventListener('track', this._onaddstreampoly = function (e) { | |
|           e.streams.forEach(function (stream) { | |
|             if (!pc._remoteStreams) { | |
|               pc._remoteStreams = []; | |
|             } | |
|             if (pc._remoteStreams.indexOf(stream) >= 0) { | |
|               return; | |
|             } | |
|             pc._remoteStreams.push(stream); | |
|             var event = new Event('addstream'); | |
|             event.stream = stream; | |
|             pc.dispatchEvent(event); | |
|           }); | |
|         }); | |
|       } | |
|       return origSetRemoteDescription.apply(pc, arguments); | |
|     }; | |
|   } | |
| } | |
| 
 | |
| function shimCallbacksAPI(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   var prototype = window.RTCPeerConnection.prototype; | |
|   var origCreateOffer = prototype.createOffer; | |
|   var origCreateAnswer = prototype.createAnswer; | |
|   var setLocalDescription = prototype.setLocalDescription; | |
|   var setRemoteDescription = prototype.setRemoteDescription; | |
|   var addIceCandidate = prototype.addIceCandidate; | |
| 
 | |
|   prototype.createOffer = function createOffer(successCallback, failureCallback) { | |
|     var options = arguments.length >= 2 ? arguments[2] : arguments[0]; | |
|     var promise = origCreateOffer.apply(this, [options]); | |
|     if (!failureCallback) { | |
|       return promise; | |
|     } | |
|     promise.then(successCallback, failureCallback); | |
|     return Promise.resolve(); | |
|   }; | |
| 
 | |
|   prototype.createAnswer = function createAnswer(successCallback, failureCallback) { | |
|     var options = arguments.length >= 2 ? arguments[2] : arguments[0]; | |
|     var promise = origCreateAnswer.apply(this, [options]); | |
|     if (!failureCallback) { | |
|       return promise; | |
|     } | |
|     promise.then(successCallback, failureCallback); | |
|     return Promise.resolve(); | |
|   }; | |
| 
 | |
|   var withCallback = function withCallback(description, successCallback, failureCallback) { | |
|     var promise = setLocalDescription.apply(this, [description]); | |
|     if (!failureCallback) { | |
|       return promise; | |
|     } | |
|     promise.then(successCallback, failureCallback); | |
|     return Promise.resolve(); | |
|   }; | |
|   prototype.setLocalDescription = withCallback; | |
| 
 | |
|   withCallback = function withCallback(description, successCallback, failureCallback) { | |
|     var promise = setRemoteDescription.apply(this, [description]); | |
|     if (!failureCallback) { | |
|       return promise; | |
|     } | |
|     promise.then(successCallback, failureCallback); | |
|     return Promise.resolve(); | |
|   }; | |
|   prototype.setRemoteDescription = withCallback; | |
| 
 | |
|   withCallback = function withCallback(candidate, successCallback, failureCallback) { | |
|     var promise = addIceCandidate.apply(this, [candidate]); | |
|     if (!failureCallback) { | |
|       return promise; | |
|     } | |
|     promise.then(successCallback, failureCallback); | |
|     return Promise.resolve(); | |
|   }; | |
|   prototype.addIceCandidate = withCallback; | |
| } | |
| 
 | |
| function shimGetUserMedia(window) { | |
|   var navigator = window && window.navigator; | |
| 
 | |
|   if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { | |
|     // shim not needed in Safari 12.1 | |
|     var mediaDevices = navigator.mediaDevices; | |
|     var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); | |
|     navigator.mediaDevices.getUserMedia = function (constraints) { | |
|       return _getUserMedia(shimConstraints(constraints)); | |
|     }; | |
|   } | |
| 
 | |
|   if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { | |
|     navigator.getUserMedia = function getUserMedia(constraints, cb, errcb) { | |
|       navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); | |
|     }.bind(navigator); | |
|   } | |
| } | |
| 
 | |
| function shimConstraints(constraints) { | |
|   if (constraints && constraints.video !== undefined) { | |
|     return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) }); | |
|   } | |
| 
 | |
|   return constraints; | |
| } | |
| 
 | |
| function shimRTCIceServerUrls(window) { | |
|   if (!window.RTCPeerConnection) { | |
|     return; | |
|   } | |
|   // migrate from non-spec RTCIceServer.url to RTCIceServer.urls | |
|   var OrigPeerConnection = window.RTCPeerConnection; | |
|   window.RTCPeerConnection = function RTCPeerConnection(pcConfig, pcConstraints) { | |
|     if (pcConfig && pcConfig.iceServers) { | |
|       var newIceServers = []; | |
|       for (var i = 0; i < pcConfig.iceServers.length; i++) { | |
|         var server = pcConfig.iceServers[i]; | |
|         if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { | |
|           utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); | |
|           server = JSON.parse(JSON.stringify(server)); | |
|           server.urls = server.url; | |
|           delete server.url; | |
|           newIceServers.push(server); | |
|         } else { | |
|           newIceServers.push(pcConfig.iceServers[i]); | |
|         } | |
|       } | |
|       pcConfig.iceServers = newIceServers; | |
|     } | |
|     return new OrigPeerConnection(pcConfig, pcConstraints); | |
|   }; | |
|   window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; | |
|   // wrap static methods. Currently just generateCertificate. | |
|   if ('generateCertificate' in OrigPeerConnection) { | |
|     Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { | |
|       get: function get() { | |
|         return OrigPeerConnection.generateCertificate; | |
|       } | |
|     }); | |
|   } | |
| } | |
| 
 | |
| function shimTrackEventTransceiver(window) { | |
|   // Add event.transceiver member over deprecated event.receiver | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { | |
|     Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { | |
|       get: function get() { | |
|         return { receiver: this.receiver }; | |
|       } | |
|     }); | |
|   } | |
| } | |
| 
 | |
| function shimCreateOfferLegacy(window) { | |
|   var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; | |
|   window.RTCPeerConnection.prototype.createOffer = function createOffer(offerOptions) { | |
|     if (offerOptions) { | |
|       if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { | |
|         // support bit values | |
|         offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; | |
|       } | |
|       var audioTransceiver = this.getTransceivers().find(function (transceiver) { | |
|         return transceiver.receiver.track.kind === 'audio'; | |
|       }); | |
|       if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { | |
|         if (audioTransceiver.direction === 'sendrecv') { | |
|           if (audioTransceiver.setDirection) { | |
|             audioTransceiver.setDirection('sendonly'); | |
|           } else { | |
|             audioTransceiver.direction = 'sendonly'; | |
|           } | |
|         } else if (audioTransceiver.direction === 'recvonly') { | |
|           if (audioTransceiver.setDirection) { | |
|             audioTransceiver.setDirection('inactive'); | |
|           } else { | |
|             audioTransceiver.direction = 'inactive'; | |
|           } | |
|         } | |
|       } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { | |
|         this.addTransceiver('audio', { direction: 'recvonly' }); | |
|       } | |
| 
 | |
|       if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { | |
|         // support bit values | |
|         offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; | |
|       } | |
|       var videoTransceiver = this.getTransceivers().find(function (transceiver) { | |
|         return transceiver.receiver.track.kind === 'video'; | |
|       }); | |
|       if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { | |
|         if (videoTransceiver.direction === 'sendrecv') { | |
|           if (videoTransceiver.setDirection) { | |
|             videoTransceiver.setDirection('sendonly'); | |
|           } else { | |
|             videoTransceiver.direction = 'sendonly'; | |
|           } | |
|         } else if (videoTransceiver.direction === 'recvonly') { | |
|           if (videoTransceiver.setDirection) { | |
|             videoTransceiver.setDirection('inactive'); | |
|           } else { | |
|             videoTransceiver.direction = 'inactive'; | |
|           } | |
|         } | |
|       } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { | |
|         this.addTransceiver('video', { direction: 'recvonly' }); | |
|       } | |
|     } | |
|     return origCreateOffer.apply(this, arguments); | |
|   }; | |
| } | |
| 
 | |
| function shimAudioContext(window) { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || window.AudioContext) { | |
|     return; | |
|   } | |
|   window.AudioContext = window.webkitAudioContext; | |
| } | |
| 
 | |
| },{"../utils":11}],11:[function(require,module,exports){ | |
| /* | |
|  *  Copyright (c) 2016 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'; | |
| 
 | |
| Object.defineProperty(exports, "__esModule", { | |
|   value: true | |
| }); | |
| 
 | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| exports.extractVersion = extractVersion; | |
| exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent; | |
| exports.disableLog = disableLog; | |
| exports.disableWarnings = disableWarnings; | |
| exports.log = log; | |
| exports.deprecated = deprecated; | |
| exports.detectBrowser = detectBrowser; | |
| exports.compactObject = compactObject; | |
| exports.walkStats = walkStats; | |
| exports.filterStats = filterStats; | |
| 
 | |
| function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | |
| 
 | |
| var logDisabled_ = true; | |
| var deprecationWarnings_ = true; | |
| 
 | |
| /** | |
|  * Extract browser version out of the provided user agent string. | |
|  * | |
|  * @param {!string} uastring userAgent string. | |
|  * @param {!string} expr Regular expression used as match criteria. | |
|  * @param {!number} pos position in the version string to be returned. | |
|  * @return {!number} browser version. | |
|  */ | |
| function extractVersion(uastring, expr, pos) { | |
|   var match = uastring.match(expr); | |
|   return match && match.length >= pos && parseInt(match[pos], 10); | |
| } | |
| 
 | |
| // Wraps the peerconnection event eventNameToWrap in a function | |
| // which returns the modified event object (or false to prevent | |
| // the event). | |
| 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 wrappedCallback(e) { | |
|       var modifiedEvent = wrapper(e); | |
|       if (modifiedEvent) { | |
|         if (cb.handleEvent) { | |
|           cb.handleEvent(modifiedEvent); | |
|         } else { | |
|           cb(modifiedEvent); | |
|         } | |
|       } | |
|     }; | |
|     this._eventMap = this._eventMap || {}; | |
|     if (!this._eventMap[eventNameToWrap]) { | |
|       this._eventMap[eventNameToWrap] = new Map(); | |
|     } | |
|     this._eventMap[eventNameToWrap].set(cb, wrappedCallback); | |
|     return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); | |
|   }; | |
| 
 | |
|   var nativeRemoveEventListener = proto.removeEventListener; | |
|   proto.removeEventListener = function (nativeEventName, cb) { | |
|     if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[eventNameToWrap]) { | |
|       return nativeRemoveEventListener.apply(this, arguments); | |
|     } | |
|     if (!this._eventMap[eventNameToWrap].has(cb)) { | |
|       return nativeRemoveEventListener.apply(this, arguments); | |
|     } | |
|     var unwrappedCb = this._eventMap[eventNameToWrap].get(cb); | |
|     this._eventMap[eventNameToWrap].delete(cb); | |
|     if (this._eventMap[eventNameToWrap].size === 0) { | |
|       delete this._eventMap[eventNameToWrap]; | |
|     } | |
|     if (Object.keys(this._eventMap).length === 0) { | |
|       delete this._eventMap; | |
|     } | |
|     return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); | |
|   }; | |
| 
 | |
|   Object.defineProperty(proto, 'on' + eventNameToWrap, { | |
|     get: function get() { | |
|       return this['_on' + eventNameToWrap]; | |
|     }, | |
|     set: function set(cb) { | |
|       if (this['_on' + eventNameToWrap]) { | |
|         this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); | |
|         delete this['_on' + eventNameToWrap]; | |
|       } | |
|       if (cb) { | |
|         this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); | |
|       } | |
|     }, | |
| 
 | |
|     enumerable: true, | |
|     configurable: true | |
|   }); | |
| } | |
| 
 | |
| function disableLog(bool) { | |
|   if (typeof bool !== 'boolean') { | |
|     return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); | |
|   } | |
|   logDisabled_ = bool; | |
|   return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; | |
| } | |
| 
 | |
| /** | |
|  * Disable or enable deprecation warnings | |
|  * @param {!boolean} bool set to true to disable warnings. | |
|  */ | |
| function disableWarnings(bool) { | |
|   if (typeof bool !== 'boolean') { | |
|     return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); | |
|   } | |
|   deprecationWarnings_ = !bool; | |
|   return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); | |
| } | |
| 
 | |
| function log() { | |
|   if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') { | |
|     if (logDisabled_) { | |
|       return; | |
|     } | |
|     if (typeof console !== 'undefined' && typeof console.log === 'function') { | |
|       console.log.apply(console, arguments); | |
|     } | |
|   } | |
| } | |
| 
 | |
| /** | |
|  * Shows a deprecation warning suggesting the modern and spec-compatible API. | |
|  */ | |
| function deprecated(oldMethod, newMethod) { | |
|   if (!deprecationWarnings_) { | |
|     return; | |
|   } | |
|   console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); | |
| } | |
| 
 | |
| /** | |
|  * Browser detector. | |
|  * | |
|  * @return {object} result containing browser and version | |
|  *     properties. | |
|  */ | |
| function detectBrowser(window) { | |
|   // Returned result object. | |
|   var result = { browser: null, version: null }; | |
| 
 | |
|   // Fail early if it's not a browser | |
|   if (typeof window === 'undefined' || !window.navigator) { | |
|     result.browser = 'Not a browser.'; | |
|     return result; | |
|   } | |
| 
 | |
|   var navigator = window.navigator; | |
| 
 | |
| 
 | |
|   if (navigator.mozGetUserMedia) { | |
|     // Firefox. | |
|     result.browser = 'firefox'; | |
|     result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); | |
|   } else if (navigator.webkitGetUserMedia || window.isSecureContext === false && window.webkitRTCPeerConnection) { | |
|     // Chrome, Chromium, Webview, Opera. | |
|     // Version matches Chrome/WebRTC version. | |
|     // Chrome 74 removed webkitGetUserMedia on http as well so we need the | |
|     // more complicated fallback to webkitRTCPeerConnection. | |
|     result.browser = 'chrome'; | |
|     result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); | |
|   } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { | |
|     // Safari. | |
|     result.browser = 'safari'; | |
|     result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); | |
|     result.supportsUnifiedPlan = window.RTCRtpTransceiver && 'currentDirection' in window.RTCRtpTransceiver.prototype; | |
|   } else { | |
|     // Default fallthrough: not supported. | |
|     result.browser = 'Not a supported browser.'; | |
|     return result; | |
|   } | |
| 
 | |
|   return result; | |
| } | |
| 
 | |
| /** | |
|  * Checks if something is an object. | |
|  * | |
|  * @param {*} val The something you want to check. | |
|  * @return true if val is an object, false otherwise. | |
|  */ | |
| function isObject(val) { | |
|   return Object.prototype.toString.call(val) === '[object Object]'; | |
| } | |
| 
 | |
| /** | |
|  * Remove all empty objects and undefined values | |
|  * from a nested object -- an enhanced and vanilla version | |
|  * of Lodash's `compact`. | |
|  */ | |
| function compactObject(data) { | |
|   if (!isObject(data)) { | |
|     return data; | |
|   } | |
| 
 | |
|   return Object.keys(data).reduce(function (accumulator, key) { | |
|     var isObj = isObject(data[key]); | |
|     var value = isObj ? compactObject(data[key]) : data[key]; | |
|     var isEmptyObject = isObj && !Object.keys(value).length; | |
|     if (value === undefined || isEmptyObject) { | |
|       return accumulator; | |
|     } | |
|     return Object.assign(accumulator, _defineProperty({}, key, value)); | |
|   }, {}); | |
| } | |
| 
 | |
| /* iterates the stats graph recursively. */ | |
| function walkStats(stats, base, resultSet) { | |
|   if (!base || resultSet.has(base.id)) { | |
|     return; | |
|   } | |
|   resultSet.set(base.id, base); | |
|   Object.keys(base).forEach(function (name) { | |
|     if (name.endsWith('Id')) { | |
|       walkStats(stats, stats.get(base[name]), resultSet); | |
|     } else if (name.endsWith('Ids')) { | |
|       base[name].forEach(function (id) { | |
|         walkStats(stats, stats.get(id), resultSet); | |
|       }); | |
|     } | |
|   }); | |
| } | |
| 
 | |
| /* filter getStats for a sender/receiver track. */ | |
| function filterStats(result, track, outbound) { | |
|   var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; | |
|   var filteredResult = new Map(); | |
|   if (track === null) { | |
|     return filteredResult; | |
|   } | |
|   var trackStats = []; | |
|   result.forEach(function (value) { | |
|     if (value.type === 'track' && value.trackIdentifier === track.id) { | |
|       trackStats.push(value); | |
|     } | |
|   }); | |
|   trackStats.forEach(function (trackStat) { | |
|     result.forEach(function (stats) { | |
|       if (stats.type === streamStatsType && stats.trackId === trackStat.id) { | |
|         walkStats(result, stats, filteredResult); | |
|       } | |
|     }); | |
|   }); | |
|   return filteredResult; | |
| } | |
| 
 | |
| },{}],12:[function(require,module,exports){ | |
| /* eslint-env node */ | |
| 'use strict'; | |
| 
 | |
| // SDP helpers. | |
|  | |
| var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | |
| 
 | |
| var SDPUtils = {}; | |
| 
 | |
| // Generate an alphanumeric identifier for cname or mids. | |
| // TODO: use UUIDs instead? https://gist.github.com/jed/982883 | |
| SDPUtils.generateIdentifier = function () { | |
|   return Math.random().toString(36).substr(2, 10); | |
| }; | |
| 
 | |
| // The RTCP CNAME used by all peerconnections from the same JS. | |
| SDPUtils.localCName = SDPUtils.generateIdentifier(); | |
| 
 | |
| // Splits SDP into lines, dealing with both CRLF and LF. | |
| SDPUtils.splitLines = function (blob) { | |
|   return blob.trim().split('\n').map(function (line) { | |
|     return line.trim(); | |
|   }); | |
| }; | |
| // Splits SDP into sessionpart and mediasections. Ensures CRLF. | |
| SDPUtils.splitSections = function (blob) { | |
|   var parts = blob.split('\nm='); | |
|   return parts.map(function (part, index) { | |
|     return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; | |
|   }); | |
| }; | |
| 
 | |
| // Returns the session description. | |
| SDPUtils.getDescription = function (blob) { | |
|   var sections = SDPUtils.splitSections(blob); | |
|   return sections && sections[0]; | |
| }; | |
| 
 | |
| // Returns the individual media sections. | |
| SDPUtils.getMediaSections = function (blob) { | |
|   var sections = SDPUtils.splitSections(blob); | |
|   sections.shift(); | |
|   return sections; | |
| }; | |
| 
 | |
| // Returns lines that start with a certain prefix. | |
| SDPUtils.matchPrefix = function (blob, prefix) { | |
|   return SDPUtils.splitLines(blob).filter(function (line) { | |
|     return line.indexOf(prefix) === 0; | |
|   }); | |
| }; | |
| 
 | |
| // Parses an ICE candidate line. Sample input: | |
| // candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 | |
| // rport 55996" | |
| // Input can be prefixed with a=. | |
| SDPUtils.parseCandidate = function (line) { | |
|   var parts = void 0; | |
|   // Parse both variants. | |
|   if (line.indexOf('a=candidate:') === 0) { | |
|     parts = line.substring(12).split(' '); | |
|   } else { | |
|     parts = line.substring(10).split(' '); | |
|   } | |
| 
 | |
|   var candidate = { | |
|     foundation: parts[0], | |
|     component: { 1: 'rtp', 2: 'rtcp' }[parts[1]] || parts[1], | |
|     protocol: parts[2].toLowerCase(), | |
|     priority: parseInt(parts[3], 10), | |
|     ip: parts[4], | |
|     address: parts[4], // address is an alias for ip. | |
|     port: parseInt(parts[5], 10), | |
|     // skip parts[6] == 'typ' | |
|     type: parts[7] | |
|   }; | |
| 
 | |
|   for (var i = 8; i < parts.length; i += 2) { | |
|     switch (parts[i]) { | |
|       case 'raddr': | |
|         candidate.relatedAddress = parts[i + 1]; | |
|         break; | |
|       case 'rport': | |
|         candidate.relatedPort = parseInt(parts[i + 1], 10); | |
|         break; | |
|       case 'tcptype': | |
|         candidate.tcpType = parts[i + 1]; | |
|         break; | |
|       case 'ufrag': | |
|         candidate.ufrag = parts[i + 1]; // for backward compatibility. | |
|         candidate.usernameFragment = parts[i + 1]; | |
|         break; | |
|       default: | |
|         // extension handling, in particular ufrag. Don't overwrite. | |
|         if (candidate[parts[i]] === undefined) { | |
|           candidate[parts[i]] = parts[i + 1]; | |
|         } | |
|         break; | |
|     } | |
|   } | |
|   return candidate; | |
| }; | |
| 
 | |
| // Translates a candidate object into SDP candidate attribute. | |
| // This does not include the a= prefix! | |
| SDPUtils.writeCandidate = function (candidate) { | |
|   var sdp = []; | |
|   sdp.push(candidate.foundation); | |
| 
 | |
|   var component = candidate.component; | |
|   if (component === 'rtp') { | |
|     sdp.push(1); | |
|   } else if (component === 'rtcp') { | |
|     sdp.push(2); | |
|   } else { | |
|     sdp.push(component); | |
|   } | |
|   sdp.push(candidate.protocol.toUpperCase()); | |
|   sdp.push(candidate.priority); | |
|   sdp.push(candidate.address || candidate.ip); | |
|   sdp.push(candidate.port); | |
| 
 | |
|   var type = candidate.type; | |
|   sdp.push('typ'); | |
|   sdp.push(type); | |
|   if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) { | |
|     sdp.push('raddr'); | |
|     sdp.push(candidate.relatedAddress); | |
|     sdp.push('rport'); | |
|     sdp.push(candidate.relatedPort); | |
|   } | |
|   if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { | |
|     sdp.push('tcptype'); | |
|     sdp.push(candidate.tcpType); | |
|   } | |
|   if (candidate.usernameFragment || candidate.ufrag) { | |
|     sdp.push('ufrag'); | |
|     sdp.push(candidate.usernameFragment || candidate.ufrag); | |
|   } | |
|   return 'candidate:' + sdp.join(' '); | |
| }; | |
| 
 | |
| // Parses an ice-options line, returns an array of option tags. | |
| // Sample input: | |
| // a=ice-options:foo bar | |
| SDPUtils.parseIceOptions = function (line) { | |
|   return line.substr(14).split(' '); | |
| }; | |
| 
 | |
| // Parses a rtpmap line, returns RTCRtpCoddecParameters. Sample input: | |
| // a=rtpmap:111 opus/48000/2 | |
| SDPUtils.parseRtpMap = function (line) { | |
|   var parts = line.substr(9).split(' '); | |
|   var parsed = { | |
|     payloadType: parseInt(parts.shift(), 10) // was: id | |
|   }; | |
| 
 | |
|   parts = parts[0].split('/'); | |
| 
 | |
|   parsed.name = parts[0]; | |
|   parsed.clockRate = parseInt(parts[1], 10); // was: clockrate | |
|   parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; | |
|   // legacy alias, got renamed back to channels in ORTC. | |
|   parsed.numChannels = parsed.channels; | |
|   return parsed; | |
| }; | |
| 
 | |
| // Generates a rtpmap line from RTCRtpCodecCapability or | |
| // RTCRtpCodecParameters. | |
| SDPUtils.writeRtpMap = function (codec) { | |
|   var pt = codec.payloadType; | |
|   if (codec.preferredPayloadType !== undefined) { | |
|     pt = codec.preferredPayloadType; | |
|   } | |
|   var channels = codec.channels || codec.numChannels || 1; | |
|   return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + (channels !== 1 ? '/' + channels : '') + '\r\n'; | |
| }; | |
| 
 | |
| // Parses a extmap line (headerextension from RFC 5285). Sample input: | |
| // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset | |
| // a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset | |
| SDPUtils.parseExtmap = function (line) { | |
|   var parts = line.substr(9).split(' '); | |
|   return { | |
|     id: parseInt(parts[0], 10), | |
|     direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', | |
|     uri: parts[1] | |
|   }; | |
| }; | |
| 
 | |
| // Generates an extmap line from RTCRtpHeaderExtensionParameters or | |
| // RTCRtpHeaderExtension. | |
| SDPUtils.writeExtmap = function (headerExtension) { | |
|   return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + (headerExtension.direction && headerExtension.direction !== 'sendrecv' ? '/' + headerExtension.direction : '') + ' ' + headerExtension.uri + '\r\n'; | |
| }; | |
| 
 | |
| // Parses a fmtp line, returns dictionary. Sample input: | |
| // a=fmtp:96 vbr=on;cng=on | |
| // Also deals with vbr=on; cng=on | |
| SDPUtils.parseFmtp = function (line) { | |
|   var parsed = {}; | |
|   var kv = void 0; | |
|   var parts = line.substr(line.indexOf(' ') + 1).split(';'); | |
|   for (var j = 0; j < parts.length; j++) { | |
|     kv = parts[j].trim().split('='); | |
|     parsed[kv[0].trim()] = kv[1]; | |
|   } | |
|   return parsed; | |
| }; | |
| 
 | |
| // Generates a fmtp line from RTCRtpCodecCapability or RTCRtpCodecParameters. | |
| SDPUtils.writeFmtp = function (codec) { | |
|   var line = ''; | |
|   var pt = codec.payloadType; | |
|   if (codec.preferredPayloadType !== undefined) { | |
|     pt = codec.preferredPayloadType; | |
|   } | |
|   if (codec.parameters && Object.keys(codec.parameters).length) { | |
|     var params = []; | |
|     Object.keys(codec.parameters).forEach(function (param) { | |
|       if (codec.parameters[param] !== undefined) { | |
|         params.push(param + '=' + codec.parameters[param]); | |
|       } else { | |
|         params.push(param); | |
|       } | |
|     }); | |
|     line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; | |
|   } | |
|   return line; | |
| }; | |
| 
 | |
| // Parses a rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: | |
| // a=rtcp-fb:98 nack rpsi | |
| SDPUtils.parseRtcpFb = function (line) { | |
|   var parts = line.substr(line.indexOf(' ') + 1).split(' '); | |
|   return { | |
|     type: parts.shift(), | |
|     parameter: parts.join(' ') | |
|   }; | |
| }; | |
| 
 | |
| // Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. | |
| SDPUtils.writeRtcpFb = function (codec) { | |
|   var lines = ''; | |
|   var pt = codec.payloadType; | |
|   if (codec.preferredPayloadType !== undefined) { | |
|     pt = codec.preferredPayloadType; | |
|   } | |
|   if (codec.rtcpFeedback && codec.rtcpFeedback.length) { | |
|     // FIXME: special handling for trr-int? | |
|     codec.rtcpFeedback.forEach(function (fb) { | |
|       lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + '\r\n'; | |
|     }); | |
|   } | |
|   return lines; | |
| }; | |
| 
 | |
| // Parses a RFC 5576 ssrc media attribute. Sample input: | |
| // a=ssrc:3735928559 cname:something | |
| SDPUtils.parseSsrcMedia = function (line) { | |
|   var sp = line.indexOf(' '); | |
|   var parts = { | |
|     ssrc: parseInt(line.substr(7, sp - 7), 10) | |
|   }; | |
|   var colon = line.indexOf(':', sp); | |
|   if (colon > -1) { | |
|     parts.attribute = line.substr(sp + 1, colon - sp - 1); | |
|     parts.value = line.substr(colon + 1); | |
|   } else { | |
|     parts.attribute = line.substr(sp + 1); | |
|   } | |
|   return parts; | |
| }; | |
| 
 | |
| // Parse a ssrc-group line (see RFC 5576). Sample input: | |
| // a=ssrc-group:semantics 12 34 | |
| SDPUtils.parseSsrcGroup = function (line) { | |
|   var parts = line.substr(13).split(' '); | |
|   return { | |
|     semantics: parts.shift(), | |
|     ssrcs: parts.map(function (ssrc) { | |
|       return parseInt(ssrc, 10); | |
|     }) | |
|   }; | |
| }; | |
| 
 | |
| // Extracts the MID (RFC 5888) from a media section. | |
| // Returns the MID or undefined if no mid line was found. | |
| SDPUtils.getMid = function (mediaSection) { | |
|   var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; | |
|   if (mid) { | |
|     return mid.substr(6); | |
|   } | |
| }; | |
| 
 | |
| // Parses a fingerprint line for DTLS-SRTP. | |
| SDPUtils.parseFingerprint = function (line) { | |
|   var parts = line.substr(14).split(' '); | |
|   return { | |
|     algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. | |
|     value: parts[1].toUpperCase() // the definition is upper-case in RFC 4572. | |
|   }; | |
| }; | |
| 
 | |
| // Extracts DTLS parameters from SDP media section or sessionpart. | |
| // FIXME: for consistency with other functions this should only | |
| //   get the fingerprint line as input. See also getIceParameters. | |
| SDPUtils.getDtlsParameters = function (mediaSection, sessionpart) { | |
|   var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=fingerprint:'); | |
|   // Note: a=setup line is ignored since we use the 'auto' role in Edge. | |
|   return { | |
|     role: 'auto', | |
|     fingerprints: lines.map(SDPUtils.parseFingerprint) | |
|   }; | |
| }; | |
| 
 | |
| // Serializes DTLS parameters to SDP. | |
| SDPUtils.writeDtlsParameters = function (params, setupType) { | |
|   var sdp = 'a=setup:' + setupType + '\r\n'; | |
|   params.fingerprints.forEach(function (fp) { | |
|     sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; | |
|   }); | |
|   return sdp; | |
| }; | |
| 
 | |
| // Parses a=crypto lines into | |
| //   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members | |
| SDPUtils.parseCryptoLine = function (line) { | |
|   var parts = line.substr(9).split(' '); | |
|   return { | |
|     tag: parseInt(parts[0], 10), | |
|     cryptoSuite: parts[1], | |
|     keyParams: parts[2], | |
|     sessionParams: parts.slice(3) | |
|   }; | |
| }; | |
| 
 | |
| SDPUtils.writeCryptoLine = function (parameters) { | |
|   return 'a=crypto:' + parameters.tag + ' ' + parameters.cryptoSuite + ' ' + (_typeof(parameters.keyParams) === 'object' ? SDPUtils.writeCryptoKeyParams(parameters.keyParams) : parameters.keyParams) + (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') + '\r\n'; | |
| }; | |
| 
 | |
| // Parses the crypto key parameters into | |
| //   https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam* | |
| SDPUtils.parseCryptoKeyParams = function (keyParams) { | |
|   if (keyParams.indexOf('inline:') !== 0) { | |
|     return null; | |
|   } | |
|   var parts = keyParams.substr(7).split('|'); | |
|   return { | |
|     keyMethod: 'inline', | |
|     keySalt: parts[0], | |
|     lifeTime: parts[1], | |
|     mkiValue: parts[2] ? parts[2].split(':')[0] : undefined, | |
|     mkiLength: parts[2] ? parts[2].split(':')[1] : undefined | |
|   }; | |
| }; | |
| 
 | |
| SDPUtils.writeCryptoKeyParams = function (keyParams) { | |
|   return keyParams.keyMethod + ':' + keyParams.keySalt + (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') + (keyParams.mkiValue && keyParams.mkiLength ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength : ''); | |
| }; | |
| 
 | |
| // Extracts all SDES parameters. | |
| SDPUtils.getCryptoParameters = function (mediaSection, sessionpart) { | |
|   var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=crypto:'); | |
|   return lines.map(SDPUtils.parseCryptoLine); | |
| }; | |
| 
 | |
| // Parses ICE information from SDP media section or sessionpart. | |
| // FIXME: for consistency with other functions this should only | |
| //   get the ice-ufrag and ice-pwd lines as input. | |
| SDPUtils.getIceParameters = function (mediaSection, sessionpart) { | |
|   var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-ufrag:')[0]; | |
|   var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart, 'a=ice-pwd:')[0]; | |
|   if (!(ufrag && pwd)) { | |
|     return null; | |
|   } | |
|   return { | |
|     usernameFragment: ufrag.substr(12), | |
|     password: pwd.substr(10) | |
|   }; | |
| }; | |
| 
 | |
| // Serializes ICE parameters to SDP. | |
| SDPUtils.writeIceParameters = function (params) { | |
|   var sdp = 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + 'a=ice-pwd:' + params.password + '\r\n'; | |
|   if (params.iceLite) { | |
|     sdp += 'a=ice-lite\r\n'; | |
|   } | |
|   return sdp; | |
| }; | |
| 
 | |
| // Parses the SDP media section and returns RTCRtpParameters. | |
| SDPUtils.parseRtpParameters = function (mediaSection) { | |
|   var description = { | |
|     codecs: [], | |
|     headerExtensions: [], | |
|     fecMechanisms: [], | |
|     rtcp: [] | |
|   }; | |
|   var lines = SDPUtils.splitLines(mediaSection); | |
|   var mline = lines[0].split(' '); | |
|   for (var i = 3; i < mline.length; i++) { | |
|     // find all codecs from mline[3..] | |
|     var pt = mline[i]; | |
|     var rtpmapline = SDPUtils.matchPrefix(mediaSection, 'a=rtpmap:' + pt + ' ')[0]; | |
|     if (rtpmapline) { | |
|       var codec = SDPUtils.parseRtpMap(rtpmapline); | |
|       var fmtps = SDPUtils.matchPrefix(mediaSection, 'a=fmtp:' + pt + ' '); | |
|       // Only the first a=fmtp:<pt> is considered. | |
|       codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; | |
|       codec.rtcpFeedback = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-fb:' + pt + ' ').map(SDPUtils.parseRtcpFb); | |
|       description.codecs.push(codec); | |
|       // parse FEC mechanisms from rtpmap lines. | |
|       switch (codec.name.toUpperCase()) { | |
|         case 'RED': | |
|         case 'ULPFEC': | |
|           description.fecMechanisms.push(codec.name.toUpperCase()); | |
|           break; | |
|         default: | |
|           // only RED and ULPFEC are recognized as FEC mechanisms. | |
|           break; | |
|       } | |
|     } | |
|   } | |
|   SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function (line) { | |
|     description.headerExtensions.push(SDPUtils.parseExtmap(line)); | |
|   }); | |
|   // FIXME: parse rtcp. | |
|   return description; | |
| }; | |
| 
 | |
| // Generates parts of the SDP media section describing the capabilities / | |
| // parameters. | |
| SDPUtils.writeRtpDescription = function (kind, caps) { | |
|   var sdp = ''; | |
| 
 | |
|   // Build the mline. | |
|   sdp += 'm=' + kind + ' '; | |
|   sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. | |
|   sdp += ' UDP/TLS/RTP/SAVPF '; | |
|   sdp += caps.codecs.map(function (codec) { | |
|     if (codec.preferredPayloadType !== undefined) { | |
|       return codec.preferredPayloadType; | |
|     } | |
|     return codec.payloadType; | |
|   }).join(' ') + '\r\n'; | |
| 
 | |
|   sdp += 'c=IN IP4 0.0.0.0\r\n'; | |
|   sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; | |
| 
 | |
|   // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. | |
|   caps.codecs.forEach(function (codec) { | |
|     sdp += SDPUtils.writeRtpMap(codec); | |
|     sdp += SDPUtils.writeFmtp(codec); | |
|     sdp += SDPUtils.writeRtcpFb(codec); | |
|   }); | |
|   var maxptime = 0; | |
|   caps.codecs.forEach(function (codec) { | |
|     if (codec.maxptime > maxptime) { | |
|       maxptime = codec.maxptime; | |
|     } | |
|   }); | |
|   if (maxptime > 0) { | |
|     sdp += 'a=maxptime:' + maxptime + '\r\n'; | |
|   } | |
| 
 | |
|   if (caps.headerExtensions) { | |
|     caps.headerExtensions.forEach(function (extension) { | |
|       sdp += SDPUtils.writeExtmap(extension); | |
|     }); | |
|   } | |
|   // FIXME: write fecMechanisms. | |
|   return sdp; | |
| }; | |
| 
 | |
| // Parses the SDP media section and returns an array of | |
| // RTCRtpEncodingParameters. | |
| SDPUtils.parseRtpEncodingParameters = function (mediaSection) { | |
|   var encodingParameters = []; | |
|   var description = SDPUtils.parseRtpParameters(mediaSection); | |
|   var hasRed = description.fecMechanisms.indexOf('RED') !== -1; | |
|   var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; | |
| 
 | |
|   // filter a=ssrc:... cname:, ignore PlanB-msid | |
|   var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(function (line) { | |
|     return SDPUtils.parseSsrcMedia(line); | |
|   }).filter(function (parts) { | |
|     return parts.attribute === 'cname'; | |
|   }); | |
|   var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; | |
|   var secondarySsrc = void 0; | |
| 
 | |
|   var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID').map(function (line) { | |
|     var parts = line.substr(17).split(' '); | |
|     return parts.map(function (part) { | |
|       return parseInt(part, 10); | |
|     }); | |
|   }); | |
|   if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { | |
|     secondarySsrc = flows[0][1]; | |
|   } | |
| 
 | |
|   description.codecs.forEach(function (codec) { | |
|     if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { | |
|       var encParam = { | |
|         ssrc: primarySsrc, | |
|         codecPayloadType: parseInt(codec.parameters.apt, 10) | |
|       }; | |
|       if (primarySsrc && secondarySsrc) { | |
|         encParam.rtx = { ssrc: secondarySsrc }; | |
|       } | |
|       encodingParameters.push(encParam); | |
|       if (hasRed) { | |
|         encParam = JSON.parse(JSON.stringify(encParam)); | |
|         encParam.fec = { | |
|           ssrc: primarySsrc, | |
|           mechanism: hasUlpfec ? 'red+ulpfec' : 'red' | |
|         }; | |
|         encodingParameters.push(encParam); | |
|       } | |
|     } | |
|   }); | |
|   if (encodingParameters.length === 0 && primarySsrc) { | |
|     encodingParameters.push({ | |
|       ssrc: primarySsrc | |
|     }); | |
|   } | |
| 
 | |
|   // we support both b=AS and b=TIAS but interpret AS as TIAS. | |
|   var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); | |
|   if (bandwidth.length) { | |
|     if (bandwidth[0].indexOf('b=TIAS:') === 0) { | |
|       bandwidth = parseInt(bandwidth[0].substr(7), 10); | |
|     } else if (bandwidth[0].indexOf('b=AS:') === 0) { | |
|       // use formula from JSEP to convert b=AS to TIAS value. | |
|       bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - 50 * 40 * 8; | |
|     } else { | |
|       bandwidth = undefined; | |
|     } | |
|     encodingParameters.forEach(function (params) { | |
|       params.maxBitrate = bandwidth; | |
|     }); | |
|   } | |
|   return encodingParameters; | |
| }; | |
| 
 | |
| // parses http://draft.ortc.org/#rtcrtcpparameters* | |
| SDPUtils.parseRtcpParameters = function (mediaSection) { | |
|   var rtcpParameters = {}; | |
| 
 | |
|   // Gets the first SSRC. Note that with RTX there might be multiple | |
|   // SSRCs. | |
|   var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:').map(function (line) { | |
|     return SDPUtils.parseSsrcMedia(line); | |
|   }).filter(function (obj) { | |
|     return obj.attribute === 'cname'; | |
|   })[0]; | |
|   if (remoteSsrc) { | |
|     rtcpParameters.cname = remoteSsrc.value; | |
|     rtcpParameters.ssrc = remoteSsrc.ssrc; | |
|   } | |
| 
 | |
|   // Edge uses the compound attribute instead of reducedSize | |
|   // compound is !reducedSize | |
|   var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); | |
|   rtcpParameters.reducedSize = rsize.length > 0; | |
|   rtcpParameters.compound = rsize.length === 0; | |
| 
 | |
|   // parses the rtcp-mux attrіbute. | |
|   // Note that Edge does not support unmuxed RTCP. | |
|   var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); | |
|   rtcpParameters.mux = mux.length > 0; | |
| 
 | |
|   return rtcpParameters; | |
| }; | |
| 
 | |
| SDPUtils.writeRtcpParameters = function (rtcpParameters) { | |
|   var sdp = ''; | |
|   if (rtcpParameters.reducedSize) { | |
|     sdp += 'a=rtcp-rsize\r\n'; | |
|   } | |
|   if (rtcpParameters.mux) { | |
|     sdp += 'a=rtcp-mux\r\n'; | |
|   } | |
|   if (rtcpParameters.ssrc !== undefined && rtcpParameters.cname) { | |
|     sdp += 'a=ssrc:' + rtcpParameters.ssrc + ' cname:' + rtcpParameters.cname + '\r\n'; | |
|   } | |
|   return sdp; | |
| }; | |
| 
 | |
| // parses either a=msid: or a=ssrc:... msid lines and returns | |
| // the id of the MediaStream and MediaStreamTrack. | |
| SDPUtils.parseMsid = function (mediaSection) { | |
|   var parts = void 0; | |
|   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 (msidParts) { | |
|     return msidParts.attribute === 'msid'; | |
|   }); | |
|   if (planB.length > 0) { | |
|     parts = planB[0].value.split(' '); | |
|     return { stream: parts[0], track: parts[1] }; | |
|   } | |
| }; | |
| 
 | |
| // SCTP | |
| // parses draft-ietf-mmusic-sctp-sdp-26 first and falls back | |
| // to draft-ietf-mmusic-sctp-sdp-05 | |
| SDPUtils.parseSctpDescription = function (mediaSection) { | |
|   var mline = SDPUtils.parseMLine(mediaSection); | |
|   var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:'); | |
|   var maxMessageSize = void 0; | |
|   if (maxSizeLine.length > 0) { | |
|     maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10); | |
|   } | |
|   if (isNaN(maxMessageSize)) { | |
|     maxMessageSize = 65536; | |
|   } | |
|   var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:'); | |
|   if (sctpPort.length > 0) { | |
|     return { | |
|       port: parseInt(sctpPort[0].substr(12), 10), | |
|       protocol: mline.fmt, | |
|       maxMessageSize: maxMessageSize | |
|     }; | |
|   } | |
|   var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:'); | |
|   if (sctpMapLines.length > 0) { | |
|     var parts = sctpMapLines[0].substr(10).split(' '); | |
|     return { | |
|       port: parseInt(parts[0], 10), | |
|       protocol: parts[1], | |
|       maxMessageSize: maxMessageSize | |
|     }; | |
|   } | |
| }; | |
| 
 | |
| // SCTP | |
| // outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers | |
| // support by now receiving in this format, unless we originally parsed | |
| // as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line | |
| // protocol of DTLS/SCTP -- without UDP/ or TCP/) | |
| SDPUtils.writeSctpDescription = function (media, sctp) { | |
|   var output = []; | |
|   if (media.protocol !== 'DTLS/SCTP') { | |
|     output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctp-port:' + sctp.port + '\r\n']; | |
|   } else { | |
|     output = ['m=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n', 'c=IN IP4 0.0.0.0\r\n', 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n']; | |
|   } | |
|   if (sctp.maxMessageSize !== undefined) { | |
|     output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n'); | |
|   } | |
|   return output.join(''); | |
| }; | |
| 
 | |
| // Generate a session ID for SDP. | |
| // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 | |
| // recommends using a cryptographically random +ve 64-bit value | |
| // but right now this should be acceptable and within the right range | |
| SDPUtils.generateSessionId = function () { | |
|   return Math.random().toString().substr(2, 21); | |
| }; | |
| 
 | |
| // Write boiler plate for start of SDP | |
| // sessId argument is optional - if not supplied it will | |
| // be generated randomly | |
| // sessVersion is optional and defaults to 2 | |
| // sessUser is optional and defaults to 'thisisadapterortc' | |
| SDPUtils.writeSessionBoilerplate = function (sessId, sessVer, sessUser) { | |
|   var sessionId = void 0; | |
|   var version = sessVer !== undefined ? sessVer : 2; | |
|   if (sessId) { | |
|     sessionId = sessId; | |
|   } else { | |
|     sessionId = SDPUtils.generateSessionId(); | |
|   } | |
|   var user = sessUser || 'thisisadapterortc'; | |
|   // FIXME: sess-id should be an NTP timestamp. | |
|   return 'v=0\r\n' + 'o=' + user + ' ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; | |
| }; | |
| 
 | |
| // Gets the direction from the mediaSection or the sessionpart. | |
| SDPUtils.getDirection = function (mediaSection, sessionpart) { | |
|   // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. | |
|   var lines = SDPUtils.splitLines(mediaSection); | |
|   for (var i = 0; i < lines.length; i++) { | |
|     switch (lines[i]) { | |
|       case 'a=sendrecv': | |
|       case 'a=sendonly': | |
|       case 'a=recvonly': | |
|       case 'a=inactive': | |
|         return lines[i].substr(2); | |
|       default: | |
|       // FIXME: What should happen here? | |
|     } | |
|   } | |
|   if (sessionpart) { | |
|     return SDPUtils.getDirection(sessionpart); | |
|   } | |
|   return 'sendrecv'; | |
| }; | |
| 
 | |
| SDPUtils.getKind = function (mediaSection) { | |
|   var lines = SDPUtils.splitLines(mediaSection); | |
|   var mline = lines[0].split(' '); | |
|   return mline[0].substr(2); | |
| }; | |
| 
 | |
| SDPUtils.isRejected = function (mediaSection) { | |
|   return mediaSection.split(' ', 2)[1] === '0'; | |
| }; | |
| 
 | |
| SDPUtils.parseMLine = function (mediaSection) { | |
|   var lines = SDPUtils.splitLines(mediaSection); | |
|   var parts = lines[0].substr(2).split(' '); | |
|   return { | |
|     kind: parts[0], | |
|     port: parseInt(parts[1], 10), | |
|     protocol: parts[2], | |
|     fmt: parts.slice(3).join(' ') | |
|   }; | |
| }; | |
| 
 | |
| SDPUtils.parseOLine = function (mediaSection) { | |
|   var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; | |
|   var parts = line.substr(2).split(' '); | |
|   return { | |
|     username: parts[0], | |
|     sessionId: parts[1], | |
|     sessionVersion: parseInt(parts[2], 10), | |
|     netType: parts[3], | |
|     addressType: parts[4], | |
|     address: parts[5] | |
|   }; | |
| }; | |
| 
 | |
| // a very naive interpretation of a valid SDP. | |
| SDPUtils.isValidSDP = function (blob) { | |
|   if (typeof blob !== 'string' || blob.length === 0) { | |
|     return false; | |
|   } | |
|   var lines = SDPUtils.splitLines(blob); | |
|   for (var i = 0; i < lines.length; i++) { | |
|     if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { | |
|       return false; | |
|     } | |
|     // TODO: check the modifier a bit more. | |
|   } | |
|   return true; | |
| }; | |
| 
 | |
| // Expose public methods. | |
| if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === 'object') { | |
|   module.exports = SDPUtils; | |
| } | |
| },{}]},{},[1])(1) | |
| });
 |