pax_global_header 0000666 0000000 0000000 00000000064 12544264443 0014522 g ustar 00root root 0000000 0000000 52 comment=9ddf6664289d9ab9da786edcd2f8b61b0633f013
rtcninja.js-0.6.2/ 0000775 0000000 0000000 00000000000 12544264443 0013752 5 ustar 00root root 0000000 0000000 rtcninja.js-0.6.2/.gitignore 0000664 0000000 0000000 00000000303 12544264443 0015736 0 ustar 00root root 0000000 0000000 # Node and bower deps
node_modules
bower_components
# Logs and databases
*.log
dump.rdb
output
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
# Others
html
rtcninja.js-0.6.2/.jscsrc 0000664 0000000 0000000 00000000077 12544264443 0015246 0 ustar 00root root 0000000 0000000 {
"preset": "crockford",
"validateIndentation": "\t"
}
rtcninja.js-0.6.2/.jshintrc 0000664 0000000 0000000 00000001010 12544264443 0015567 0 ustar 00root root 0000000 0000000 {
"bitwise": true,
"curly": true,
"eqeqeq": true,
"forin": true,
"freeze": true,
"latedef": "function",
"noarg": true,
"nonbsp": true,
"nonew": true,
"plusplus": true,
"undef": true,
"unused": true,
"strict": true,
"maxparams": 3,
"maxdepth": 4,
"maxstatements": 70,
"maxlen": 140,
"validthis": true,
"browser": true,
"browserify": true,
"devel": false,
"jquery": false,
"mocha": false,
"node": true,
"worker": false
}
rtcninja.js-0.6.2/.npmignore 0000664 0000000 0000000 00000000052 12544264443 0015746 0 ustar 00root root 0000000 0000000 .gitignore
/node_modules/
/NO_GIT/
/html/
rtcninja.js-0.6.2/LICENSE 0000664 0000000 0000000 00000002073 12544264443 0014761 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2015, eFace2Face Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
rtcninja.js-0.6.2/README.md 0000664 0000000 0000000 00000006270 12544264443 0015236 0 ustar 00root root 0000000 0000000 # rtcninja.js
WebRTC API wrapper to deal with different browsers transparently, [eventually](http://iswebrtcreadyyet.com/) this library shouldn't be needed. We only have to wait until W3C group in charge [finishes the specification](https://tools.ietf.org/wg/rtcweb/) and the different browsers implement it correctly :sweat_smile:.
Supported environments:
* [Google Chrome](https://www.google.com/chrome/browser/desktop/index.html) (desktop & mobile)
* [Google Canary](https://www.google.com/chrome/browser/canary.html) (desktop & mobile)
* [Mozilla Firefox](https://www.mozilla.org/en-GB/firefox/new) (desktop & mobile)
* [Firefox Nigthly](https://nightly.mozilla.org/) (desktop & mobile)
* [Opera](http://www.opera.com/)
* [Vivaldi](https://vivaldi.com/)
* [CrossWalk](https://crosswalk-project.org/)
* [Cordova](cordova.apache.org): iOS support, you only have to use our plugin [following these steps](https://github.com/eface2face/cordova-plugin-iosrtc#usage).
* [Node-webkit](https://github.com/nwjs/nw.js/)
## Installation
### **npm**:
```bash
$ npm install rtcninja
```
and then:
```javascript
var rtcninja = require('rtcninja');
```
### **bower**:
```bash
$ bower install rtcninja
```
## Browserified library
Take a browserified version of the library from the `dist/` folder:
* `dist/rtcninja-X.Y.Z.js`: The uncompressed version.
* `dist/rtcninja-X.Y.Z.min.js`: The compressed production-ready version.
* `dist/rtcninja.js`: A copy of the uncompressed version.
* `dist/rtcninja.min.js`: A copy of the compressed version.
They expose the global `window.rtcninja` module.
## Usage
In the [examples](./examples/) folder we provide a complete one.
```javascript
// Must first call it.
rtcninja();
// Then check.
if (rtcninja.hasWebRTC()) {
// Do something.
}
else {
// Do something.
}
```
## Documentation
You can read the full [API documentation](docs/index.md) in the docs folder.
## Issues
https://github.com/eface2face/rtcninja.js/issues
## Developer guide
* Create a branch with a name including your user and a meaningful word about the fix/feature you're going to implement, ie: "jesusprubio/fixstuff"
* Use [GitHub pull requests](https://help.github.com/articles/using-pull-requests).
* Conventions:
* We use [JSHint](http://jshint.com/) and [Crockford's Styleguide](http://javascript.crockford.com/code.html).
* Please run `grunt lint` to be sure your code fits with them.
### Debugging
The library includes the Node [debug](https://github.com/visionmedia/debug) module. In order to enable debugging:
In Node set the `DEBUG=rtcninja*` environment variable before running the application, or set it at the top of the script:
```javascript
process.env.DEBUG = 'rtcninja*';
```
In the browser run `rtcninja.debug.enable('rtcninja*');` and reload the page. Note that the debugging settings are stored into the browser LocalStorage. To disable it run `rtcninja.debug.disable('rtcninja*');`.
## Copyright & License
* eFace2Face Inc.
* [MIT](./LICENSE)
rtcninja.js-0.6.2/banner.txt 0000664 0000000 0000000 00000000234 12544264443 0015757 0 ustar 00root root 0000000 0000000 /*
* <%= pkg.name %>.js v<%= pkg.version %>
* <%= pkg.description %>
* Copyright <%= currentYear %> <%= pkg.author %>
* License <%= pkg.license %>
*/
rtcninja.js-0.6.2/bower.json 0000664 0000000 0000000 00000001000 12544264443 0015752 0 ustar 00root root 0000000 0000000 {
"name": "rtcninja",
"version": "0.6.2",
"description": "WebRTC API wrapper to deal with different browsers",
"author": "Iñaki Baz Castillo (http://eface2face.com)",
"license": "MIT",
"main": "dist/rtcninja.js",
"homepage": "https://github.com/eface2face/rtcninja.js",
"repository": {
"type": "git",
"url": "https://github.com/eface2face/rtcninja.js.git"
},
"keywords": [
"webrtc"
],
"ignore": [
"node_modules",
"NO_GIT",
"test"
]
}
rtcninja.js-0.6.2/dist/ 0000775 0000000 0000000 00000000000 12544264443 0014715 5 ustar 00root root 0000000 0000000 rtcninja.js-0.6.2/dist/rtcninja-0.6.2.js 0000664 0000000 0000000 00000147650 12544264443 0017541 0 ustar 00root root 0000000 0000000 /*
* rtcninja.js v0.6.2
* WebRTC API wrapper to deal with different browsers
* Copyright 2015 Iñaki Baz Castillo (http://eface2face.com)
* License MIT
*/
(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.rtcninja = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 32) ||
(browser.android && browser.chrome && browserVersion >= 39) ||
(isDesktop && browser.opera && browserVersion >= 27) ||
(browser.android && browser.opera && browserVersion >= 24) ||
(browser.android && browser.webkit && !browser.chrome && browserVersion >= 37) ||
(virtNavigator.webkitGetUserMedia && virtGlobal.webkitRTCPeerConnection)
) {
hasWebRTC = true;
getUserMedia = virtNavigator.webkitGetUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.webkitRTCPeerConnection;
RTCSessionDescription = virtGlobal.RTCSessionDescription;
RTCIceCandidate = virtGlobal.RTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = true;
oldSpecRTCOfferOptions = false;
// Firefox desktop, Firefox Android.
} else if (
(isDesktop && browser.firefox && browserVersion >= 22) ||
(browser.android && browser.firefox && browserVersion >= 33) ||
(virtNavigator.mozGetUserMedia && virtGlobal.mozRTCPeerConnection)
) {
hasWebRTC = true;
getUserMedia = virtNavigator.mozGetUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.mozRTCPeerConnection;
RTCSessionDescription = virtGlobal.mozRTCSessionDescription;
RTCIceCandidate = virtGlobal.mozRTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
attachMediaStream = function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = false;
oldSpecRTCOfferOptions = false;
// WebRTC plugin required. For example IE or Safari with the Temasys plugin.
} else if (
options.plugin &&
typeof options.plugin.isRequired === 'function' &&
options.plugin.isRequired() &&
typeof options.plugin.isInstalled === 'function' &&
options.plugin.isInstalled()
) {
var pluginiface = options.plugin.interface;
hasWebRTC = true;
getUserMedia = pluginiface.getUserMedia;
RTCPeerConnection = pluginiface.RTCPeerConnection;
RTCSessionDescription = pluginiface.RTCSessionDescription;
RTCIceCandidate = pluginiface.RTCIceCandidate;
MediaStreamTrack = pluginiface.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = pluginiface.attachMediaStream;
canRenegotiate = pluginiface.canRenegotiate;
oldSpecRTCOfferOptions = true; // TODO: Update when fixed in the plugin.
// Best effort (may be adater.js is loaded).
} else if (virtNavigator.getUserMedia && virtGlobal.RTCPeerConnection) {
hasWebRTC = true;
getUserMedia = virtNavigator.getUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.RTCPeerConnection;
RTCSessionDescription = virtGlobal.RTCSessionDescription;
RTCIceCandidate = virtGlobal.RTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = virtGlobal.attachMediaStream || function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = false;
oldSpecRTCOfferOptions = false;
}
function throwNonSupported(item) {
return function () {
throw new Error('rtcninja: WebRTC not supported, missing ' + item +
' [browser: ' + browser.name + ' ' + browser.version + ']');
};
}
// Public API.
// Expose a WebRTC checker.
Adapter.hasWebRTC = function () {
return hasWebRTC;
};
// Expose getUserMedia.
if (getUserMedia) {
Adapter.getUserMedia = function (constraints, successCallback, errorCallback) {
debug('getUserMedia() | constraints: %o', constraints);
try {
getUserMedia(constraints,
function (stream) {
debug('getUserMedia() | success');
if (successCallback) {
successCallback(stream);
}
},
function (error) {
debug('getUserMedia() | error:', error);
if (errorCallback) {
errorCallback(error);
}
}
);
}
catch (error) {
debugerror('getUserMedia() | error:', error);
if (errorCallback) {
errorCallback(error);
}
}
};
} else {
Adapter.getUserMedia = function (constraints, successCallback, errorCallback) {
debugerror('getUserMedia() | WebRTC not supported');
if (errorCallback) {
errorCallback(new Error('rtcninja: WebRTC not supported, missing ' +
'getUserMedia [browser: ' + browser.name + ' ' + browser.version + ']'));
} else {
throwNonSupported('getUserMedia');
}
};
}
// Expose RTCPeerConnection.
Adapter.RTCPeerConnection = RTCPeerConnection || throwNonSupported('RTCPeerConnection');
// Expose RTCSessionDescription.
Adapter.RTCSessionDescription = RTCSessionDescription || throwNonSupported('RTCSessionDescription');
// Expose RTCIceCandidate.
Adapter.RTCIceCandidate = RTCIceCandidate || throwNonSupported('RTCIceCandidate');
// Expose MediaStreamTrack.
Adapter.MediaStreamTrack = MediaStreamTrack || throwNonSupported('MediaStreamTrack');
// Expose getMediaDevices.
Adapter.getMediaDevices = getMediaDevices;
// Expose MediaStreamTrack.
Adapter.attachMediaStream = attachMediaStream || throwNonSupported('attachMediaStream');
// Expose canRenegotiate attribute.
Adapter.canRenegotiate = canRenegotiate;
// Expose closeMediaStream.
Adapter.closeMediaStream = function (stream) {
if (!stream) {
return;
}
// Latest spec states that MediaStream has no stop() method and instead must
// call stop() on every MediaStreamTrack.
if (MediaStreamTrack && MediaStreamTrack.prototype && MediaStreamTrack.prototype.stop) {
debug('closeMediaStream() | calling stop() on all the MediaStreamTrack');
var tracks, i, len;
if (stream.getTracks) {
tracks = stream.getTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
} else {
tracks = stream.getAudioTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
tracks = stream.getVideoTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
}
// Deprecated by the spec, but still in use.
} else if (typeof stream.stop === 'function') {
debug('closeMediaStream() | calling stop() on the MediaStream');
stream.stop();
}
};
// Expose fixPeerConnectionConfig.
Adapter.fixPeerConnectionConfig = function (pcConfig) {
var i, len, iceServer, hasUrls, hasUrl;
if (!Array.isArray(pcConfig.iceServers)) {
pcConfig.iceServers = [];
}
for (i = 0, len = pcConfig.iceServers.length; i < len; i += 1) {
iceServer = pcConfig.iceServers[i];
hasUrls = iceServer.hasOwnProperty('urls');
hasUrl = iceServer.hasOwnProperty('url');
if (typeof iceServer === 'object') {
// Has .urls but not .url, so add .url with a single string value.
if (hasUrls && !hasUrl) {
iceServer.url = (Array.isArray(iceServer.urls) ? iceServer.urls[0] : iceServer.urls);
// Has .url but not .urls, so add .urls with same value.
} else if (!hasUrls && hasUrl) {
iceServer.urls = (Array.isArray(iceServer.url) ? iceServer.url.slice() : iceServer.url);
}
// Ensure .url is a single string.
if (hasUrl && Array.isArray(iceServer.url)) {
iceServer.url = iceServer.url[0];
}
}
}
};
// Expose fixRTCOfferOptions.
Adapter.fixRTCOfferOptions = function (options) {
options = options || {};
// New spec.
if (!oldSpecRTCOfferOptions) {
if (options.mandatory && options.mandatory.OfferToReceiveAudio) {
options.offerToReceiveAudio = 1;
}
if (options.mandatory && options.mandatory.OfferToReceiveVideo) {
options.offerToReceiveVideo = 1;
}
delete options.mandatory;
// Old spec.
} else {
if (options.offerToReceiveAudio) {
options.mandatory = options.mandatory || {};
options.mandatory.OfferToReceiveAudio = true;
}
if (options.offerToReceiveVideo) {
options.mandatory = options.mandatory || {};
options.mandatory.OfferToReceiveVideo = true;
}
}
};
return Adapter;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"bowser":5,"debug":6}],2:[function(require,module,exports){
'use strict';
// Expose the RTCPeerConnection class.
module.exports = RTCPeerConnection;
// Dependencies.
var merge = require('merge'),
debug = require('debug')('rtcninja:RTCPeerConnection'),
debugerror = require('debug')('rtcninja:ERROR:RTCPeerConnection'),
Adapter = require('./Adapter'),
// Internal constants.
C = {
REGEXP_NORMALIZED_CANDIDATE: new RegExp(/^candidate:/i),
REGEXP_FIX_CANDIDATE: new RegExp(/(^a=|\r|\n)/gi),
REGEXP_RELAY_CANDIDATE: new RegExp(/ relay /i),
REGEXP_SDP_CANDIDATES: new RegExp(/^a=candidate:.*\r\n/igm),
REGEXP_SDP_NON_RELAY_CANDIDATES: new RegExp(/^a=candidate:(.(?!relay ))*\r\n/igm)
},
// Internal variables.
VAR = {
normalizeCandidate: null
};
debugerror.log = console.warn.bind(console);
// Constructor
function RTCPeerConnection(pcConfig, pcConstraints) {
debug('new | pcConfig: %o', pcConfig);
// Set this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
// NOTE: Deprecated pcConstraints argument.
this.pcConstraints = pcConstraints;
// Own version of the localDescription.
this.ourLocalDescription = null;
// Latest values of PC attributes to avoid events with same value.
this.ourSignalingState = null;
this.ourIceConnectionState = null;
this.ourIceGatheringState = null;
// Timer for options.gatheringTimeout.
this.timerGatheringTimeout = null;
// Timer for options.gatheringTimeoutAfterRelay.
this.timerGatheringTimeoutAfterRelay = null;
// Flag to ignore new gathered ICE candidates.
this.ignoreIceGathering = false;
// Flag set when closed.
this.closed = false;
// Set RTCPeerConnection.
setPeerConnection.call(this);
// Set properties.
setProperties.call(this);
}
// Public API.
RTCPeerConnection.prototype.createOffer = function (successCallback, failureCallback, options) {
debug('createOffer()');
var self = this;
Adapter.fixRTCOfferOptions(options);
this.pc.createOffer(
function (offer) {
if (isClosed.call(self)) {
return;
}
debug('createOffer() | success');
if (successCallback) {
successCallback(offer);
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('createOffer() | error:', error);
if (failureCallback) {
failureCallback(error);
}
},
options
);
};
RTCPeerConnection.prototype.createAnswer = function (successCallback, failureCallback, options) {
debug('createAnswer()');
var self = this;
this.pc.createAnswer(
function (answer) {
if (isClosed.call(self)) {
return;
}
debug('createAnswer() | success');
if (successCallback) {
successCallback(answer);
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('createAnswer() | error:', error);
if (failureCallback) {
failureCallback(error);
}
},
options
);
};
RTCPeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
debug('setLocalDescription()');
var self = this;
this.pc.setLocalDescription(
description,
// success.
function () {
if (isClosed.call(self)) {
return;
}
debug('setLocalDescription() | success');
// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
runTimerGatheringTimeout();
if (successCallback) {
successCallback();
}
},
// failure
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('setLocalDescription() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
// Enable (again) ICE gathering.
this.ignoreIceGathering = false;
// Handle gatheringTimeout.
function runTimerGatheringTimeout() {
if (typeof self.options.gatheringTimeout !== 'number') {
return;
}
// If setLocalDescription was already called, it may happen that
// ICE gathering is not needed, so don't run this timer.
if (self.pc.iceGatheringState === 'complete') {
return;
}
debug('setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)',
self.options.gatheringTimeout);
self.timerGatheringTimeout = setTimeout(function () {
if (isClosed.call(self)) {
return;
}
debug('forced end of candidates after gatheringTimeout timeout');
// Clear gathering timers.
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({ candidate: null }, null);
}
}, self.options.gatheringTimeout);
}
};
RTCPeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
debug('setRemoteDescription()');
var self = this;
this.pc.setRemoteDescription(
description,
function () {
if (isClosed.call(self)) {
return;
}
debug('setRemoteDescription() | success');
if (successCallback) {
successCallback();
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('setRemoteDescription() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
};
RTCPeerConnection.prototype.updateIce = function (pcConfig) {
debug('updateIce() | pcConfig: %o', pcConfig);
// Update this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
this.pc.updateIce(this.pcConfig);
// Enable (again) ICE gathering.
this.ignoreIceGathering = false;
};
RTCPeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
debug('addIceCandidate() | candidate: %o', candidate);
var self = this;
this.pc.addIceCandidate(
candidate,
function () {
if (isClosed.call(self)) {
return;
}
debug('addIceCandidate() | success');
if (successCallback) {
successCallback();
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('addIceCandidate() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
};
RTCPeerConnection.prototype.getConfiguration = function () {
debug('getConfiguration()');
return this.pc.getConfiguration();
};
RTCPeerConnection.prototype.getLocalStreams = function () {
debug('getLocalStreams()');
return this.pc.getLocalStreams();
};
RTCPeerConnection.prototype.getRemoteStreams = function () {
debug('getRemoteStreams()');
return this.pc.getRemoteStreams();
};
RTCPeerConnection.prototype.getStreamById = function (streamId) {
debug('getStreamById() | streamId: %s', streamId);
return this.pc.getStreamById(streamId);
};
RTCPeerConnection.prototype.addStream = function (stream) {
debug('addStream() | stream: %s', stream);
this.pc.addStream(stream);
};
RTCPeerConnection.prototype.removeStream = function (stream) {
debug('removeStream() | stream: %o', stream);
this.pc.removeStream(stream);
};
RTCPeerConnection.prototype.close = function () {
debug('close()');
this.closed = true;
// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
this.pc.close();
};
RTCPeerConnection.prototype.createDataChannel = function () {
debug('createDataChannel()');
return this.pc.createDataChannel.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.createDTMFSender = function (track) {
debug('createDTMFSender()');
return this.pc.createDTMFSender(track);
};
RTCPeerConnection.prototype.getStats = function () {
debug('getStats()');
return this.pc.getStats.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.setIdentityProvider = function () {
debug('setIdentityProvider()');
return this.pc.setIdentityProvider.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.getIdentityAssertion = function () {
debug('getIdentityAssertion()');
return this.pc.getIdentityAssertion();
};
RTCPeerConnection.prototype.reset = function (pcConfig) {
debug('reset() | pcConfig: %o', pcConfig);
var pc = this.pc;
// Remove events in the old PC.
pc.onnegotiationneeded = null;
pc.onicecandidate = null;
pc.onaddstream = null;
pc.onremovestream = null;
pc.ondatachannel = null;
pc.onsignalingstatechange = null;
pc.oniceconnectionstatechange = null;
pc.onicegatheringstatechange = null;
pc.onidentityresult = null;
pc.onpeeridentity = null;
pc.onidpassertionerror = null;
pc.onidpvalidationerror = null;
// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
// Silently close the old PC.
debug('reset() | closing current peerConnection');
pc.close();
// Set this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
// Create a new PC.
setPeerConnection.call(this);
};
// Private Helpers.
function setConfigurationAndOptions(pcConfig) {
// Clone pcConfig.
this.pcConfig = merge(true, pcConfig);
// Fix pcConfig.
Adapter.fixPeerConnectionConfig(this.pcConfig);
this.options = {
iceTransportsRelay: (this.pcConfig.iceTransports === 'relay'),
iceTransportsNone: (this.pcConfig.iceTransports === 'none'),
gatheringTimeout: this.pcConfig.gatheringTimeout,
gatheringTimeoutAfterRelay: this.pcConfig.gatheringTimeoutAfterRelay
};
// Remove custom rtcninja.RTCPeerConnection options from pcConfig.
delete this.pcConfig.gatheringTimeout;
delete this.pcConfig.gatheringTimeoutAfterRelay;
debug('setConfigurationAndOptions | processed pcConfig: %o', this.pcConfig);
}
function isClosed() {
return ((this.closed) || (this.pc && this.pc.iceConnectionState === 'closed'));
}
function setEvents() {
var self = this,
pc = this.pc;
pc.onnegotiationneeded = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onnegotiationneeded()');
if (self.onnegotiationneeded) {
self.onnegotiationneeded(event);
}
};
pc.onicecandidate = function (event) {
var candidate, isRelay, newCandidate;
if (isClosed.call(self)) {
return;
}
if (self.ignoreIceGathering) {
return;
}
// Ignore any candidate (event the null one) if iceTransports:'none' is set.
if (self.options.iceTransportsNone) {
return;
}
candidate = event.candidate;
if (candidate) {
isRelay = C.REGEXP_RELAY_CANDIDATE.test(candidate.candidate);
// Ignore if just relay candidates are requested.
if (self.options.iceTransportsRelay && !isRelay) {
return;
}
// Handle gatheringTimeoutAfterRelay.
if (isRelay && !self.timerGatheringTimeoutAfterRelay &&
(typeof self.options.gatheringTimeoutAfterRelay === 'number')) {
debug('onicecandidate() | first relay candidate found, ending gathering in %d ms', self.options.gatheringTimeoutAfterRelay);
self.timerGatheringTimeoutAfterRelay = setTimeout(function () {
if (isClosed.call(self)) {
return;
}
debug('forced end of candidates after timeout');
// Clear gathering timers.
delete self.timerGatheringTimeoutAfterRelay;
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({candidate: null}, null);
}
}, self.options.gatheringTimeoutAfterRelay);
}
newCandidate = new Adapter.RTCIceCandidate({
sdpMid: candidate.sdpMid,
sdpMLineIndex: candidate.sdpMLineIndex,
candidate: candidate.candidate
});
// Force correct candidate syntax (just check it once).
if (VAR.normalizeCandidate === null) {
if (C.REGEXP_NORMALIZED_CANDIDATE.test(candidate.candidate)) {
VAR.normalizeCandidate = false;
} else {
debug('onicecandidate() | normalizing ICE candidates syntax (remove "a=" and "\\r\\n")');
VAR.normalizeCandidate = true;
}
}
if (VAR.normalizeCandidate) {
newCandidate.candidate = candidate.candidate.replace(C.REGEXP_FIX_CANDIDATE, '');
}
debug(
'onicecandidate() | m%d(%s) %s',
newCandidate.sdpMLineIndex,
newCandidate.sdpMid || 'no mid', newCandidate.candidate);
if (self.onicecandidate) {
self.onicecandidate(event, newCandidate);
}
// Null candidate (end of candidates).
} else {
debug('onicecandidate() | end of candidates');
// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
if (self.onicecandidate) {
self.onicecandidate(event, null);
}
}
};
pc.onaddstream = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onaddstream() | stream: %o', event.stream);
if (self.onaddstream) {
self.onaddstream(event, event.stream);
}
};
pc.onremovestream = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onremovestream() | stream: %o', event.stream);
if (self.onremovestream) {
self.onremovestream(event, event.stream);
}
};
pc.ondatachannel = function (event) {
if (isClosed.call(self)) {
return;
}
debug('ondatachannel() | datachannel: %o', event.channel);
if (self.ondatachannel) {
self.ondatachannel(event, event.channel);
}
};
pc.onsignalingstatechange = function (event) {
if (pc.signalingState === self.ourSignalingState) {
return;
}
debug('onsignalingstatechange() | signalingState: %s', pc.signalingState);
self.ourSignalingState = pc.signalingState;
if (self.onsignalingstatechange) {
self.onsignalingstatechange(event, pc.signalingState);
}
};
pc.oniceconnectionstatechange = function (event) {
if (pc.iceConnectionState === self.ourIceConnectionState) {
return;
}
debug('oniceconnectionstatechange() | iceConnectionState: %s', pc.iceConnectionState);
self.ourIceConnectionState = pc.iceConnectionState;
if (self.oniceconnectionstatechange) {
self.oniceconnectionstatechange(event, pc.iceConnectionState);
}
};
pc.onicegatheringstatechange = function (event) {
if (isClosed.call(self)) {
return;
}
if (pc.iceGatheringState === self.ourIceGatheringState) {
return;
}
debug('onicegatheringstatechange() | iceGatheringState: %s', pc.iceGatheringState);
self.ourIceGatheringState = pc.iceGatheringState;
if (self.onicegatheringstatechange) {
self.onicegatheringstatechange(event, pc.iceGatheringState);
}
};
pc.onidentityresult = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidentityresult()');
if (self.onidentityresult) {
self.onidentityresult(event);
}
};
pc.onpeeridentity = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onpeeridentity()');
if (self.onpeeridentity) {
self.onpeeridentity(event);
}
};
pc.onidpassertionerror = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidpassertionerror()');
if (self.onidpassertionerror) {
self.onidpassertionerror(event);
}
};
pc.onidpvalidationerror = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidpvalidationerror()');
if (self.onidpvalidationerror) {
self.onidpvalidationerror(event);
}
};
}
function setPeerConnection() {
// Create a RTCPeerConnection.
if (!this.pcConstraints) {
this.pc = new Adapter.RTCPeerConnection(this.pcConfig);
} else {
// NOTE: Deprecated.
this.pc = new Adapter.RTCPeerConnection(this.pcConfig, this.pcConstraints);
}
// Set RTC events.
setEvents.call(this);
}
function getLocalDescription() {
var pc = this.pc,
options = this.options,
sdp = null;
if (!pc.localDescription) {
this.ourLocalDescription = null;
return null;
}
// Mangle the SDP string.
if (options.iceTransportsRelay) {
sdp = pc.localDescription.sdp.replace(C.REGEXP_SDP_NON_RELAY_CANDIDATES, '');
} else if (options.iceTransportsNone) {
sdp = pc.localDescription.sdp.replace(C.REGEXP_SDP_CANDIDATES, '');
}
this.ourLocalDescription = new Adapter.RTCSessionDescription({
type: pc.localDescription.type,
sdp: sdp || pc.localDescription.sdp
});
return this.ourLocalDescription;
}
function setProperties() {
var self = this;
Object.defineProperties(this, {
peerConnection: {
get: function () {
return self.pc;
}
},
signalingState: {
get: function () {
return self.pc.signalingState;
}
},
iceConnectionState: {
get: function () {
return self.pc.iceConnectionState;
}
},
iceGatheringState: {
get: function () {
return self.pc.iceGatheringState;
}
},
localDescription: {
get: function () {
return getLocalDescription.call(self);
}
},
remoteDescription: {
get: function () {
return self.pc.remoteDescription;
}
},
peerIdentity: {
get: function () {
return self.pc.peerIdentity;
}
}
});
}
},{"./Adapter":1,"debug":6,"merge":9}],3:[function(require,module,exports){
'use strict';
module.exports = rtcninja;
// Dependencies.
var browser = require('bowser').browser,
debug = require('debug')('rtcninja'),
debugerror = require('debug')('rtcninja:ERROR'),
version = require('./version'),
Adapter = require('./Adapter'),
RTCPeerConnection = require('./RTCPeerConnection'),
// Internal vars.
called = false;
debugerror.log = console.warn.bind(console);
debug('version %s', version);
debug('detected browser: %s %s [mobile:%s, tablet:%s, android:%s, ios:%s]',
browser.name, browser.version, !!browser.mobile, !!browser.tablet,
!!browser.android, !!browser.ios);
// Constructor.
function rtcninja(options) {
// Load adapter
var iface = Adapter(options || {}); // jshint ignore:line
called = true;
// Expose RTCPeerConnection class.
rtcninja.RTCPeerConnection = RTCPeerConnection;
// Expose WebRTC API and utils.
rtcninja.getUserMedia = iface.getUserMedia;
rtcninja.RTCSessionDescription = iface.RTCSessionDescription;
rtcninja.RTCIceCandidate = iface.RTCIceCandidate;
rtcninja.MediaStreamTrack = iface.MediaStreamTrack;
rtcninja.getMediaDevices = iface.getMediaDevices;
rtcninja.attachMediaStream = iface.attachMediaStream;
rtcninja.closeMediaStream = iface.closeMediaStream;
rtcninja.canRenegotiate = iface.canRenegotiate;
// Log WebRTC support.
if (iface.hasWebRTC()) {
debug('WebRTC supported');
return true;
} else {
debugerror('WebRTC not supported');
return false;
}
}
// Public API.
// If called without calling rtcninja(), call it.
rtcninja.hasWebRTC = function () {
if (!called) {
rtcninja();
}
return Adapter.hasWebRTC();
};
// Expose version property.
Object.defineProperty(rtcninja, 'version', {
get: function () {
return version;
}
});
// Expose called property.
Object.defineProperty(rtcninja, 'called', {
get: function () {
return called;
}
});
// Exposing stuff.
rtcninja.debug = require('debug');
rtcninja.browser = browser;
},{"./Adapter":1,"./RTCPeerConnection":2,"./version":4,"bowser":5,"debug":6}],4:[function(require,module,exports){
'use strict';
// Expose the 'version' field of package.json.
module.exports = require('../package.json').version;
},{"../package.json":10}],5:[function(require,module,exports){
/*!
* Bowser - a browser detector
* https://github.com/ded/bowser
* MIT License | (c) Dustin Diaz 2014
*/
!function (name, definition) {
if (typeof module != 'undefined' && module.exports) module.exports['browser'] = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else this[name] = definition()
}('bowser', function () {
/**
* See useragents.js for examples of navigator.userAgent
*/
var t = true
function detect(ua) {
function getFirstMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[1]) || '';
}
function getSecondMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[2]) || '';
}
var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
, likeAndroid = /like android/i.test(ua)
, android = !likeAndroid && /android/i.test(ua)
, edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i)
, versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
, tablet = /tablet/i.test(ua)
, mobile = !tablet && /[^-]mobi/i.test(ua)
, result
if (/opera|opr/i.test(ua)) {
result = {
name: 'Opera'
, opera: t
, version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
}
}
else if (/windows phone/i.test(ua)) {
result = {
name: 'Windows Phone'
, windowsphone: t
}
if (edgeVersion) {
result.msedge = t
result.version = edgeVersion
}
else {
result.msie = t
result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
}
}
else if (/msie|trident/i.test(ua)) {
result = {
name: 'Internet Explorer'
, msie: t
, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
}
}
else if (/chrome.+? edge/i.test(ua)) {
result = {
name: 'Microsoft Edge'
, msedge: t
, version: edgeVersion
}
}
else if (/chrome|crios|crmo/i.test(ua)) {
result = {
name: 'Chrome'
, chrome: t
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
}
}
else if (iosdevice) {
result = {
name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
}
// WTF: version is not part of user agent in web apps
if (versionIdentifier) {
result.version = versionIdentifier
}
}
else if (/sailfish/i.test(ua)) {
result = {
name: 'Sailfish'
, sailfish: t
, version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
}
}
else if (/seamonkey\//i.test(ua)) {
result = {
name: 'SeaMonkey'
, seamonkey: t
, version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
}
}
else if (/firefox|iceweasel/i.test(ua)) {
result = {
name: 'Firefox'
, firefox: t
, version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
}
if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
result.firefoxos = t
}
}
else if (/silk/i.test(ua)) {
result = {
name: 'Amazon Silk'
, silk: t
, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
}
}
else if (android) {
result = {
name: 'Android'
, version: versionIdentifier
}
}
else if (/phantom/i.test(ua)) {
result = {
name: 'PhantomJS'
, phantom: t
, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
}
}
else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
result = {
name: 'BlackBerry'
, blackberry: t
, version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
}
}
else if (/(web|hpw)os/i.test(ua)) {
result = {
name: 'WebOS'
, webos: t
, version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
};
/touchpad\//i.test(ua) && (result.touchpad = t)
}
else if (/bada/i.test(ua)) {
result = {
name: 'Bada'
, bada: t
, version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
};
}
else if (/tizen/i.test(ua)) {
result = {
name: 'Tizen'
, tizen: t
, version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
};
}
else if (/safari/i.test(ua)) {
result = {
name: 'Safari'
, safari: t
, version: versionIdentifier
}
}
else {
result = {
name: getFirstMatch(/^(.*)\/(.*) /),
version: getSecondMatch(/^(.*)\/(.*) /)
};
}
// set webkit or gecko flag for browsers based on these engines
if (!result.msedge && /(apple)?webkit/i.test(ua)) {
result.name = result.name || "Webkit"
result.webkit = t
if (!result.version && versionIdentifier) {
result.version = versionIdentifier
}
} else if (!result.opera && /gecko\//i.test(ua)) {
result.name = result.name || "Gecko"
result.gecko = t
result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
}
// set OS flags for platforms that have multiple browsers
if (!result.msedge && (android || result.silk)) {
result.android = t
} else if (iosdevice) {
result[iosdevice] = t
result.ios = t
}
// OS version extraction
var osVersion = '';
if (result.windowsphone) {
osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
} else if (iosdevice) {
osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
osVersion = osVersion.replace(/[_\s]/g, '.');
} else if (android) {
osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
} else if (result.webos) {
osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
} else if (result.blackberry) {
osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
} else if (result.bada) {
osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
} else if (result.tizen) {
osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
}
if (osVersion) {
result.osversion = osVersion;
}
// device type extraction
var osMajorVersion = osVersion.split('.')[0];
if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) {
result.tablet = t
} else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) {
result.mobile = t
}
// Graded Browser Support
// http://developer.yahoo.com/yui/articles/gbs
if (result.msedge ||
(result.msie && result.version >= 10) ||
(result.chrome && result.version >= 20) ||
(result.firefox && result.version >= 20.0) ||
(result.safari && result.version >= 6) ||
(result.opera && result.version >= 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
(result.blackberry && result.version >= 10.1)
) {
result.a = t;
}
else if ((result.msie && result.version < 10) ||
(result.chrome && result.version < 20) ||
(result.firefox && result.version < 20.0) ||
(result.safari && result.version < 6) ||
(result.opera && result.version < 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] < 6)
) {
result.c = t
} else result.x = t
return result
}
var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
bowser.test = function (browserList) {
for (var i = 0; i < browserList.length; ++i) {
var browserItem = browserList[i];
if (typeof browserItem=== 'string') {
if (browserItem in bowser) {
return true;
}
}
}
return false;
}
/*
* Set our detect method to the main bowser object so we can
* reuse it to test other user agents.
* This is needed to implement future tests.
*/
bowser._detect = detect;
return bowser
});
},{}],6:[function(require,module,exports){
/**
* This is the web browser implementation of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = require('./debug');
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = 'undefined' != typeof chrome
&& 'undefined' != typeof chrome.storage
? chrome.storage.local
: localstorage();
/**
* Colors.
*/
exports.colors = [
'lightseagreen',
'forestgreen',
'goldenrod',
'dodgerblue',
'darkorchid',
'crimson'
];
/**
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
function useColors() {
// is webkit? http://stackoverflow.com/a/16459606/376773
return ('WebkitAppearance' in document.documentElement.style) ||
// is firebug? http://stackoverflow.com/a/398120/376773
(window.console && (console.firebug || (console.exception && console.table))) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
}
/**
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
*/
exports.formatters.j = function(v) {
return JSON.stringify(v);
};
/**
* Colorize log arguments if enabled.
*
* @api public
*/
function formatArgs() {
var args = arguments;
var useColors = this.useColors;
args[0] = (useColors ? '%c' : '')
+ this.namespace
+ (useColors ? ' %c' : ' ')
+ args[0]
+ (useColors ? '%c ' : ' ')
+ '+' + exports.humanize(this.diff);
if (!useColors) return args;
var c = 'color: ' + this.color;
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
var index = 0;
var lastC = 0;
args[0].replace(/%[a-z%]/g, function(match) {
if ('%%' === match) return;
index++;
if ('%c' === match) {
// we only are interested in the *last* %c
// (the user may have provided their own)
lastC = index;
}
});
args.splice(lastC, 0, c);
return args;
}
/**
* Invokes `console.log()` when available.
* No-op when `console.log` is not a "function".
*
* @api public
*/
function log() {
// this hackery is required for IE8/9, where
// the `console.log` function doesn't have 'apply'
return 'object' === typeof console
&& console.log
&& Function.prototype.apply.call(console.log, console, arguments);
}
/**
* Save `namespaces`.
*
* @param {String} namespaces
* @api private
*/
function save(namespaces) {
try {
if (null == namespaces) {
exports.storage.removeItem('debug');
} else {
exports.storage.debug = namespaces;
}
} catch(e) {}
}
/**
* Load `namespaces`.
*
* @return {String} returns the previously persisted debug modes
* @api private
*/
function load() {
var r;
try {
r = exports.storage.debug;
} catch(e) {}
return r;
}
/**
* Enable namespaces listed in `localStorage.debug` initially.
*/
exports.enable(load());
/**
* Localstorage attempts to return the localstorage.
*
* This is necessary because safari throws
* when a user disables cookies/localstorage
* and you attempt to access it.
*
* @return {LocalStorage}
* @api private
*/
function localstorage(){
try {
return window.localStorage;
} catch (e) {}
}
},{"./debug":7}],7:[function(require,module,exports){
/**
* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = debug;
exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
exports.enabled = enabled;
exports.humanize = require('ms');
/**
* The currently active debug mode names, and names to skip.
*/
exports.names = [];
exports.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lowercased letter, i.e. "n".
*/
exports.formatters = {};
/**
* Previously assigned color.
*/
var prevColor = 0;
/**
* Previous log timestamp.
*/
var prevTime;
/**
* Select a color.
*
* @return {Number}
* @api private
*/
function selectColor() {
return exports.colors[prevColor++ % exports.colors.length];
}
/**
* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/
function debug(namespace) {
// define the `disabled` version
function disabled() {
}
disabled.enabled = false;
// define the `enabled` version
function enabled() {
var self = enabled;
// set `diff` timestamp
var curr = +new Date();
var ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
// add the `color` if not set
if (null == self.useColors) self.useColors = exports.useColors();
if (null == self.color && self.useColors) self.color = selectColor();
var args = Array.prototype.slice.call(arguments);
args[0] = exports.coerce(args[0]);
if ('string' !== typeof args[0]) {
// anything else let's inspect with %o
args = ['%o'].concat(args);
}
// apply any `formatters` transformations
var index = 0;
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
// if we encounter an escaped % then don't increase the array index
if (match === '%%') return match;
index++;
var formatter = exports.formatters[format];
if ('function' === typeof formatter) {
var val = args[index];
match = formatter.call(self, val);
// now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
if ('function' === typeof exports.formatArgs) {
args = exports.formatArgs.apply(self, args);
}
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
var fn = exports.enabled(namespace) ? enabled : disabled;
fn.namespace = namespace;
return fn;
}
/**
* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/
function enable(namespaces) {
exports.save(namespaces);
var split = (namespaces || '').split(/[\s,]+/);
var len = split.length;
for (var i = 0; i < len; i++) {
if (!split[i]) continue; // ignore empty strings
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
exports.names.push(new RegExp('^' + namespaces + '$'));
}
}
}
/**
* Disable debug output.
*
* @api public
*/
function disable() {
exports.enable('');
}
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
function enabled(name) {
var i, len;
for (i = 0, len = exports.skips.length; i < len; i++) {
if (exports.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = exports.names.length; i < len; i++) {
if (exports.names[i].test(name)) {
return true;
}
}
return false;
}
/**
* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/
function coerce(val) {
if (val instanceof Error) return val.stack || val.message;
return val;
}
},{"ms":8}],8:[function(require,module,exports){
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} options
* @return {String|Number}
* @api public
*/
module.exports = function(val, options){
options = options || {};
if ('string' == typeof val) return parse(val);
return options.long
? long(val)
: short(val);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = '' + str;
if (str.length > 10000) return;
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
if (!match) return;
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function short(ms) {
if (ms >= d) return Math.round(ms / d) + 'd';
if (ms >= h) return Math.round(ms / h) + 'h';
if (ms >= m) return Math.round(ms / m) + 'm';
if (ms >= s) return Math.round(ms / s) + 's';
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function long(ms) {
return plural(ms, d, 'day')
|| plural(ms, h, 'hour')
|| plural(ms, m, 'minute')
|| plural(ms, s, 'second')
|| ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, n, name) {
if (ms < n) return;
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
return Math.ceil(ms / n) + ' ' + name + 's';
}
},{}],9:[function(require,module,exports){
/*!
* @name JavaScript/NodeJS Merge v1.2.0
* @author yeikos
* @repository https://github.com/yeikos/js.merge
* Copyright 2014 yeikos - MIT license
* https://raw.github.com/yeikos/js.merge/master/LICENSE
*/
;(function(isNode) {
/**
* Merge one or more objects
* @param bool? clone
* @param mixed,... arguments
* @return object
*/
var Public = function(clone) {
return merge(clone === true, false, arguments);
}, publicName = 'merge';
/**
* Merge two or more objects recursively
* @param bool? clone
* @param mixed,... arguments
* @return object
*/
Public.recursive = function(clone) {
return merge(clone === true, true, arguments);
};
/**
* Clone the input removing any reference
* @param mixed input
* @return mixed
*/
Public.clone = function(input) {
var output = input,
type = typeOf(input),
index, size;
if (type === 'array') {
output = [];
size = input.length;
for (index=0;index (http://eface2face.com)",
"contributors": [
"Jesús Pérez "
],
"license": "MIT",
"main": "lib/rtcninja.js",
"homepage": "https://github.com/eface2face/rtcninja.js",
"repository": {
"type": "git",
"url": "https://github.com/eface2face/rtcninja.js.git"
},
"keywords": [
"webrtc"
],
"engines": {
"node": ">=0.10.32"
},
"dependencies": {
"bowser": "^0.7.3",
"debug": "^2.2.0",
"merge": "^1.2.0"
},
"devDependencies": {
"browserify": "^10.2.3",
"gulp": "git+https://github.com/gulpjs/gulp.git#4.0",
"gulp-expect-file": "0.0.7",
"gulp-filelog": "^0.4.1",
"gulp-header": "^1.2.2",
"gulp-jscs": "^1.6.0",
"gulp-jscs-stylish": "^1.1.0",
"gulp-jshint": "^1.11.0",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.2.0",
"jshint-stylish": "^1.0.2",
"retire": "^1.1.0",
"shelljs": "^0.5.0",
"vinyl-source-stream": "^1.1.0"
}
}
},{}]},{},[3])(3)
}); rtcninja.js-0.6.2/dist/rtcninja-0.6.2.min.js 0000664 0000000 0000000 00000061354 12544264443 0020317 0 ustar 00root root 0000000 0000000 /*
* rtcninja.js v0.6.2
* WebRTC API wrapper to deal with different browsers
* Copyright 2015 Iñaki Baz Castillo (http://eface2face.com)
* License MIT
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.rtcninja=e()}}(function(){var e;return function t(e,n,i){function o(a,s){if(!n[a]){if(!e[a]){var c="function"==typeof require&&require;if(!s&&c)return c(a,!0);if(r)return r(a,!0);var d=new Error("Cannot find module '"+a+"'");throw d.code="MODULE_NOT_FOUND",d}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,i)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a=32||a.android&&a.chrome&&v>=39||b&&a.opera&&v>=27||a.android&&a.opera&&v>=24||a.android&&a.webkit&&!a.chrome&&v>=37||r.webkitGetUserMedia&&o.webkitRTCPeerConnection)C=!0,d=r.webkitGetUserMedia.bind(r),l=o.webkitRTCPeerConnection,u=o.RTCSessionDescription,p=o.RTCIceCandidate,g=o.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=function(e,t){return e.src=URL.createObjectURL(t),e},h=!0,y=!1;else if(b&&a.firefox&&v>=22||a.android&&a.firefox&&v>=33||r.mozGetUserMedia&&o.mozRTCPeerConnection)C=!0,d=r.mozGetUserMedia.bind(r),l=o.mozRTCPeerConnection,u=o.mozRTCSessionDescription,p=o.mozRTCIceCandidate,g=o.MediaStreamTrack,m=function(e,t){return e.src=URL.createObjectURL(t),e},h=!1,y=!1;else if(e.plugin&&"function"==typeof e.plugin.isRequired&&e.plugin.isRequired()&&"function"==typeof e.plugin.isInstalled&&e.plugin.isInstalled()){var n=e.plugin["interface"];C=!0,d=n.getUserMedia,l=n.RTCPeerConnection,u=n.RTCSessionDescription,p=n.RTCIceCandidate,g=n.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=n.attachMediaStream,h=n.canRenegotiate,y=!0}else r.getUserMedia&&o.RTCPeerConnection&&(C=!0,d=r.getUserMedia.bind(r),l=o.RTCPeerConnection,u=o.RTCSessionDescription,p=o.RTCIceCandidate,g=o.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=o.attachMediaStream||function(e,t){return e.src=URL.createObjectURL(t),e},h=!1,y=!1);return i.hasWebRTC=function(){return C},i.getUserMedia=d?function(e,t,n){s("getUserMedia() | constraints: %o",e);try{d(e,function(e){s("getUserMedia() | success"),t&&t(e)},function(e){s("getUserMedia() | error:",e),n&&n(e)})}catch(i){c("getUserMedia() | error:",i),n&&n(i)}}:function(e,n,i){c("getUserMedia() | WebRTC not supported"),i?i(new Error("rtcninja: WebRTC not supported, missing getUserMedia [browser: "+a.name+" "+a.version+"]")):t("getUserMedia")},i.RTCPeerConnection=l||t("RTCPeerConnection"),i.RTCSessionDescription=u||t("RTCSessionDescription"),i.RTCIceCandidate=p||t("RTCIceCandidate"),i.MediaStreamTrack=g||t("MediaStreamTrack"),i.getMediaDevices=f,i.attachMediaStream=m||t("attachMediaStream"),i.canRenegotiate=h,i.closeMediaStream=function(e){if(e)if(g&&g.prototype&&g.prototype.stop){s("closeMediaStream() | calling stop() on all the MediaStreamTrack");var t,n,i;if(e.getTracks)for(t=e.getTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop();else{for(t=e.getAudioTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop();for(t=e.getVideoTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop()}}else"function"==typeof e.stop&&(s("closeMediaStream() | calling stop() on the MediaStream"),e.stop())},i.fixPeerConnectionConfig=function(e){var t,n,i,o,r;for(Array.isArray(e.iceServers)||(e.iceServers=[]),t=0,n=e.iceServers.length;n>t;t+=1)i=e.iceServers[t],o=i.hasOwnProperty("urls"),r=i.hasOwnProperty("url"),"object"==typeof i&&(o&&!r?i.url=Array.isArray(i.urls)?i.urls[0]:i.urls:!o&&r&&(i.urls=Array.isArray(i.url)?i.url.slice():i.url),r&&Array.isArray(i.url)&&(i.url=i.url[0]))},i.fixRTCOfferOptions=function(e){e=e||{},y?(e.offerToReceiveAudio&&(e.mandatory=e.mandatory||{},e.mandatory.OfferToReceiveAudio=!0),e.offerToReceiveVideo&&(e.mandatory=e.mandatory||{},e.mandatory.OfferToReceiveVideo=!0)):(e.mandatory&&e.mandatory.OfferToReceiveAudio&&(e.offerToReceiveAudio=1),e.mandatory&&e.mandatory.OfferToReceiveVideo&&(e.offerToReceiveVideo=1),delete e.mandatory)},i}t.exports=i;var o,r,a=e("bowser").browser,s=e("debug")("rtcninja:Adapter"),c=e("debug")("rtcninja:ERROR:Adapter"),d=null,l=null,u=null,p=null,g=null,f=null,m=null,h=!1,y=!1,v=Number(a.version)||0,b=!(a.mobile&&a.tablet),C=!1;c.log=console.warn.bind(console),o=n.window||n,r=o.navigator||{}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{bowser:5,debug:6}],2:[function(e,t,n){"use strict";function i(e,t){u("new | pcConfig: %o",e),o.call(this,e),this.pcConstraints=t,this.ourLocalDescription=null,this.ourSignalingState=null,this.ourIceConnectionState=null,this.ourIceGatheringState=null,this.timerGatheringTimeout=null,this.timerGatheringTimeoutAfterRelay=null,this.ignoreIceGathering=!1,this.closed=!1,s.call(this),d.call(this)}function o(e){this.pcConfig=l(!0,e),g.fixPeerConnectionConfig(this.pcConfig),this.options={iceTransportsRelay:"relay"===this.pcConfig.iceTransports,iceTransportsNone:"none"===this.pcConfig.iceTransports,gatheringTimeout:this.pcConfig.gatheringTimeout,gatheringTimeoutAfterRelay:this.pcConfig.gatheringTimeoutAfterRelay},delete this.pcConfig.gatheringTimeout,delete this.pcConfig.gatheringTimeoutAfterRelay,u("setConfigurationAndOptions | processed pcConfig: %o",this.pcConfig)}function r(){return this.closed||this.pc&&"closed"===this.pc.iceConnectionState}function a(){var e=this,t=this.pc;t.onnegotiationneeded=function(t){r.call(e)||(u("onnegotiationneeded()"),e.onnegotiationneeded&&e.onnegotiationneeded(t))},t.onicecandidate=function(t){var n,i,o;if(!r.call(e)&&!e.ignoreIceGathering&&!e.options.iceTransportsNone)if(n=t.candidate){if(i=f.REGEXP_RELAY_CANDIDATE.test(n.candidate),e.options.iceTransportsRelay&&!i)return;i&&!e.timerGatheringTimeoutAfterRelay&&"number"==typeof e.options.gatheringTimeoutAfterRelay&&(u("onicecandidate() | first relay candidate found, ending gathering in %d ms",e.options.gatheringTimeoutAfterRelay),e.timerGatheringTimeoutAfterRelay=setTimeout(function(){r.call(e)||(u("forced end of candidates after timeout"),delete e.timerGatheringTimeoutAfterRelay,clearTimeout(e.timerGatheringTimeout),delete e.timerGatheringTimeout,e.ignoreIceGathering=!0,e.onicecandidate&&e.onicecandidate({candidate:null},null))},e.options.gatheringTimeoutAfterRelay)),o=new g.RTCIceCandidate({sdpMid:n.sdpMid,sdpMLineIndex:n.sdpMLineIndex,candidate:n.candidate}),null===m.normalizeCandidate&&(f.REGEXP_NORMALIZED_CANDIDATE.test(n.candidate)?m.normalizeCandidate=!1:(u('onicecandidate() | normalizing ICE candidates syntax (remove "a=" and "\\r\\n")'),m.normalizeCandidate=!0)),m.normalizeCandidate&&(o.candidate=n.candidate.replace(f.REGEXP_FIX_CANDIDATE,"")),u("onicecandidate() | m%d(%s) %s",o.sdpMLineIndex,o.sdpMid||"no mid",o.candidate),e.onicecandidate&&e.onicecandidate(t,o)}else u("onicecandidate() | end of candidates"),clearTimeout(e.timerGatheringTimeout),delete e.timerGatheringTimeout,clearTimeout(e.timerGatheringTimeoutAfterRelay),delete e.timerGatheringTimeoutAfterRelay,e.onicecandidate&&e.onicecandidate(t,null)},t.onaddstream=function(t){r.call(e)||(u("onaddstream() | stream: %o",t.stream),e.onaddstream&&e.onaddstream(t,t.stream))},t.onremovestream=function(t){r.call(e)||(u("onremovestream() | stream: %o",t.stream),e.onremovestream&&e.onremovestream(t,t.stream))},t.ondatachannel=function(t){r.call(e)||(u("ondatachannel() | datachannel: %o",t.channel),e.ondatachannel&&e.ondatachannel(t,t.channel))},t.onsignalingstatechange=function(n){t.signalingState!==e.ourSignalingState&&(u("onsignalingstatechange() | signalingState: %s",t.signalingState),e.ourSignalingState=t.signalingState,e.onsignalingstatechange&&e.onsignalingstatechange(n,t.signalingState))},t.oniceconnectionstatechange=function(n){t.iceConnectionState!==e.ourIceConnectionState&&(u("oniceconnectionstatechange() | iceConnectionState: %s",t.iceConnectionState),e.ourIceConnectionState=t.iceConnectionState,e.oniceconnectionstatechange&&e.oniceconnectionstatechange(n,t.iceConnectionState))},t.onicegatheringstatechange=function(n){r.call(e)||t.iceGatheringState!==e.ourIceGatheringState&&(u("onicegatheringstatechange() | iceGatheringState: %s",t.iceGatheringState),e.ourIceGatheringState=t.iceGatheringState,e.onicegatheringstatechange&&e.onicegatheringstatechange(n,t.iceGatheringState))},t.onidentityresult=function(t){r.call(e)||(u("onidentityresult()"),e.onidentityresult&&e.onidentityresult(t))},t.onpeeridentity=function(t){r.call(e)||(u("onpeeridentity()"),e.onpeeridentity&&e.onpeeridentity(t))},t.onidpassertionerror=function(t){r.call(e)||(u("onidpassertionerror()"),e.onidpassertionerror&&e.onidpassertionerror(t))},t.onidpvalidationerror=function(t){r.call(e)||(u("onidpvalidationerror()"),e.onidpvalidationerror&&e.onidpvalidationerror(t))}}function s(){this.pc=this.pcConstraints?new g.RTCPeerConnection(this.pcConfig,this.pcConstraints):new g.RTCPeerConnection(this.pcConfig),a.call(this)}function c(){var e=this.pc,t=this.options,n=null;return e.localDescription?(t.iceTransportsRelay?n=e.localDescription.sdp.replace(f.REGEXP_SDP_NON_RELAY_CANDIDATES,""):t.iceTransportsNone&&(n=e.localDescription.sdp.replace(f.REGEXP_SDP_CANDIDATES,"")),this.ourLocalDescription=new g.RTCSessionDescription({type:e.localDescription.type,sdp:n||e.localDescription.sdp}),this.ourLocalDescription):(this.ourLocalDescription=null,null)}function d(){var e=this;Object.defineProperties(this,{peerConnection:{get:function(){return e.pc}},signalingState:{get:function(){return e.pc.signalingState}},iceConnectionState:{get:function(){return e.pc.iceConnectionState}},iceGatheringState:{get:function(){return e.pc.iceGatheringState}},localDescription:{get:function(){return c.call(e)}},remoteDescription:{get:function(){return e.pc.remoteDescription}},peerIdentity:{get:function(){return e.pc.peerIdentity}}})}t.exports=i;var l=e("merge"),u=e("debug")("rtcninja:RTCPeerConnection"),p=e("debug")("rtcninja:ERROR:RTCPeerConnection"),g=e("./Adapter"),f={REGEXP_NORMALIZED_CANDIDATE:new RegExp(/^candidate:/i),REGEXP_FIX_CANDIDATE:new RegExp(/(^a=|\r|\n)/gi),REGEXP_RELAY_CANDIDATE:new RegExp(/ relay /i),REGEXP_SDP_CANDIDATES:new RegExp(/^a=candidate:.*\r\n/gim),REGEXP_SDP_NON_RELAY_CANDIDATES:new RegExp(/^a=candidate:(.(?!relay ))*\r\n/gim)},m={normalizeCandidate:null};p.log=console.warn.bind(console),i.prototype.createOffer=function(e,t,n){u("createOffer()");var i=this;g.fixRTCOfferOptions(n),this.pc.createOffer(function(t){r.call(i)||(u("createOffer() | success"),e&&e(t))},function(e){r.call(i)||(p("createOffer() | error:",e),t&&t(e))},n)},i.prototype.createAnswer=function(e,t,n){u("createAnswer()");var i=this;this.pc.createAnswer(function(t){r.call(i)||(u("createAnswer() | success"),e&&e(t))},function(e){r.call(i)||(p("createAnswer() | error:",e),t&&t(e))},n)},i.prototype.setLocalDescription=function(e,t,n){function i(){"number"==typeof o.options.gatheringTimeout&&"complete"!==o.pc.iceGatheringState&&(u("setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)",o.options.gatheringTimeout),o.timerGatheringTimeout=setTimeout(function(){r.call(o)||(u("forced end of candidates after gatheringTimeout timeout"),delete o.timerGatheringTimeout,clearTimeout(o.timerGatheringTimeoutAfterRelay),delete o.timerGatheringTimeoutAfterRelay,o.ignoreIceGathering=!0,o.onicecandidate&&o.onicecandidate({candidate:null},null))},o.options.gatheringTimeout))}u("setLocalDescription()");var o=this;this.pc.setLocalDescription(e,function(){r.call(o)||(u("setLocalDescription() | success"),clearTimeout(o.timerGatheringTimeout),delete o.timerGatheringTimeout,clearTimeout(o.timerGatheringTimeoutAfterRelay),delete o.timerGatheringTimeoutAfterRelay,i(),t&&t())},function(e){r.call(o)||(p("setLocalDescription() | error:",e),n&&n(e))}),this.ignoreIceGathering=!1},i.prototype.setRemoteDescription=function(e,t,n){u("setRemoteDescription()");var i=this;this.pc.setRemoteDescription(e,function(){r.call(i)||(u("setRemoteDescription() | success"),t&&t())},function(e){r.call(i)||(p("setRemoteDescription() | error:",e),n&&n(e))})},i.prototype.updateIce=function(e){u("updateIce() | pcConfig: %o",e),o.call(this,e),this.pc.updateIce(this.pcConfig),this.ignoreIceGathering=!1},i.prototype.addIceCandidate=function(e,t,n){u("addIceCandidate() | candidate: %o",e);var i=this;this.pc.addIceCandidate(e,function(){r.call(i)||(u("addIceCandidate() | success"),t&&t())},function(e){r.call(i)||(p("addIceCandidate() | error:",e),n&&n(e))})},i.prototype.getConfiguration=function(){return u("getConfiguration()"),this.pc.getConfiguration()},i.prototype.getLocalStreams=function(){return u("getLocalStreams()"),this.pc.getLocalStreams()},i.prototype.getRemoteStreams=function(){return u("getRemoteStreams()"),this.pc.getRemoteStreams()},i.prototype.getStreamById=function(e){return u("getStreamById() | streamId: %s",e),this.pc.getStreamById(e)},i.prototype.addStream=function(e){u("addStream() | stream: %s",e),this.pc.addStream(e)},i.prototype.removeStream=function(e){u("removeStream() | stream: %o",e),this.pc.removeStream(e)},i.prototype.close=function(){u("close()"),this.closed=!0,clearTimeout(this.timerGatheringTimeout),delete this.timerGatheringTimeout,clearTimeout(this.timerGatheringTimeoutAfterRelay),delete this.timerGatheringTimeoutAfterRelay,this.pc.close()},i.prototype.createDataChannel=function(){return u("createDataChannel()"),this.pc.createDataChannel.apply(this.pc,arguments)},i.prototype.createDTMFSender=function(e){return u("createDTMFSender()"),this.pc.createDTMFSender(e)},i.prototype.getStats=function(){return u("getStats()"),this.pc.getStats.apply(this.pc,arguments)},i.prototype.setIdentityProvider=function(){return u("setIdentityProvider()"),this.pc.setIdentityProvider.apply(this.pc,arguments)},i.prototype.getIdentityAssertion=function(){return u("getIdentityAssertion()"),this.pc.getIdentityAssertion()},i.prototype.reset=function(e){u("reset() | pcConfig: %o",e);var t=this.pc;t.onnegotiationneeded=null,t.onicecandidate=null,t.onaddstream=null,t.onremovestream=null,t.ondatachannel=null,t.onsignalingstatechange=null,t.oniceconnectionstatechange=null,t.onicegatheringstatechange=null,t.onidentityresult=null,t.onpeeridentity=null,t.onidpassertionerror=null,t.onidpvalidationerror=null,clearTimeout(this.timerGatheringTimeout),delete this.timerGatheringTimeout,clearTimeout(this.timerGatheringTimeoutAfterRelay),delete this.timerGatheringTimeoutAfterRelay,u("reset() | closing current peerConnection"),t.close(),o.call(this,e),s.call(this)}},{"./Adapter":1,debug:6,merge:9}],3:[function(e,t,n){"use strict";function i(e){var t=c(e||{});return l=!0,i.RTCPeerConnection=d,i.getUserMedia=t.getUserMedia,i.RTCSessionDescription=t.RTCSessionDescription,i.RTCIceCandidate=t.RTCIceCandidate,i.MediaStreamTrack=t.MediaStreamTrack,i.getMediaDevices=t.getMediaDevices,i.attachMediaStream=t.attachMediaStream,i.closeMediaStream=t.closeMediaStream,i.canRenegotiate=t.canRenegotiate,t.hasWebRTC()?(r("WebRTC supported"),!0):(a("WebRTC not supported"),!1)}t.exports=i;var o=e("bowser").browser,r=e("debug")("rtcninja"),a=e("debug")("rtcninja:ERROR"),s=e("./version"),c=e("./Adapter"),d=e("./RTCPeerConnection"),l=!1;a.log=console.warn.bind(console),r("version %s",s),r("detected browser: %s %s [mobile:%s, tablet:%s, android:%s, ios:%s]",o.name,o.version,!!o.mobile,!!o.tablet,!!o.android,!!o.ios),i.hasWebRTC=function(){return l||i(),c.hasWebRTC()},Object.defineProperty(i,"version",{get:function(){return s}}),Object.defineProperty(i,"called",{get:function(){return l}}),i.debug=e("debug"),i.browser=o},{"./Adapter":1,"./RTCPeerConnection":2,"./version":4,bowser:5,debug:6}],4:[function(e,t,n){"use strict";t.exports=e("../package.json").version},{"../package.json":10}],5:[function(t,n,i){!function(t,i){"undefined"!=typeof n&&n.exports?n.exports.browser=i():"function"==typeof e&&e.amd?e(i):this[t]=i()}("bowser",function(){function e(e){function n(t){var n=e.match(t);return n&&n.length>1&&n[1]||""}function i(t){var n=e.match(t);return n&&n.length>1&&n[2]||""}var o,r=n(/(ipod|iphone|ipad)/i).toLowerCase(),a=/like android/i.test(e),s=!a&&/android/i.test(e),c=n(/edge\/(\d+(\.\d+)?)/i),d=n(/version\/(\d+(\.\d+)?)/i),l=/tablet/i.test(e),u=!l&&/[^-]mobi/i.test(e);/opera|opr/i.test(e)?o={name:"Opera",opera:t,version:d||n(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)}:/windows phone/i.test(e)?(o={name:"Windows Phone",windowsphone:t},c?(o.msedge=t,o.version=c):(o.msie=t,o.version=n(/iemobile\/(\d+(\.\d+)?)/i))):/msie|trident/i.test(e)?o={name:"Internet Explorer",msie:t,version:n(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:/chrome.+? edge/i.test(e)?o={name:"Microsoft Edge",msedge:t,version:c}:/chrome|crios|crmo/i.test(e)?o={name:"Chrome",chrome:t,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:r?(o={name:"iphone"==r?"iPhone":"ipad"==r?"iPad":"iPod"},d&&(o.version=d)):/sailfish/i.test(e)?o={name:"Sailfish",sailfish:t,version:n(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(e)?o={name:"SeaMonkey",seamonkey:t,version:n(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel/i.test(e)?(o={name:"Firefox",firefox:t,version:n(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(e)&&(o.firefoxos=t)):/silk/i.test(e)?o={name:"Amazon Silk",silk:t,version:n(/silk\/(\d+(\.\d+)?)/i)}:s?o={name:"Android",version:d}:/phantom/i.test(e)?o={name:"PhantomJS",phantom:t,version:n(/phantomjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(e)||/rim\stablet/i.test(e)?o={name:"BlackBerry",blackberry:t,version:d||n(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:/(web|hpw)os/i.test(e)?(o={name:"WebOS",webos:t,version:d||n(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(e)&&(o.touchpad=t)):o=/bada/i.test(e)?{name:"Bada",bada:t,version:n(/dolfin\/(\d+(\.\d+)?)/i)}:/tizen/i.test(e)?{name:"Tizen",tizen:t,version:n(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||d}:/safari/i.test(e)?{name:"Safari",safari:t,version:d}:{name:n(/^(.*)\/(.*) /),version:i(/^(.*)\/(.*) /)},!o.msedge&&/(apple)?webkit/i.test(e)?(o.name=o.name||"Webkit",o.webkit=t,!o.version&&d&&(o.version=d)):!o.opera&&/gecko\//i.test(e)&&(o.name=o.name||"Gecko",o.gecko=t,o.version=o.version||n(/gecko\/(\d+(\.\d+)?)/i)),o.msedge||!s&&!o.silk?r&&(o[r]=t,o.ios=t):o.android=t;var p="";o.windowsphone?p=n(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):r?(p=n(/os (\d+([_\s]\d+)*) like mac os x/i),p=p.replace(/[_\s]/g,".")):s?p=n(/android[ \/-](\d+(\.\d+)*)/i):o.webos?p=n(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):o.blackberry?p=n(/rim\stablet\sos\s(\d+(\.\d+)*)/i):o.bada?p=n(/bada\/(\d+(\.\d+)*)/i):o.tizen&&(p=n(/tizen[\/\s](\d+(\.\d+)*)/i)),p&&(o.osversion=p);var g=p.split(".")[0];return l||"ipad"==r||s&&(3==g||4==g&&!u)||o.silk?o.tablet=t:(u||"iphone"==r||"ipod"==r||s||o.blackberry||o.webos||o.bada)&&(o.mobile=t),o.msedge||o.msie&&o.version>=10||o.chrome&&o.version>=20||o.firefox&&o.version>=20||o.safari&&o.version>=6||o.opera&&o.version>=10||o.ios&&o.osversion&&o.osversion.split(".")[0]>=6||o.blackberry&&o.version>=10.1?o.a=t:o.msie&&o.version<10||o.chrome&&o.version<20||o.firefox&&o.version<20||o.safari&&o.version<6||o.opera&&o.version<10||o.ios&&o.osversion&&o.osversion.split(".")[0]<6?o.c=t:o.x=t,o}var t=!0,n=e("undefined"!=typeof navigator?navigator.userAgent:"");return n.test=function(e){for(var t=0;t=31}function o(){var e=arguments,t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+n.humanize(this.diff),!t)return e;var i="color: "+this.color;e=[e[0],i,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,r=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(r=o))}),e.splice(r,0,i),e}function r(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?n.storage.removeItem("debug"):n.storage.debug=e}catch(t){}}function s(){var e;try{e=n.storage.debug}catch(t){}return e}function c(){try{return window.localStorage}catch(e){}}n=t.exports=e("./debug"),n.log=r,n.formatArgs=o,n.save=a,n.load=s,n.useColors=i,n.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),n.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],n.formatters.j=function(e){return JSON.stringify(e)},n.enable(s())},{"./debug":7}],7:[function(e,t,n){function i(){return n.colors[l++%n.colors.length]}function o(e){function t(){}function o(){var e=o,t=+new Date,r=t-(d||t);e.diff=r,e.prev=d,e.curr=t,d=t,null==e.useColors&&(e.useColors=n.useColors()),null==e.color&&e.useColors&&(e.color=i());var a=Array.prototype.slice.call(arguments);a[0]=n.coerce(a[0]),"string"!=typeof a[0]&&(a=["%o"].concat(a));var s=0;a[0]=a[0].replace(/%([a-z%])/g,function(t,i){if("%%"===t)return t;s++;var o=n.formatters[i];if("function"==typeof o){var r=a[s];t=o.call(e,r),a.splice(s,1),s--}return t}),"function"==typeof n.formatArgs&&(a=n.formatArgs.apply(e,a));var c=o.log||n.log||console.log.bind(console);c.apply(e,a)}t.enabled=!1,o.enabled=!0;var r=n.enabled(e)?o:t;return r.namespace=e,r}function r(e){n.save(e);for(var t=(e||"").split(/[\s,]+/),i=t.length,o=0;i>o;o++)t[o]&&(e=t[o].replace(/\*/g,".*?"),"-"===e[0]?n.skips.push(new RegExp("^"+e.substr(1)+"$")):n.names.push(new RegExp("^"+e+"$")))}function a(){n.enable("")}function s(e){var t,i;for(t=0,i=n.skips.length;i>t;t++)if(n.skips[t].test(e))return!1;for(t=0,i=n.names.length;i>t;t++)if(n.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}n=t.exports=o,n.coerce=c,n.disable=a,n.enable=r,n.enabled=s,n.humanize=e("ms"),n.names=[],n.skips=[],n.formatters={};var d,l=0},{ms:8}],8:[function(e,t,n){function i(e){if(e=""+e,!(e.length>1e4)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),i=(t[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return n*u;case"days":case"day":case"d":return n*l;case"hours":case"hour":case"hrs":case"hr":case"h":return n*d;case"minutes":case"minute":case"mins":case"min":case"m":return n*c;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function o(e){return e>=l?Math.round(e/l)+"d":e>=d?Math.round(e/d)+"h":e>=c?Math.round(e/c)+"m":e>=s?Math.round(e/s)+"s":e+"ms"}function r(e){return a(e,l,"day")||a(e,d,"hour")||a(e,c,"minute")||a(e,s,"second")||e+" ms"}function a(e,t,n){return t>e?void 0:1.5*t>e?Math.floor(e/t)+" "+n:Math.ceil(e/t)+" "+n+"s"}var s=1e3,c=60*s,d=60*c,l=24*d,u=365.25*l;t.exports=function(e,t){return t=t||{},"string"==typeof e?i(e):t["long"]?r(e):o(e)}},{}],9:[function(e,t,n){!function(e){function n(e,t){if("object"!==o(e))return t;for(var i in t)e[i]="object"===o(e[i])&&"object"===o(t[i])?n(e[i],t[i]):t[i];return e}function i(e,t,i){var a=i[0],s=i.length;(e||"object"!==o(a))&&(a={});for(var c=0;s>c;++c){var d=i[c],l=o(d);if("object"===l)for(var u in d){var p=e?r.clone(d[u]):d[u];a[u]=t?n(a[u],p):p}}return a}function o(e){return{}.toString.call(e).slice(8,-1).toLowerCase()}var r=function(e){return i(e===!0,!1,arguments)},a="merge";r.recursive=function(e){return i(e===!0,!0,arguments)},r.clone=function(e){var t,n,i=e,a=o(e);if("array"===a)for(i=[],n=e.length,t=0;n>t;++t)i[t]=r.clone(e[t]);else if("object"===a){i={};for(t in e)i[t]=r.clone(e[t])}return i},e?t.exports=r:window[a]=r}("object"==typeof t&&t&&"object"==typeof t.exports&&t.exports)},{}],10:[function(e,t,n){t.exports={name:"rtcninja",version:"0.6.2",description:"WebRTC API wrapper to deal with different browsers",author:"Iñaki Baz Castillo (http://eface2face.com)",contributors:["Jesús Pérez "],license:"MIT",main:"lib/rtcninja.js",homepage:"https://github.com/eface2face/rtcninja.js",repository:{type:"git",url:"https://github.com/eface2face/rtcninja.js.git"},keywords:["webrtc"],engines:{node:">=0.10.32"},dependencies:{bowser:"^0.7.3",debug:"^2.2.0",merge:"^1.2.0"},devDependencies:{browserify:"^10.2.3",gulp:"git+https://github.com/gulpjs/gulp.git#4.0","gulp-expect-file":"0.0.7","gulp-filelog":"^0.4.1","gulp-header":"^1.2.2","gulp-jscs":"^1.6.0","gulp-jscs-stylish":"^1.1.0","gulp-jshint":"^1.11.0","gulp-rename":"^1.2.2","gulp-uglify":"^1.2.0","jshint-stylish":"^1.0.2",retire:"^1.1.0",shelljs:"^0.5.0","vinyl-source-stream":"^1.1.0"}}},{}]},{},[3])(3)}); rtcninja.js-0.6.2/dist/rtcninja.js 0000664 0000000 0000000 00000147650 12544264443 0017100 0 ustar 00root root 0000000 0000000 /*
* rtcninja.js v0.6.2
* WebRTC API wrapper to deal with different browsers
* Copyright 2015 Iñaki Baz Castillo (http://eface2face.com)
* License MIT
*/
(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.rtcninja = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 32) ||
(browser.android && browser.chrome && browserVersion >= 39) ||
(isDesktop && browser.opera && browserVersion >= 27) ||
(browser.android && browser.opera && browserVersion >= 24) ||
(browser.android && browser.webkit && !browser.chrome && browserVersion >= 37) ||
(virtNavigator.webkitGetUserMedia && virtGlobal.webkitRTCPeerConnection)
) {
hasWebRTC = true;
getUserMedia = virtNavigator.webkitGetUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.webkitRTCPeerConnection;
RTCSessionDescription = virtGlobal.RTCSessionDescription;
RTCIceCandidate = virtGlobal.RTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = true;
oldSpecRTCOfferOptions = false;
// Firefox desktop, Firefox Android.
} else if (
(isDesktop && browser.firefox && browserVersion >= 22) ||
(browser.android && browser.firefox && browserVersion >= 33) ||
(virtNavigator.mozGetUserMedia && virtGlobal.mozRTCPeerConnection)
) {
hasWebRTC = true;
getUserMedia = virtNavigator.mozGetUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.mozRTCPeerConnection;
RTCSessionDescription = virtGlobal.mozRTCSessionDescription;
RTCIceCandidate = virtGlobal.mozRTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
attachMediaStream = function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = false;
oldSpecRTCOfferOptions = false;
// WebRTC plugin required. For example IE or Safari with the Temasys plugin.
} else if (
options.plugin &&
typeof options.plugin.isRequired === 'function' &&
options.plugin.isRequired() &&
typeof options.plugin.isInstalled === 'function' &&
options.plugin.isInstalled()
) {
var pluginiface = options.plugin.interface;
hasWebRTC = true;
getUserMedia = pluginiface.getUserMedia;
RTCPeerConnection = pluginiface.RTCPeerConnection;
RTCSessionDescription = pluginiface.RTCSessionDescription;
RTCIceCandidate = pluginiface.RTCIceCandidate;
MediaStreamTrack = pluginiface.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = pluginiface.attachMediaStream;
canRenegotiate = pluginiface.canRenegotiate;
oldSpecRTCOfferOptions = true; // TODO: Update when fixed in the plugin.
// Best effort (may be adater.js is loaded).
} else if (virtNavigator.getUserMedia && virtGlobal.RTCPeerConnection) {
hasWebRTC = true;
getUserMedia = virtNavigator.getUserMedia.bind(virtNavigator);
RTCPeerConnection = virtGlobal.RTCPeerConnection;
RTCSessionDescription = virtGlobal.RTCSessionDescription;
RTCIceCandidate = virtGlobal.RTCIceCandidate;
MediaStreamTrack = virtGlobal.MediaStreamTrack;
if (MediaStreamTrack && MediaStreamTrack.getSources) {
getMediaDevices = MediaStreamTrack.getSources.bind(MediaStreamTrack);
} else if (virtNavigator.getMediaDevices) {
getMediaDevices = virtNavigator.getMediaDevices.bind(virtNavigator);
}
attachMediaStream = virtGlobal.attachMediaStream || function (element, stream) {
element.src = URL.createObjectURL(stream);
return element;
};
canRenegotiate = false;
oldSpecRTCOfferOptions = false;
}
function throwNonSupported(item) {
return function () {
throw new Error('rtcninja: WebRTC not supported, missing ' + item +
' [browser: ' + browser.name + ' ' + browser.version + ']');
};
}
// Public API.
// Expose a WebRTC checker.
Adapter.hasWebRTC = function () {
return hasWebRTC;
};
// Expose getUserMedia.
if (getUserMedia) {
Adapter.getUserMedia = function (constraints, successCallback, errorCallback) {
debug('getUserMedia() | constraints: %o', constraints);
try {
getUserMedia(constraints,
function (stream) {
debug('getUserMedia() | success');
if (successCallback) {
successCallback(stream);
}
},
function (error) {
debug('getUserMedia() | error:', error);
if (errorCallback) {
errorCallback(error);
}
}
);
}
catch (error) {
debugerror('getUserMedia() | error:', error);
if (errorCallback) {
errorCallback(error);
}
}
};
} else {
Adapter.getUserMedia = function (constraints, successCallback, errorCallback) {
debugerror('getUserMedia() | WebRTC not supported');
if (errorCallback) {
errorCallback(new Error('rtcninja: WebRTC not supported, missing ' +
'getUserMedia [browser: ' + browser.name + ' ' + browser.version + ']'));
} else {
throwNonSupported('getUserMedia');
}
};
}
// Expose RTCPeerConnection.
Adapter.RTCPeerConnection = RTCPeerConnection || throwNonSupported('RTCPeerConnection');
// Expose RTCSessionDescription.
Adapter.RTCSessionDescription = RTCSessionDescription || throwNonSupported('RTCSessionDescription');
// Expose RTCIceCandidate.
Adapter.RTCIceCandidate = RTCIceCandidate || throwNonSupported('RTCIceCandidate');
// Expose MediaStreamTrack.
Adapter.MediaStreamTrack = MediaStreamTrack || throwNonSupported('MediaStreamTrack');
// Expose getMediaDevices.
Adapter.getMediaDevices = getMediaDevices;
// Expose MediaStreamTrack.
Adapter.attachMediaStream = attachMediaStream || throwNonSupported('attachMediaStream');
// Expose canRenegotiate attribute.
Adapter.canRenegotiate = canRenegotiate;
// Expose closeMediaStream.
Adapter.closeMediaStream = function (stream) {
if (!stream) {
return;
}
// Latest spec states that MediaStream has no stop() method and instead must
// call stop() on every MediaStreamTrack.
if (MediaStreamTrack && MediaStreamTrack.prototype && MediaStreamTrack.prototype.stop) {
debug('closeMediaStream() | calling stop() on all the MediaStreamTrack');
var tracks, i, len;
if (stream.getTracks) {
tracks = stream.getTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
} else {
tracks = stream.getAudioTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
tracks = stream.getVideoTracks();
for (i = 0, len = tracks.length; i < len; i += 1) {
tracks[i].stop();
}
}
// Deprecated by the spec, but still in use.
} else if (typeof stream.stop === 'function') {
debug('closeMediaStream() | calling stop() on the MediaStream');
stream.stop();
}
};
// Expose fixPeerConnectionConfig.
Adapter.fixPeerConnectionConfig = function (pcConfig) {
var i, len, iceServer, hasUrls, hasUrl;
if (!Array.isArray(pcConfig.iceServers)) {
pcConfig.iceServers = [];
}
for (i = 0, len = pcConfig.iceServers.length; i < len; i += 1) {
iceServer = pcConfig.iceServers[i];
hasUrls = iceServer.hasOwnProperty('urls');
hasUrl = iceServer.hasOwnProperty('url');
if (typeof iceServer === 'object') {
// Has .urls but not .url, so add .url with a single string value.
if (hasUrls && !hasUrl) {
iceServer.url = (Array.isArray(iceServer.urls) ? iceServer.urls[0] : iceServer.urls);
// Has .url but not .urls, so add .urls with same value.
} else if (!hasUrls && hasUrl) {
iceServer.urls = (Array.isArray(iceServer.url) ? iceServer.url.slice() : iceServer.url);
}
// Ensure .url is a single string.
if (hasUrl && Array.isArray(iceServer.url)) {
iceServer.url = iceServer.url[0];
}
}
}
};
// Expose fixRTCOfferOptions.
Adapter.fixRTCOfferOptions = function (options) {
options = options || {};
// New spec.
if (!oldSpecRTCOfferOptions) {
if (options.mandatory && options.mandatory.OfferToReceiveAudio) {
options.offerToReceiveAudio = 1;
}
if (options.mandatory && options.mandatory.OfferToReceiveVideo) {
options.offerToReceiveVideo = 1;
}
delete options.mandatory;
// Old spec.
} else {
if (options.offerToReceiveAudio) {
options.mandatory = options.mandatory || {};
options.mandatory.OfferToReceiveAudio = true;
}
if (options.offerToReceiveVideo) {
options.mandatory = options.mandatory || {};
options.mandatory.OfferToReceiveVideo = true;
}
}
};
return Adapter;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"bowser":5,"debug":6}],2:[function(require,module,exports){
'use strict';
// Expose the RTCPeerConnection class.
module.exports = RTCPeerConnection;
// Dependencies.
var merge = require('merge'),
debug = require('debug')('rtcninja:RTCPeerConnection'),
debugerror = require('debug')('rtcninja:ERROR:RTCPeerConnection'),
Adapter = require('./Adapter'),
// Internal constants.
C = {
REGEXP_NORMALIZED_CANDIDATE: new RegExp(/^candidate:/i),
REGEXP_FIX_CANDIDATE: new RegExp(/(^a=|\r|\n)/gi),
REGEXP_RELAY_CANDIDATE: new RegExp(/ relay /i),
REGEXP_SDP_CANDIDATES: new RegExp(/^a=candidate:.*\r\n/igm),
REGEXP_SDP_NON_RELAY_CANDIDATES: new RegExp(/^a=candidate:(.(?!relay ))*\r\n/igm)
},
// Internal variables.
VAR = {
normalizeCandidate: null
};
debugerror.log = console.warn.bind(console);
// Constructor
function RTCPeerConnection(pcConfig, pcConstraints) {
debug('new | pcConfig: %o', pcConfig);
// Set this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
// NOTE: Deprecated pcConstraints argument.
this.pcConstraints = pcConstraints;
// Own version of the localDescription.
this.ourLocalDescription = null;
// Latest values of PC attributes to avoid events with same value.
this.ourSignalingState = null;
this.ourIceConnectionState = null;
this.ourIceGatheringState = null;
// Timer for options.gatheringTimeout.
this.timerGatheringTimeout = null;
// Timer for options.gatheringTimeoutAfterRelay.
this.timerGatheringTimeoutAfterRelay = null;
// Flag to ignore new gathered ICE candidates.
this.ignoreIceGathering = false;
// Flag set when closed.
this.closed = false;
// Set RTCPeerConnection.
setPeerConnection.call(this);
// Set properties.
setProperties.call(this);
}
// Public API.
RTCPeerConnection.prototype.createOffer = function (successCallback, failureCallback, options) {
debug('createOffer()');
var self = this;
Adapter.fixRTCOfferOptions(options);
this.pc.createOffer(
function (offer) {
if (isClosed.call(self)) {
return;
}
debug('createOffer() | success');
if (successCallback) {
successCallback(offer);
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('createOffer() | error:', error);
if (failureCallback) {
failureCallback(error);
}
},
options
);
};
RTCPeerConnection.prototype.createAnswer = function (successCallback, failureCallback, options) {
debug('createAnswer()');
var self = this;
this.pc.createAnswer(
function (answer) {
if (isClosed.call(self)) {
return;
}
debug('createAnswer() | success');
if (successCallback) {
successCallback(answer);
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('createAnswer() | error:', error);
if (failureCallback) {
failureCallback(error);
}
},
options
);
};
RTCPeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
debug('setLocalDescription()');
var self = this;
this.pc.setLocalDescription(
description,
// success.
function () {
if (isClosed.call(self)) {
return;
}
debug('setLocalDescription() | success');
// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
runTimerGatheringTimeout();
if (successCallback) {
successCallback();
}
},
// failure
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('setLocalDescription() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
// Enable (again) ICE gathering.
this.ignoreIceGathering = false;
// Handle gatheringTimeout.
function runTimerGatheringTimeout() {
if (typeof self.options.gatheringTimeout !== 'number') {
return;
}
// If setLocalDescription was already called, it may happen that
// ICE gathering is not needed, so don't run this timer.
if (self.pc.iceGatheringState === 'complete') {
return;
}
debug('setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)',
self.options.gatheringTimeout);
self.timerGatheringTimeout = setTimeout(function () {
if (isClosed.call(self)) {
return;
}
debug('forced end of candidates after gatheringTimeout timeout');
// Clear gathering timers.
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({ candidate: null }, null);
}
}, self.options.gatheringTimeout);
}
};
RTCPeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
debug('setRemoteDescription()');
var self = this;
this.pc.setRemoteDescription(
description,
function () {
if (isClosed.call(self)) {
return;
}
debug('setRemoteDescription() | success');
if (successCallback) {
successCallback();
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('setRemoteDescription() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
};
RTCPeerConnection.prototype.updateIce = function (pcConfig) {
debug('updateIce() | pcConfig: %o', pcConfig);
// Update this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
this.pc.updateIce(this.pcConfig);
// Enable (again) ICE gathering.
this.ignoreIceGathering = false;
};
RTCPeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
debug('addIceCandidate() | candidate: %o', candidate);
var self = this;
this.pc.addIceCandidate(
candidate,
function () {
if (isClosed.call(self)) {
return;
}
debug('addIceCandidate() | success');
if (successCallback) {
successCallback();
}
},
function (error) {
if (isClosed.call(self)) {
return;
}
debugerror('addIceCandidate() | error:', error);
if (failureCallback) {
failureCallback(error);
}
}
);
};
RTCPeerConnection.prototype.getConfiguration = function () {
debug('getConfiguration()');
return this.pc.getConfiguration();
};
RTCPeerConnection.prototype.getLocalStreams = function () {
debug('getLocalStreams()');
return this.pc.getLocalStreams();
};
RTCPeerConnection.prototype.getRemoteStreams = function () {
debug('getRemoteStreams()');
return this.pc.getRemoteStreams();
};
RTCPeerConnection.prototype.getStreamById = function (streamId) {
debug('getStreamById() | streamId: %s', streamId);
return this.pc.getStreamById(streamId);
};
RTCPeerConnection.prototype.addStream = function (stream) {
debug('addStream() | stream: %s', stream);
this.pc.addStream(stream);
};
RTCPeerConnection.prototype.removeStream = function (stream) {
debug('removeStream() | stream: %o', stream);
this.pc.removeStream(stream);
};
RTCPeerConnection.prototype.close = function () {
debug('close()');
this.closed = true;
// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
this.pc.close();
};
RTCPeerConnection.prototype.createDataChannel = function () {
debug('createDataChannel()');
return this.pc.createDataChannel.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.createDTMFSender = function (track) {
debug('createDTMFSender()');
return this.pc.createDTMFSender(track);
};
RTCPeerConnection.prototype.getStats = function () {
debug('getStats()');
return this.pc.getStats.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.setIdentityProvider = function () {
debug('setIdentityProvider()');
return this.pc.setIdentityProvider.apply(this.pc, arguments);
};
RTCPeerConnection.prototype.getIdentityAssertion = function () {
debug('getIdentityAssertion()');
return this.pc.getIdentityAssertion();
};
RTCPeerConnection.prototype.reset = function (pcConfig) {
debug('reset() | pcConfig: %o', pcConfig);
var pc = this.pc;
// Remove events in the old PC.
pc.onnegotiationneeded = null;
pc.onicecandidate = null;
pc.onaddstream = null;
pc.onremovestream = null;
pc.ondatachannel = null;
pc.onsignalingstatechange = null;
pc.oniceconnectionstatechange = null;
pc.onicegatheringstatechange = null;
pc.onidentityresult = null;
pc.onpeeridentity = null;
pc.onidpassertionerror = null;
pc.onidpvalidationerror = null;
// Clear gathering timers.
clearTimeout(this.timerGatheringTimeout);
delete this.timerGatheringTimeout;
clearTimeout(this.timerGatheringTimeoutAfterRelay);
delete this.timerGatheringTimeoutAfterRelay;
// Silently close the old PC.
debug('reset() | closing current peerConnection');
pc.close();
// Set this.pcConfig and this.options.
setConfigurationAndOptions.call(this, pcConfig);
// Create a new PC.
setPeerConnection.call(this);
};
// Private Helpers.
function setConfigurationAndOptions(pcConfig) {
// Clone pcConfig.
this.pcConfig = merge(true, pcConfig);
// Fix pcConfig.
Adapter.fixPeerConnectionConfig(this.pcConfig);
this.options = {
iceTransportsRelay: (this.pcConfig.iceTransports === 'relay'),
iceTransportsNone: (this.pcConfig.iceTransports === 'none'),
gatheringTimeout: this.pcConfig.gatheringTimeout,
gatheringTimeoutAfterRelay: this.pcConfig.gatheringTimeoutAfterRelay
};
// Remove custom rtcninja.RTCPeerConnection options from pcConfig.
delete this.pcConfig.gatheringTimeout;
delete this.pcConfig.gatheringTimeoutAfterRelay;
debug('setConfigurationAndOptions | processed pcConfig: %o', this.pcConfig);
}
function isClosed() {
return ((this.closed) || (this.pc && this.pc.iceConnectionState === 'closed'));
}
function setEvents() {
var self = this,
pc = this.pc;
pc.onnegotiationneeded = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onnegotiationneeded()');
if (self.onnegotiationneeded) {
self.onnegotiationneeded(event);
}
};
pc.onicecandidate = function (event) {
var candidate, isRelay, newCandidate;
if (isClosed.call(self)) {
return;
}
if (self.ignoreIceGathering) {
return;
}
// Ignore any candidate (event the null one) if iceTransports:'none' is set.
if (self.options.iceTransportsNone) {
return;
}
candidate = event.candidate;
if (candidate) {
isRelay = C.REGEXP_RELAY_CANDIDATE.test(candidate.candidate);
// Ignore if just relay candidates are requested.
if (self.options.iceTransportsRelay && !isRelay) {
return;
}
// Handle gatheringTimeoutAfterRelay.
if (isRelay && !self.timerGatheringTimeoutAfterRelay &&
(typeof self.options.gatheringTimeoutAfterRelay === 'number')) {
debug('onicecandidate() | first relay candidate found, ending gathering in %d ms', self.options.gatheringTimeoutAfterRelay);
self.timerGatheringTimeoutAfterRelay = setTimeout(function () {
if (isClosed.call(self)) {
return;
}
debug('forced end of candidates after timeout');
// Clear gathering timers.
delete self.timerGatheringTimeoutAfterRelay;
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
// Ignore new candidates.
self.ignoreIceGathering = true;
if (self.onicecandidate) {
self.onicecandidate({candidate: null}, null);
}
}, self.options.gatheringTimeoutAfterRelay);
}
newCandidate = new Adapter.RTCIceCandidate({
sdpMid: candidate.sdpMid,
sdpMLineIndex: candidate.sdpMLineIndex,
candidate: candidate.candidate
});
// Force correct candidate syntax (just check it once).
if (VAR.normalizeCandidate === null) {
if (C.REGEXP_NORMALIZED_CANDIDATE.test(candidate.candidate)) {
VAR.normalizeCandidate = false;
} else {
debug('onicecandidate() | normalizing ICE candidates syntax (remove "a=" and "\\r\\n")');
VAR.normalizeCandidate = true;
}
}
if (VAR.normalizeCandidate) {
newCandidate.candidate = candidate.candidate.replace(C.REGEXP_FIX_CANDIDATE, '');
}
debug(
'onicecandidate() | m%d(%s) %s',
newCandidate.sdpMLineIndex,
newCandidate.sdpMid || 'no mid', newCandidate.candidate);
if (self.onicecandidate) {
self.onicecandidate(event, newCandidate);
}
// Null candidate (end of candidates).
} else {
debug('onicecandidate() | end of candidates');
// Clear gathering timers.
clearTimeout(self.timerGatheringTimeout);
delete self.timerGatheringTimeout;
clearTimeout(self.timerGatheringTimeoutAfterRelay);
delete self.timerGatheringTimeoutAfterRelay;
if (self.onicecandidate) {
self.onicecandidate(event, null);
}
}
};
pc.onaddstream = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onaddstream() | stream: %o', event.stream);
if (self.onaddstream) {
self.onaddstream(event, event.stream);
}
};
pc.onremovestream = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onremovestream() | stream: %o', event.stream);
if (self.onremovestream) {
self.onremovestream(event, event.stream);
}
};
pc.ondatachannel = function (event) {
if (isClosed.call(self)) {
return;
}
debug('ondatachannel() | datachannel: %o', event.channel);
if (self.ondatachannel) {
self.ondatachannel(event, event.channel);
}
};
pc.onsignalingstatechange = function (event) {
if (pc.signalingState === self.ourSignalingState) {
return;
}
debug('onsignalingstatechange() | signalingState: %s', pc.signalingState);
self.ourSignalingState = pc.signalingState;
if (self.onsignalingstatechange) {
self.onsignalingstatechange(event, pc.signalingState);
}
};
pc.oniceconnectionstatechange = function (event) {
if (pc.iceConnectionState === self.ourIceConnectionState) {
return;
}
debug('oniceconnectionstatechange() | iceConnectionState: %s', pc.iceConnectionState);
self.ourIceConnectionState = pc.iceConnectionState;
if (self.oniceconnectionstatechange) {
self.oniceconnectionstatechange(event, pc.iceConnectionState);
}
};
pc.onicegatheringstatechange = function (event) {
if (isClosed.call(self)) {
return;
}
if (pc.iceGatheringState === self.ourIceGatheringState) {
return;
}
debug('onicegatheringstatechange() | iceGatheringState: %s', pc.iceGatheringState);
self.ourIceGatheringState = pc.iceGatheringState;
if (self.onicegatheringstatechange) {
self.onicegatheringstatechange(event, pc.iceGatheringState);
}
};
pc.onidentityresult = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidentityresult()');
if (self.onidentityresult) {
self.onidentityresult(event);
}
};
pc.onpeeridentity = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onpeeridentity()');
if (self.onpeeridentity) {
self.onpeeridentity(event);
}
};
pc.onidpassertionerror = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidpassertionerror()');
if (self.onidpassertionerror) {
self.onidpassertionerror(event);
}
};
pc.onidpvalidationerror = function (event) {
if (isClosed.call(self)) {
return;
}
debug('onidpvalidationerror()');
if (self.onidpvalidationerror) {
self.onidpvalidationerror(event);
}
};
}
function setPeerConnection() {
// Create a RTCPeerConnection.
if (!this.pcConstraints) {
this.pc = new Adapter.RTCPeerConnection(this.pcConfig);
} else {
// NOTE: Deprecated.
this.pc = new Adapter.RTCPeerConnection(this.pcConfig, this.pcConstraints);
}
// Set RTC events.
setEvents.call(this);
}
function getLocalDescription() {
var pc = this.pc,
options = this.options,
sdp = null;
if (!pc.localDescription) {
this.ourLocalDescription = null;
return null;
}
// Mangle the SDP string.
if (options.iceTransportsRelay) {
sdp = pc.localDescription.sdp.replace(C.REGEXP_SDP_NON_RELAY_CANDIDATES, '');
} else if (options.iceTransportsNone) {
sdp = pc.localDescription.sdp.replace(C.REGEXP_SDP_CANDIDATES, '');
}
this.ourLocalDescription = new Adapter.RTCSessionDescription({
type: pc.localDescription.type,
sdp: sdp || pc.localDescription.sdp
});
return this.ourLocalDescription;
}
function setProperties() {
var self = this;
Object.defineProperties(this, {
peerConnection: {
get: function () {
return self.pc;
}
},
signalingState: {
get: function () {
return self.pc.signalingState;
}
},
iceConnectionState: {
get: function () {
return self.pc.iceConnectionState;
}
},
iceGatheringState: {
get: function () {
return self.pc.iceGatheringState;
}
},
localDescription: {
get: function () {
return getLocalDescription.call(self);
}
},
remoteDescription: {
get: function () {
return self.pc.remoteDescription;
}
},
peerIdentity: {
get: function () {
return self.pc.peerIdentity;
}
}
});
}
},{"./Adapter":1,"debug":6,"merge":9}],3:[function(require,module,exports){
'use strict';
module.exports = rtcninja;
// Dependencies.
var browser = require('bowser').browser,
debug = require('debug')('rtcninja'),
debugerror = require('debug')('rtcninja:ERROR'),
version = require('./version'),
Adapter = require('./Adapter'),
RTCPeerConnection = require('./RTCPeerConnection'),
// Internal vars.
called = false;
debugerror.log = console.warn.bind(console);
debug('version %s', version);
debug('detected browser: %s %s [mobile:%s, tablet:%s, android:%s, ios:%s]',
browser.name, browser.version, !!browser.mobile, !!browser.tablet,
!!browser.android, !!browser.ios);
// Constructor.
function rtcninja(options) {
// Load adapter
var iface = Adapter(options || {}); // jshint ignore:line
called = true;
// Expose RTCPeerConnection class.
rtcninja.RTCPeerConnection = RTCPeerConnection;
// Expose WebRTC API and utils.
rtcninja.getUserMedia = iface.getUserMedia;
rtcninja.RTCSessionDescription = iface.RTCSessionDescription;
rtcninja.RTCIceCandidate = iface.RTCIceCandidate;
rtcninja.MediaStreamTrack = iface.MediaStreamTrack;
rtcninja.getMediaDevices = iface.getMediaDevices;
rtcninja.attachMediaStream = iface.attachMediaStream;
rtcninja.closeMediaStream = iface.closeMediaStream;
rtcninja.canRenegotiate = iface.canRenegotiate;
// Log WebRTC support.
if (iface.hasWebRTC()) {
debug('WebRTC supported');
return true;
} else {
debugerror('WebRTC not supported');
return false;
}
}
// Public API.
// If called without calling rtcninja(), call it.
rtcninja.hasWebRTC = function () {
if (!called) {
rtcninja();
}
return Adapter.hasWebRTC();
};
// Expose version property.
Object.defineProperty(rtcninja, 'version', {
get: function () {
return version;
}
});
// Expose called property.
Object.defineProperty(rtcninja, 'called', {
get: function () {
return called;
}
});
// Exposing stuff.
rtcninja.debug = require('debug');
rtcninja.browser = browser;
},{"./Adapter":1,"./RTCPeerConnection":2,"./version":4,"bowser":5,"debug":6}],4:[function(require,module,exports){
'use strict';
// Expose the 'version' field of package.json.
module.exports = require('../package.json').version;
},{"../package.json":10}],5:[function(require,module,exports){
/*!
* Bowser - a browser detector
* https://github.com/ded/bowser
* MIT License | (c) Dustin Diaz 2014
*/
!function (name, definition) {
if (typeof module != 'undefined' && module.exports) module.exports['browser'] = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else this[name] = definition()
}('bowser', function () {
/**
* See useragents.js for examples of navigator.userAgent
*/
var t = true
function detect(ua) {
function getFirstMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[1]) || '';
}
function getSecondMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[2]) || '';
}
var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
, likeAndroid = /like android/i.test(ua)
, android = !likeAndroid && /android/i.test(ua)
, edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i)
, versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
, tablet = /tablet/i.test(ua)
, mobile = !tablet && /[^-]mobi/i.test(ua)
, result
if (/opera|opr/i.test(ua)) {
result = {
name: 'Opera'
, opera: t
, version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
}
}
else if (/windows phone/i.test(ua)) {
result = {
name: 'Windows Phone'
, windowsphone: t
}
if (edgeVersion) {
result.msedge = t
result.version = edgeVersion
}
else {
result.msie = t
result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
}
}
else if (/msie|trident/i.test(ua)) {
result = {
name: 'Internet Explorer'
, msie: t
, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
}
}
else if (/chrome.+? edge/i.test(ua)) {
result = {
name: 'Microsoft Edge'
, msedge: t
, version: edgeVersion
}
}
else if (/chrome|crios|crmo/i.test(ua)) {
result = {
name: 'Chrome'
, chrome: t
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
}
}
else if (iosdevice) {
result = {
name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
}
// WTF: version is not part of user agent in web apps
if (versionIdentifier) {
result.version = versionIdentifier
}
}
else if (/sailfish/i.test(ua)) {
result = {
name: 'Sailfish'
, sailfish: t
, version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
}
}
else if (/seamonkey\//i.test(ua)) {
result = {
name: 'SeaMonkey'
, seamonkey: t
, version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
}
}
else if (/firefox|iceweasel/i.test(ua)) {
result = {
name: 'Firefox'
, firefox: t
, version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
}
if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
result.firefoxos = t
}
}
else if (/silk/i.test(ua)) {
result = {
name: 'Amazon Silk'
, silk: t
, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
}
}
else if (android) {
result = {
name: 'Android'
, version: versionIdentifier
}
}
else if (/phantom/i.test(ua)) {
result = {
name: 'PhantomJS'
, phantom: t
, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
}
}
else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
result = {
name: 'BlackBerry'
, blackberry: t
, version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
}
}
else if (/(web|hpw)os/i.test(ua)) {
result = {
name: 'WebOS'
, webos: t
, version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
};
/touchpad\//i.test(ua) && (result.touchpad = t)
}
else if (/bada/i.test(ua)) {
result = {
name: 'Bada'
, bada: t
, version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
};
}
else if (/tizen/i.test(ua)) {
result = {
name: 'Tizen'
, tizen: t
, version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
};
}
else if (/safari/i.test(ua)) {
result = {
name: 'Safari'
, safari: t
, version: versionIdentifier
}
}
else {
result = {
name: getFirstMatch(/^(.*)\/(.*) /),
version: getSecondMatch(/^(.*)\/(.*) /)
};
}
// set webkit or gecko flag for browsers based on these engines
if (!result.msedge && /(apple)?webkit/i.test(ua)) {
result.name = result.name || "Webkit"
result.webkit = t
if (!result.version && versionIdentifier) {
result.version = versionIdentifier
}
} else if (!result.opera && /gecko\//i.test(ua)) {
result.name = result.name || "Gecko"
result.gecko = t
result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
}
// set OS flags for platforms that have multiple browsers
if (!result.msedge && (android || result.silk)) {
result.android = t
} else if (iosdevice) {
result[iosdevice] = t
result.ios = t
}
// OS version extraction
var osVersion = '';
if (result.windowsphone) {
osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
} else if (iosdevice) {
osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
osVersion = osVersion.replace(/[_\s]/g, '.');
} else if (android) {
osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
} else if (result.webos) {
osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
} else if (result.blackberry) {
osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
} else if (result.bada) {
osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
} else if (result.tizen) {
osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
}
if (osVersion) {
result.osversion = osVersion;
}
// device type extraction
var osMajorVersion = osVersion.split('.')[0];
if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) {
result.tablet = t
} else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) {
result.mobile = t
}
// Graded Browser Support
// http://developer.yahoo.com/yui/articles/gbs
if (result.msedge ||
(result.msie && result.version >= 10) ||
(result.chrome && result.version >= 20) ||
(result.firefox && result.version >= 20.0) ||
(result.safari && result.version >= 6) ||
(result.opera && result.version >= 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
(result.blackberry && result.version >= 10.1)
) {
result.a = t;
}
else if ((result.msie && result.version < 10) ||
(result.chrome && result.version < 20) ||
(result.firefox && result.version < 20.0) ||
(result.safari && result.version < 6) ||
(result.opera && result.version < 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] < 6)
) {
result.c = t
} else result.x = t
return result
}
var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
bowser.test = function (browserList) {
for (var i = 0; i < browserList.length; ++i) {
var browserItem = browserList[i];
if (typeof browserItem=== 'string') {
if (browserItem in bowser) {
return true;
}
}
}
return false;
}
/*
* Set our detect method to the main bowser object so we can
* reuse it to test other user agents.
* This is needed to implement future tests.
*/
bowser._detect = detect;
return bowser
});
},{}],6:[function(require,module,exports){
/**
* This is the web browser implementation of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = require('./debug');
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = 'undefined' != typeof chrome
&& 'undefined' != typeof chrome.storage
? chrome.storage.local
: localstorage();
/**
* Colors.
*/
exports.colors = [
'lightseagreen',
'forestgreen',
'goldenrod',
'dodgerblue',
'darkorchid',
'crimson'
];
/**
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
function useColors() {
// is webkit? http://stackoverflow.com/a/16459606/376773
return ('WebkitAppearance' in document.documentElement.style) ||
// is firebug? http://stackoverflow.com/a/398120/376773
(window.console && (console.firebug || (console.exception && console.table))) ||
// is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
}
/**
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
*/
exports.formatters.j = function(v) {
return JSON.stringify(v);
};
/**
* Colorize log arguments if enabled.
*
* @api public
*/
function formatArgs() {
var args = arguments;
var useColors = this.useColors;
args[0] = (useColors ? '%c' : '')
+ this.namespace
+ (useColors ? ' %c' : ' ')
+ args[0]
+ (useColors ? '%c ' : ' ')
+ '+' + exports.humanize(this.diff);
if (!useColors) return args;
var c = 'color: ' + this.color;
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
// the final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
var index = 0;
var lastC = 0;
args[0].replace(/%[a-z%]/g, function(match) {
if ('%%' === match) return;
index++;
if ('%c' === match) {
// we only are interested in the *last* %c
// (the user may have provided their own)
lastC = index;
}
});
args.splice(lastC, 0, c);
return args;
}
/**
* Invokes `console.log()` when available.
* No-op when `console.log` is not a "function".
*
* @api public
*/
function log() {
// this hackery is required for IE8/9, where
// the `console.log` function doesn't have 'apply'
return 'object' === typeof console
&& console.log
&& Function.prototype.apply.call(console.log, console, arguments);
}
/**
* Save `namespaces`.
*
* @param {String} namespaces
* @api private
*/
function save(namespaces) {
try {
if (null == namespaces) {
exports.storage.removeItem('debug');
} else {
exports.storage.debug = namespaces;
}
} catch(e) {}
}
/**
* Load `namespaces`.
*
* @return {String} returns the previously persisted debug modes
* @api private
*/
function load() {
var r;
try {
r = exports.storage.debug;
} catch(e) {}
return r;
}
/**
* Enable namespaces listed in `localStorage.debug` initially.
*/
exports.enable(load());
/**
* Localstorage attempts to return the localstorage.
*
* This is necessary because safari throws
* when a user disables cookies/localstorage
* and you attempt to access it.
*
* @return {LocalStorage}
* @api private
*/
function localstorage(){
try {
return window.localStorage;
} catch (e) {}
}
},{"./debug":7}],7:[function(require,module,exports){
/**
* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*
* Expose `debug()` as the module.
*/
exports = module.exports = debug;
exports.coerce = coerce;
exports.disable = disable;
exports.enable = enable;
exports.enabled = enabled;
exports.humanize = require('ms');
/**
* The currently active debug mode names, and names to skip.
*/
exports.names = [];
exports.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lowercased letter, i.e. "n".
*/
exports.formatters = {};
/**
* Previously assigned color.
*/
var prevColor = 0;
/**
* Previous log timestamp.
*/
var prevTime;
/**
* Select a color.
*
* @return {Number}
* @api private
*/
function selectColor() {
return exports.colors[prevColor++ % exports.colors.length];
}
/**
* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/
function debug(namespace) {
// define the `disabled` version
function disabled() {
}
disabled.enabled = false;
// define the `enabled` version
function enabled() {
var self = enabled;
// set `diff` timestamp
var curr = +new Date();
var ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
// add the `color` if not set
if (null == self.useColors) self.useColors = exports.useColors();
if (null == self.color && self.useColors) self.color = selectColor();
var args = Array.prototype.slice.call(arguments);
args[0] = exports.coerce(args[0]);
if ('string' !== typeof args[0]) {
// anything else let's inspect with %o
args = ['%o'].concat(args);
}
// apply any `formatters` transformations
var index = 0;
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
// if we encounter an escaped % then don't increase the array index
if (match === '%%') return match;
index++;
var formatter = exports.formatters[format];
if ('function' === typeof formatter) {
var val = args[index];
match = formatter.call(self, val);
// now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
if ('function' === typeof exports.formatArgs) {
args = exports.formatArgs.apply(self, args);
}
var logFn = enabled.log || exports.log || console.log.bind(console);
logFn.apply(self, args);
}
enabled.enabled = true;
var fn = exports.enabled(namespace) ? enabled : disabled;
fn.namespace = namespace;
return fn;
}
/**
* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/
function enable(namespaces) {
exports.save(namespaces);
var split = (namespaces || '').split(/[\s,]+/);
var len = split.length;
for (var i = 0; i < len; i++) {
if (!split[i]) continue; // ignore empty strings
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
} else {
exports.names.push(new RegExp('^' + namespaces + '$'));
}
}
}
/**
* Disable debug output.
*
* @api public
*/
function disable() {
exports.enable('');
}
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
function enabled(name) {
var i, len;
for (i = 0, len = exports.skips.length; i < len; i++) {
if (exports.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = exports.names.length; i < len; i++) {
if (exports.names[i].test(name)) {
return true;
}
}
return false;
}
/**
* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/
function coerce(val) {
if (val instanceof Error) return val.stack || val.message;
return val;
}
},{"ms":8}],8:[function(require,module,exports){
/**
* Helpers.
*/
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} options
* @return {String|Number}
* @api public
*/
module.exports = function(val, options){
options = options || {};
if ('string' == typeof val) return parse(val);
return options.long
? long(val)
: short(val);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = '' + str;
if (str.length > 10000) return;
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
if (!match) return;
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function short(ms) {
if (ms >= d) return Math.round(ms / d) + 'd';
if (ms >= h) return Math.round(ms / h) + 'h';
if (ms >= m) return Math.round(ms / m) + 'm';
if (ms >= s) return Math.round(ms / s) + 's';
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function long(ms) {
return plural(ms, d, 'day')
|| plural(ms, h, 'hour')
|| plural(ms, m, 'minute')
|| plural(ms, s, 'second')
|| ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, n, name) {
if (ms < n) return;
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
return Math.ceil(ms / n) + ' ' + name + 's';
}
},{}],9:[function(require,module,exports){
/*!
* @name JavaScript/NodeJS Merge v1.2.0
* @author yeikos
* @repository https://github.com/yeikos/js.merge
* Copyright 2014 yeikos - MIT license
* https://raw.github.com/yeikos/js.merge/master/LICENSE
*/
;(function(isNode) {
/**
* Merge one or more objects
* @param bool? clone
* @param mixed,... arguments
* @return object
*/
var Public = function(clone) {
return merge(clone === true, false, arguments);
}, publicName = 'merge';
/**
* Merge two or more objects recursively
* @param bool? clone
* @param mixed,... arguments
* @return object
*/
Public.recursive = function(clone) {
return merge(clone === true, true, arguments);
};
/**
* Clone the input removing any reference
* @param mixed input
* @return mixed
*/
Public.clone = function(input) {
var output = input,
type = typeOf(input),
index, size;
if (type === 'array') {
output = [];
size = input.length;
for (index=0;index (http://eface2face.com)",
"contributors": [
"Jesús Pérez "
],
"license": "MIT",
"main": "lib/rtcninja.js",
"homepage": "https://github.com/eface2face/rtcninja.js",
"repository": {
"type": "git",
"url": "https://github.com/eface2face/rtcninja.js.git"
},
"keywords": [
"webrtc"
],
"engines": {
"node": ">=0.10.32"
},
"dependencies": {
"bowser": "^0.7.3",
"debug": "^2.2.0",
"merge": "^1.2.0"
},
"devDependencies": {
"browserify": "^10.2.3",
"gulp": "git+https://github.com/gulpjs/gulp.git#4.0",
"gulp-expect-file": "0.0.7",
"gulp-filelog": "^0.4.1",
"gulp-header": "^1.2.2",
"gulp-jscs": "^1.6.0",
"gulp-jscs-stylish": "^1.1.0",
"gulp-jshint": "^1.11.0",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.2.0",
"jshint-stylish": "^1.0.2",
"retire": "^1.1.0",
"shelljs": "^0.5.0",
"vinyl-source-stream": "^1.1.0"
}
}
},{}]},{},[3])(3)
}); rtcninja.js-0.6.2/dist/rtcninja.min.js 0000664 0000000 0000000 00000061354 12544264443 0017656 0 ustar 00root root 0000000 0000000 /*
* rtcninja.js v0.6.2
* WebRTC API wrapper to deal with different browsers
* Copyright 2015 Iñaki Baz Castillo (http://eface2face.com)
* License MIT
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.rtcninja=e()}}(function(){var e;return function t(e,n,i){function o(a,s){if(!n[a]){if(!e[a]){var c="function"==typeof require&&require;if(!s&&c)return c(a,!0);if(r)return r(a,!0);var d=new Error("Cannot find module '"+a+"'");throw d.code="MODULE_NOT_FOUND",d}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,i)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a=32||a.android&&a.chrome&&v>=39||b&&a.opera&&v>=27||a.android&&a.opera&&v>=24||a.android&&a.webkit&&!a.chrome&&v>=37||r.webkitGetUserMedia&&o.webkitRTCPeerConnection)C=!0,d=r.webkitGetUserMedia.bind(r),l=o.webkitRTCPeerConnection,u=o.RTCSessionDescription,p=o.RTCIceCandidate,g=o.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=function(e,t){return e.src=URL.createObjectURL(t),e},h=!0,y=!1;else if(b&&a.firefox&&v>=22||a.android&&a.firefox&&v>=33||r.mozGetUserMedia&&o.mozRTCPeerConnection)C=!0,d=r.mozGetUserMedia.bind(r),l=o.mozRTCPeerConnection,u=o.mozRTCSessionDescription,p=o.mozRTCIceCandidate,g=o.MediaStreamTrack,m=function(e,t){return e.src=URL.createObjectURL(t),e},h=!1,y=!1;else if(e.plugin&&"function"==typeof e.plugin.isRequired&&e.plugin.isRequired()&&"function"==typeof e.plugin.isInstalled&&e.plugin.isInstalled()){var n=e.plugin["interface"];C=!0,d=n.getUserMedia,l=n.RTCPeerConnection,u=n.RTCSessionDescription,p=n.RTCIceCandidate,g=n.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=n.attachMediaStream,h=n.canRenegotiate,y=!0}else r.getUserMedia&&o.RTCPeerConnection&&(C=!0,d=r.getUserMedia.bind(r),l=o.RTCPeerConnection,u=o.RTCSessionDescription,p=o.RTCIceCandidate,g=o.MediaStreamTrack,g&&g.getSources?f=g.getSources.bind(g):r.getMediaDevices&&(f=r.getMediaDevices.bind(r)),m=o.attachMediaStream||function(e,t){return e.src=URL.createObjectURL(t),e},h=!1,y=!1);return i.hasWebRTC=function(){return C},i.getUserMedia=d?function(e,t,n){s("getUserMedia() | constraints: %o",e);try{d(e,function(e){s("getUserMedia() | success"),t&&t(e)},function(e){s("getUserMedia() | error:",e),n&&n(e)})}catch(i){c("getUserMedia() | error:",i),n&&n(i)}}:function(e,n,i){c("getUserMedia() | WebRTC not supported"),i?i(new Error("rtcninja: WebRTC not supported, missing getUserMedia [browser: "+a.name+" "+a.version+"]")):t("getUserMedia")},i.RTCPeerConnection=l||t("RTCPeerConnection"),i.RTCSessionDescription=u||t("RTCSessionDescription"),i.RTCIceCandidate=p||t("RTCIceCandidate"),i.MediaStreamTrack=g||t("MediaStreamTrack"),i.getMediaDevices=f,i.attachMediaStream=m||t("attachMediaStream"),i.canRenegotiate=h,i.closeMediaStream=function(e){if(e)if(g&&g.prototype&&g.prototype.stop){s("closeMediaStream() | calling stop() on all the MediaStreamTrack");var t,n,i;if(e.getTracks)for(t=e.getTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop();else{for(t=e.getAudioTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop();for(t=e.getVideoTracks(),n=0,i=t.length;i>n;n+=1)t[n].stop()}}else"function"==typeof e.stop&&(s("closeMediaStream() | calling stop() on the MediaStream"),e.stop())},i.fixPeerConnectionConfig=function(e){var t,n,i,o,r;for(Array.isArray(e.iceServers)||(e.iceServers=[]),t=0,n=e.iceServers.length;n>t;t+=1)i=e.iceServers[t],o=i.hasOwnProperty("urls"),r=i.hasOwnProperty("url"),"object"==typeof i&&(o&&!r?i.url=Array.isArray(i.urls)?i.urls[0]:i.urls:!o&&r&&(i.urls=Array.isArray(i.url)?i.url.slice():i.url),r&&Array.isArray(i.url)&&(i.url=i.url[0]))},i.fixRTCOfferOptions=function(e){e=e||{},y?(e.offerToReceiveAudio&&(e.mandatory=e.mandatory||{},e.mandatory.OfferToReceiveAudio=!0),e.offerToReceiveVideo&&(e.mandatory=e.mandatory||{},e.mandatory.OfferToReceiveVideo=!0)):(e.mandatory&&e.mandatory.OfferToReceiveAudio&&(e.offerToReceiveAudio=1),e.mandatory&&e.mandatory.OfferToReceiveVideo&&(e.offerToReceiveVideo=1),delete e.mandatory)},i}t.exports=i;var o,r,a=e("bowser").browser,s=e("debug")("rtcninja:Adapter"),c=e("debug")("rtcninja:ERROR:Adapter"),d=null,l=null,u=null,p=null,g=null,f=null,m=null,h=!1,y=!1,v=Number(a.version)||0,b=!(a.mobile&&a.tablet),C=!1;c.log=console.warn.bind(console),o=n.window||n,r=o.navigator||{}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{bowser:5,debug:6}],2:[function(e,t,n){"use strict";function i(e,t){u("new | pcConfig: %o",e),o.call(this,e),this.pcConstraints=t,this.ourLocalDescription=null,this.ourSignalingState=null,this.ourIceConnectionState=null,this.ourIceGatheringState=null,this.timerGatheringTimeout=null,this.timerGatheringTimeoutAfterRelay=null,this.ignoreIceGathering=!1,this.closed=!1,s.call(this),d.call(this)}function o(e){this.pcConfig=l(!0,e),g.fixPeerConnectionConfig(this.pcConfig),this.options={iceTransportsRelay:"relay"===this.pcConfig.iceTransports,iceTransportsNone:"none"===this.pcConfig.iceTransports,gatheringTimeout:this.pcConfig.gatheringTimeout,gatheringTimeoutAfterRelay:this.pcConfig.gatheringTimeoutAfterRelay},delete this.pcConfig.gatheringTimeout,delete this.pcConfig.gatheringTimeoutAfterRelay,u("setConfigurationAndOptions | processed pcConfig: %o",this.pcConfig)}function r(){return this.closed||this.pc&&"closed"===this.pc.iceConnectionState}function a(){var e=this,t=this.pc;t.onnegotiationneeded=function(t){r.call(e)||(u("onnegotiationneeded()"),e.onnegotiationneeded&&e.onnegotiationneeded(t))},t.onicecandidate=function(t){var n,i,o;if(!r.call(e)&&!e.ignoreIceGathering&&!e.options.iceTransportsNone)if(n=t.candidate){if(i=f.REGEXP_RELAY_CANDIDATE.test(n.candidate),e.options.iceTransportsRelay&&!i)return;i&&!e.timerGatheringTimeoutAfterRelay&&"number"==typeof e.options.gatheringTimeoutAfterRelay&&(u("onicecandidate() | first relay candidate found, ending gathering in %d ms",e.options.gatheringTimeoutAfterRelay),e.timerGatheringTimeoutAfterRelay=setTimeout(function(){r.call(e)||(u("forced end of candidates after timeout"),delete e.timerGatheringTimeoutAfterRelay,clearTimeout(e.timerGatheringTimeout),delete e.timerGatheringTimeout,e.ignoreIceGathering=!0,e.onicecandidate&&e.onicecandidate({candidate:null},null))},e.options.gatheringTimeoutAfterRelay)),o=new g.RTCIceCandidate({sdpMid:n.sdpMid,sdpMLineIndex:n.sdpMLineIndex,candidate:n.candidate}),null===m.normalizeCandidate&&(f.REGEXP_NORMALIZED_CANDIDATE.test(n.candidate)?m.normalizeCandidate=!1:(u('onicecandidate() | normalizing ICE candidates syntax (remove "a=" and "\\r\\n")'),m.normalizeCandidate=!0)),m.normalizeCandidate&&(o.candidate=n.candidate.replace(f.REGEXP_FIX_CANDIDATE,"")),u("onicecandidate() | m%d(%s) %s",o.sdpMLineIndex,o.sdpMid||"no mid",o.candidate),e.onicecandidate&&e.onicecandidate(t,o)}else u("onicecandidate() | end of candidates"),clearTimeout(e.timerGatheringTimeout),delete e.timerGatheringTimeout,clearTimeout(e.timerGatheringTimeoutAfterRelay),delete e.timerGatheringTimeoutAfterRelay,e.onicecandidate&&e.onicecandidate(t,null)},t.onaddstream=function(t){r.call(e)||(u("onaddstream() | stream: %o",t.stream),e.onaddstream&&e.onaddstream(t,t.stream))},t.onremovestream=function(t){r.call(e)||(u("onremovestream() | stream: %o",t.stream),e.onremovestream&&e.onremovestream(t,t.stream))},t.ondatachannel=function(t){r.call(e)||(u("ondatachannel() | datachannel: %o",t.channel),e.ondatachannel&&e.ondatachannel(t,t.channel))},t.onsignalingstatechange=function(n){t.signalingState!==e.ourSignalingState&&(u("onsignalingstatechange() | signalingState: %s",t.signalingState),e.ourSignalingState=t.signalingState,e.onsignalingstatechange&&e.onsignalingstatechange(n,t.signalingState))},t.oniceconnectionstatechange=function(n){t.iceConnectionState!==e.ourIceConnectionState&&(u("oniceconnectionstatechange() | iceConnectionState: %s",t.iceConnectionState),e.ourIceConnectionState=t.iceConnectionState,e.oniceconnectionstatechange&&e.oniceconnectionstatechange(n,t.iceConnectionState))},t.onicegatheringstatechange=function(n){r.call(e)||t.iceGatheringState!==e.ourIceGatheringState&&(u("onicegatheringstatechange() | iceGatheringState: %s",t.iceGatheringState),e.ourIceGatheringState=t.iceGatheringState,e.onicegatheringstatechange&&e.onicegatheringstatechange(n,t.iceGatheringState))},t.onidentityresult=function(t){r.call(e)||(u("onidentityresult()"),e.onidentityresult&&e.onidentityresult(t))},t.onpeeridentity=function(t){r.call(e)||(u("onpeeridentity()"),e.onpeeridentity&&e.onpeeridentity(t))},t.onidpassertionerror=function(t){r.call(e)||(u("onidpassertionerror()"),e.onidpassertionerror&&e.onidpassertionerror(t))},t.onidpvalidationerror=function(t){r.call(e)||(u("onidpvalidationerror()"),e.onidpvalidationerror&&e.onidpvalidationerror(t))}}function s(){this.pc=this.pcConstraints?new g.RTCPeerConnection(this.pcConfig,this.pcConstraints):new g.RTCPeerConnection(this.pcConfig),a.call(this)}function c(){var e=this.pc,t=this.options,n=null;return e.localDescription?(t.iceTransportsRelay?n=e.localDescription.sdp.replace(f.REGEXP_SDP_NON_RELAY_CANDIDATES,""):t.iceTransportsNone&&(n=e.localDescription.sdp.replace(f.REGEXP_SDP_CANDIDATES,"")),this.ourLocalDescription=new g.RTCSessionDescription({type:e.localDescription.type,sdp:n||e.localDescription.sdp}),this.ourLocalDescription):(this.ourLocalDescription=null,null)}function d(){var e=this;Object.defineProperties(this,{peerConnection:{get:function(){return e.pc}},signalingState:{get:function(){return e.pc.signalingState}},iceConnectionState:{get:function(){return e.pc.iceConnectionState}},iceGatheringState:{get:function(){return e.pc.iceGatheringState}},localDescription:{get:function(){return c.call(e)}},remoteDescription:{get:function(){return e.pc.remoteDescription}},peerIdentity:{get:function(){return e.pc.peerIdentity}}})}t.exports=i;var l=e("merge"),u=e("debug")("rtcninja:RTCPeerConnection"),p=e("debug")("rtcninja:ERROR:RTCPeerConnection"),g=e("./Adapter"),f={REGEXP_NORMALIZED_CANDIDATE:new RegExp(/^candidate:/i),REGEXP_FIX_CANDIDATE:new RegExp(/(^a=|\r|\n)/gi),REGEXP_RELAY_CANDIDATE:new RegExp(/ relay /i),REGEXP_SDP_CANDIDATES:new RegExp(/^a=candidate:.*\r\n/gim),REGEXP_SDP_NON_RELAY_CANDIDATES:new RegExp(/^a=candidate:(.(?!relay ))*\r\n/gim)},m={normalizeCandidate:null};p.log=console.warn.bind(console),i.prototype.createOffer=function(e,t,n){u("createOffer()");var i=this;g.fixRTCOfferOptions(n),this.pc.createOffer(function(t){r.call(i)||(u("createOffer() | success"),e&&e(t))},function(e){r.call(i)||(p("createOffer() | error:",e),t&&t(e))},n)},i.prototype.createAnswer=function(e,t,n){u("createAnswer()");var i=this;this.pc.createAnswer(function(t){r.call(i)||(u("createAnswer() | success"),e&&e(t))},function(e){r.call(i)||(p("createAnswer() | error:",e),t&&t(e))},n)},i.prototype.setLocalDescription=function(e,t,n){function i(){"number"==typeof o.options.gatheringTimeout&&"complete"!==o.pc.iceGatheringState&&(u("setLocalDescription() | ending gathering in %d ms (gatheringTimeout option)",o.options.gatheringTimeout),o.timerGatheringTimeout=setTimeout(function(){r.call(o)||(u("forced end of candidates after gatheringTimeout timeout"),delete o.timerGatheringTimeout,clearTimeout(o.timerGatheringTimeoutAfterRelay),delete o.timerGatheringTimeoutAfterRelay,o.ignoreIceGathering=!0,o.onicecandidate&&o.onicecandidate({candidate:null},null))},o.options.gatheringTimeout))}u("setLocalDescription()");var o=this;this.pc.setLocalDescription(e,function(){r.call(o)||(u("setLocalDescription() | success"),clearTimeout(o.timerGatheringTimeout),delete o.timerGatheringTimeout,clearTimeout(o.timerGatheringTimeoutAfterRelay),delete o.timerGatheringTimeoutAfterRelay,i(),t&&t())},function(e){r.call(o)||(p("setLocalDescription() | error:",e),n&&n(e))}),this.ignoreIceGathering=!1},i.prototype.setRemoteDescription=function(e,t,n){u("setRemoteDescription()");var i=this;this.pc.setRemoteDescription(e,function(){r.call(i)||(u("setRemoteDescription() | success"),t&&t())},function(e){r.call(i)||(p("setRemoteDescription() | error:",e),n&&n(e))})},i.prototype.updateIce=function(e){u("updateIce() | pcConfig: %o",e),o.call(this,e),this.pc.updateIce(this.pcConfig),this.ignoreIceGathering=!1},i.prototype.addIceCandidate=function(e,t,n){u("addIceCandidate() | candidate: %o",e);var i=this;this.pc.addIceCandidate(e,function(){r.call(i)||(u("addIceCandidate() | success"),t&&t())},function(e){r.call(i)||(p("addIceCandidate() | error:",e),n&&n(e))})},i.prototype.getConfiguration=function(){return u("getConfiguration()"),this.pc.getConfiguration()},i.prototype.getLocalStreams=function(){return u("getLocalStreams()"),this.pc.getLocalStreams()},i.prototype.getRemoteStreams=function(){return u("getRemoteStreams()"),this.pc.getRemoteStreams()},i.prototype.getStreamById=function(e){return u("getStreamById() | streamId: %s",e),this.pc.getStreamById(e)},i.prototype.addStream=function(e){u("addStream() | stream: %s",e),this.pc.addStream(e)},i.prototype.removeStream=function(e){u("removeStream() | stream: %o",e),this.pc.removeStream(e)},i.prototype.close=function(){u("close()"),this.closed=!0,clearTimeout(this.timerGatheringTimeout),delete this.timerGatheringTimeout,clearTimeout(this.timerGatheringTimeoutAfterRelay),delete this.timerGatheringTimeoutAfterRelay,this.pc.close()},i.prototype.createDataChannel=function(){return u("createDataChannel()"),this.pc.createDataChannel.apply(this.pc,arguments)},i.prototype.createDTMFSender=function(e){return u("createDTMFSender()"),this.pc.createDTMFSender(e)},i.prototype.getStats=function(){return u("getStats()"),this.pc.getStats.apply(this.pc,arguments)},i.prototype.setIdentityProvider=function(){return u("setIdentityProvider()"),this.pc.setIdentityProvider.apply(this.pc,arguments)},i.prototype.getIdentityAssertion=function(){return u("getIdentityAssertion()"),this.pc.getIdentityAssertion()},i.prototype.reset=function(e){u("reset() | pcConfig: %o",e);var t=this.pc;t.onnegotiationneeded=null,t.onicecandidate=null,t.onaddstream=null,t.onremovestream=null,t.ondatachannel=null,t.onsignalingstatechange=null,t.oniceconnectionstatechange=null,t.onicegatheringstatechange=null,t.onidentityresult=null,t.onpeeridentity=null,t.onidpassertionerror=null,t.onidpvalidationerror=null,clearTimeout(this.timerGatheringTimeout),delete this.timerGatheringTimeout,clearTimeout(this.timerGatheringTimeoutAfterRelay),delete this.timerGatheringTimeoutAfterRelay,u("reset() | closing current peerConnection"),t.close(),o.call(this,e),s.call(this)}},{"./Adapter":1,debug:6,merge:9}],3:[function(e,t,n){"use strict";function i(e){var t=c(e||{});return l=!0,i.RTCPeerConnection=d,i.getUserMedia=t.getUserMedia,i.RTCSessionDescription=t.RTCSessionDescription,i.RTCIceCandidate=t.RTCIceCandidate,i.MediaStreamTrack=t.MediaStreamTrack,i.getMediaDevices=t.getMediaDevices,i.attachMediaStream=t.attachMediaStream,i.closeMediaStream=t.closeMediaStream,i.canRenegotiate=t.canRenegotiate,t.hasWebRTC()?(r("WebRTC supported"),!0):(a("WebRTC not supported"),!1)}t.exports=i;var o=e("bowser").browser,r=e("debug")("rtcninja"),a=e("debug")("rtcninja:ERROR"),s=e("./version"),c=e("./Adapter"),d=e("./RTCPeerConnection"),l=!1;a.log=console.warn.bind(console),r("version %s",s),r("detected browser: %s %s [mobile:%s, tablet:%s, android:%s, ios:%s]",o.name,o.version,!!o.mobile,!!o.tablet,!!o.android,!!o.ios),i.hasWebRTC=function(){return l||i(),c.hasWebRTC()},Object.defineProperty(i,"version",{get:function(){return s}}),Object.defineProperty(i,"called",{get:function(){return l}}),i.debug=e("debug"),i.browser=o},{"./Adapter":1,"./RTCPeerConnection":2,"./version":4,bowser:5,debug:6}],4:[function(e,t,n){"use strict";t.exports=e("../package.json").version},{"../package.json":10}],5:[function(t,n,i){!function(t,i){"undefined"!=typeof n&&n.exports?n.exports.browser=i():"function"==typeof e&&e.amd?e(i):this[t]=i()}("bowser",function(){function e(e){function n(t){var n=e.match(t);return n&&n.length>1&&n[1]||""}function i(t){var n=e.match(t);return n&&n.length>1&&n[2]||""}var o,r=n(/(ipod|iphone|ipad)/i).toLowerCase(),a=/like android/i.test(e),s=!a&&/android/i.test(e),c=n(/edge\/(\d+(\.\d+)?)/i),d=n(/version\/(\d+(\.\d+)?)/i),l=/tablet/i.test(e),u=!l&&/[^-]mobi/i.test(e);/opera|opr/i.test(e)?o={name:"Opera",opera:t,version:d||n(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)}:/windows phone/i.test(e)?(o={name:"Windows Phone",windowsphone:t},c?(o.msedge=t,o.version=c):(o.msie=t,o.version=n(/iemobile\/(\d+(\.\d+)?)/i))):/msie|trident/i.test(e)?o={name:"Internet Explorer",msie:t,version:n(/(?:msie |rv:)(\d+(\.\d+)?)/i)}:/chrome.+? edge/i.test(e)?o={name:"Microsoft Edge",msedge:t,version:c}:/chrome|crios|crmo/i.test(e)?o={name:"Chrome",chrome:t,version:n(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)}:r?(o={name:"iphone"==r?"iPhone":"ipad"==r?"iPad":"iPod"},d&&(o.version=d)):/sailfish/i.test(e)?o={name:"Sailfish",sailfish:t,version:n(/sailfish\s?browser\/(\d+(\.\d+)?)/i)}:/seamonkey\//i.test(e)?o={name:"SeaMonkey",seamonkey:t,version:n(/seamonkey\/(\d+(\.\d+)?)/i)}:/firefox|iceweasel/i.test(e)?(o={name:"Firefox",firefox:t,version:n(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)},/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(e)&&(o.firefoxos=t)):/silk/i.test(e)?o={name:"Amazon Silk",silk:t,version:n(/silk\/(\d+(\.\d+)?)/i)}:s?o={name:"Android",version:d}:/phantom/i.test(e)?o={name:"PhantomJS",phantom:t,version:n(/phantomjs\/(\d+(\.\d+)?)/i)}:/blackberry|\bbb\d+/i.test(e)||/rim\stablet/i.test(e)?o={name:"BlackBerry",blackberry:t,version:d||n(/blackberry[\d]+\/(\d+(\.\d+)?)/i)}:/(web|hpw)os/i.test(e)?(o={name:"WebOS",webos:t,version:d||n(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)},/touchpad\//i.test(e)&&(o.touchpad=t)):o=/bada/i.test(e)?{name:"Bada",bada:t,version:n(/dolfin\/(\d+(\.\d+)?)/i)}:/tizen/i.test(e)?{name:"Tizen",tizen:t,version:n(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i)||d}:/safari/i.test(e)?{name:"Safari",safari:t,version:d}:{name:n(/^(.*)\/(.*) /),version:i(/^(.*)\/(.*) /)},!o.msedge&&/(apple)?webkit/i.test(e)?(o.name=o.name||"Webkit",o.webkit=t,!o.version&&d&&(o.version=d)):!o.opera&&/gecko\//i.test(e)&&(o.name=o.name||"Gecko",o.gecko=t,o.version=o.version||n(/gecko\/(\d+(\.\d+)?)/i)),o.msedge||!s&&!o.silk?r&&(o[r]=t,o.ios=t):o.android=t;var p="";o.windowsphone?p=n(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i):r?(p=n(/os (\d+([_\s]\d+)*) like mac os x/i),p=p.replace(/[_\s]/g,".")):s?p=n(/android[ \/-](\d+(\.\d+)*)/i):o.webos?p=n(/(?:web|hpw)os\/(\d+(\.\d+)*)/i):o.blackberry?p=n(/rim\stablet\sos\s(\d+(\.\d+)*)/i):o.bada?p=n(/bada\/(\d+(\.\d+)*)/i):o.tizen&&(p=n(/tizen[\/\s](\d+(\.\d+)*)/i)),p&&(o.osversion=p);var g=p.split(".")[0];return l||"ipad"==r||s&&(3==g||4==g&&!u)||o.silk?o.tablet=t:(u||"iphone"==r||"ipod"==r||s||o.blackberry||o.webos||o.bada)&&(o.mobile=t),o.msedge||o.msie&&o.version>=10||o.chrome&&o.version>=20||o.firefox&&o.version>=20||o.safari&&o.version>=6||o.opera&&o.version>=10||o.ios&&o.osversion&&o.osversion.split(".")[0]>=6||o.blackberry&&o.version>=10.1?o.a=t:o.msie&&o.version<10||o.chrome&&o.version<20||o.firefox&&o.version<20||o.safari&&o.version<6||o.opera&&o.version<10||o.ios&&o.osversion&&o.osversion.split(".")[0]<6?o.c=t:o.x=t,o}var t=!0,n=e("undefined"!=typeof navigator?navigator.userAgent:"");return n.test=function(e){for(var t=0;t=31}function o(){var e=arguments,t=this.useColors;if(e[0]=(t?"%c":"")+this.namespace+(t?" %c":" ")+e[0]+(t?"%c ":" ")+"+"+n.humanize(this.diff),!t)return e;var i="color: "+this.color;e=[e[0],i,"color: inherit"].concat(Array.prototype.slice.call(e,1));var o=0,r=0;return e[0].replace(/%[a-z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(r=o))}),e.splice(r,0,i),e}function r(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function a(e){try{null==e?n.storage.removeItem("debug"):n.storage.debug=e}catch(t){}}function s(){var e;try{e=n.storage.debug}catch(t){}return e}function c(){try{return window.localStorage}catch(e){}}n=t.exports=e("./debug"),n.log=r,n.formatArgs=o,n.save=a,n.load=s,n.useColors=i,n.storage="undefined"!=typeof chrome&&"undefined"!=typeof chrome.storage?chrome.storage.local:c(),n.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],n.formatters.j=function(e){return JSON.stringify(e)},n.enable(s())},{"./debug":7}],7:[function(e,t,n){function i(){return n.colors[l++%n.colors.length]}function o(e){function t(){}function o(){var e=o,t=+new Date,r=t-(d||t);e.diff=r,e.prev=d,e.curr=t,d=t,null==e.useColors&&(e.useColors=n.useColors()),null==e.color&&e.useColors&&(e.color=i());var a=Array.prototype.slice.call(arguments);a[0]=n.coerce(a[0]),"string"!=typeof a[0]&&(a=["%o"].concat(a));var s=0;a[0]=a[0].replace(/%([a-z%])/g,function(t,i){if("%%"===t)return t;s++;var o=n.formatters[i];if("function"==typeof o){var r=a[s];t=o.call(e,r),a.splice(s,1),s--}return t}),"function"==typeof n.formatArgs&&(a=n.formatArgs.apply(e,a));var c=o.log||n.log||console.log.bind(console);c.apply(e,a)}t.enabled=!1,o.enabled=!0;var r=n.enabled(e)?o:t;return r.namespace=e,r}function r(e){n.save(e);for(var t=(e||"").split(/[\s,]+/),i=t.length,o=0;i>o;o++)t[o]&&(e=t[o].replace(/\*/g,".*?"),"-"===e[0]?n.skips.push(new RegExp("^"+e.substr(1)+"$")):n.names.push(new RegExp("^"+e+"$")))}function a(){n.enable("")}function s(e){var t,i;for(t=0,i=n.skips.length;i>t;t++)if(n.skips[t].test(e))return!1;for(t=0,i=n.names.length;i>t;t++)if(n.names[t].test(e))return!0;return!1}function c(e){return e instanceof Error?e.stack||e.message:e}n=t.exports=o,n.coerce=c,n.disable=a,n.enable=r,n.enabled=s,n.humanize=e("ms"),n.names=[],n.skips=[],n.formatters={};var d,l=0},{ms:8}],8:[function(e,t,n){function i(e){if(e=""+e,!(e.length>1e4)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var n=parseFloat(t[1]),i=(t[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return n*u;case"days":case"day":case"d":return n*l;case"hours":case"hour":case"hrs":case"hr":case"h":return n*d;case"minutes":case"minute":case"mins":case"min":case"m":return n*c;case"seconds":case"second":case"secs":case"sec":case"s":return n*s;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return n}}}}function o(e){return e>=l?Math.round(e/l)+"d":e>=d?Math.round(e/d)+"h":e>=c?Math.round(e/c)+"m":e>=s?Math.round(e/s)+"s":e+"ms"}function r(e){return a(e,l,"day")||a(e,d,"hour")||a(e,c,"minute")||a(e,s,"second")||e+" ms"}function a(e,t,n){return t>e?void 0:1.5*t>e?Math.floor(e/t)+" "+n:Math.ceil(e/t)+" "+n+"s"}var s=1e3,c=60*s,d=60*c,l=24*d,u=365.25*l;t.exports=function(e,t){return t=t||{},"string"==typeof e?i(e):t["long"]?r(e):o(e)}},{}],9:[function(e,t,n){!function(e){function n(e,t){if("object"!==o(e))return t;for(var i in t)e[i]="object"===o(e[i])&&"object"===o(t[i])?n(e[i],t[i]):t[i];return e}function i(e,t,i){var a=i[0],s=i.length;(e||"object"!==o(a))&&(a={});for(var c=0;s>c;++c){var d=i[c],l=o(d);if("object"===l)for(var u in d){var p=e?r.clone(d[u]):d[u];a[u]=t?n(a[u],p):p}}return a}function o(e){return{}.toString.call(e).slice(8,-1).toLowerCase()}var r=function(e){return i(e===!0,!1,arguments)},a="merge";r.recursive=function(e){return i(e===!0,!0,arguments)},r.clone=function(e){var t,n,i=e,a=o(e);if("array"===a)for(i=[],n=e.length,t=0;n>t;++t)i[t]=r.clone(e[t]);else if("object"===a){i={};for(t in e)i[t]=r.clone(e[t])}return i},e?t.exports=r:window[a]=r}("object"==typeof t&&t&&"object"==typeof t.exports&&t.exports)},{}],10:[function(e,t,n){t.exports={name:"rtcninja",version:"0.6.2",description:"WebRTC API wrapper to deal with different browsers",author:"Iñaki Baz Castillo (http://eface2face.com)",contributors:["Jesús Pérez "],license:"MIT",main:"lib/rtcninja.js",homepage:"https://github.com/eface2face/rtcninja.js",repository:{type:"git",url:"https://github.com/eface2face/rtcninja.js.git"},keywords:["webrtc"],engines:{node:">=0.10.32"},dependencies:{bowser:"^0.7.3",debug:"^2.2.0",merge:"^1.2.0"},devDependencies:{browserify:"^10.2.3",gulp:"git+https://github.com/gulpjs/gulp.git#4.0","gulp-expect-file":"0.0.7","gulp-filelog":"^0.4.1","gulp-header":"^1.2.2","gulp-jscs":"^1.6.0","gulp-jscs-stylish":"^1.1.0","gulp-jshint":"^1.11.0","gulp-rename":"^1.2.2","gulp-uglify":"^1.2.0","jshint-stylish":"^1.0.2",retire:"^1.1.0",shelljs:"^0.5.0","vinyl-source-stream":"^1.1.0"}}},{}]},{},[3])(3)}); rtcninja.js-0.6.2/docs/ 0000775 0000000 0000000 00000000000 12544264443 0014702 5 ustar 00root root 0000000 0000000 rtcninja.js-0.6.2/docs/RTCPeerConnection.md 0000664 0000000 0000000 00000006441 12544264443 0020515 0 ustar 00root root 0000000 0000000 # `rtcninja.RTCPeerConnection` Class API
The `rtcninja.RTCPeerConnection` class wrappes a native `(webkit|moz)RTCPeerConnection` and attempts to provide a uniform behavior across different WebRTC implementations. The provided API mimics the `RTCPeerConnection` API in the latest [WebRTC draft](http://w3c.github.io/webrtc-pc/).
### Features
* Normalization of the `pcConfig.iceServers` field (it deals with both the deprecated `url` field and the new `urls` one).
* Filtering of certain events once the `RTCPeerConnection` is closed. For example, old versions of Firefox fire `onicecandidate` or `onaddstream` events even after `close()` is called.
* Filtering of duplicate events. For example, some old browsers fire consecutive `oniceconnectionstatechange` events having the `iceConnectionState` attribute the same value in them.
* Normalization of the ICE candidate syntax. In some old browsers the `candidate` String in a `RTCIceCandidate` object contains incorrect "a=" and "\r\n". Those chars are removed.
* Addition of the `pcConfig.iceTransports` field in browsers not supporting it.
### `new rtcninja.RTCPeerConnection(pcConfig)` constructor
#### `pcConfig` {Object} param
Mandatory Object holding the [`RTCConfiguration`](http://w3c.github.io/webrtc-pc/#idl-def-RTCConfiguration) dictionary of the `RTCPeerConnection`. Some features not implemented in some browsers (such a Firefox) are implemented in JavaScript (such as `iceTransports`).
There are also custom options not present in the WebRTC specification:
* `gatheringTimeout` {Number}: ICE gathering is terminated after the given time (milliseconds) and a faked `onicecandidate` event with `candidate = null` is fired. No more `onicecandidate` events are fired once this timeout.
* `gatheringTimeoutAfterRelay` {Number}: Once the first "relay" (TURN) candidate is gathered, ICE gathering is terminated after the given time (milliseconds) and a faked `onicecandidate` event with `candidate = null` is fired. No more `onicecandidate` events are fired once this timeout.
### RTCPeerConnection API
`rtcninja.RTCPeerConnection` provides the same functions and attributes as described in the latest WebRTC draft for the `RTCPeerConnection` class. There are a few exceptions:
#### Events
All the native `RTCPeerConnection` events are fired with a single `event` argument of type `Event`. Events in `rtcninja.RTCPeerConnection` are full compatible with the original ones, but some of them also provide a second argument:
* `onicecandidate(event, candidate)`: Second argument is the normalized `event.candidate` field.
* `onaddstream(event, stream)`
* `onremovestream(event, stream)`
* `ondatachannel(event, channel)`
* `onsignalingstatechange(event, signalingState)`
* `oniceconnectionstatechange(event, iceConnectionState)`
* `onicegatheringstatechange(event, iceGatheringState)`
### `reset(pcConfig)` function
By calling `reset()` on a `rtcninja.RTCPeerConnection` instance the native `RTCPeerConnection` is silently closed (no events are fired) and a new `RTCPeerConnection` is created. No local stream is attached to it (must be done by the application).
*NOTE:* This is just useful in case the remote peer does **also** reset its `RTCPeerConnection`. Otherwise a new SDP renegotiation would fail.
#### `pcConfig` {Object} param
Same as in the `RTCPeerConnection` construtor.
rtcninja.js-0.6.2/docs/index.md 0000664 0000000 0000000 00000000176 12544264443 0016337 0 ustar 00root root 0000000 0000000 # API Documentation
* [`rtcninja` Module API](rtcninja.md)
* [`rtcninja.RTCPeerConnection` Class API](RTCPeerConnection.md)
rtcninja.js-0.6.2/docs/rtcninja.md 0000664 0000000 0000000 00000004247 12544264443 0017043 0 ustar 00root root 0000000 0000000 # `rtcninja` Module API
### `rtcninja()` function
By calling the library as a function it performs the WebRTC check in the browser. This function MUST be called before attempting to use the library.
It returns `true` if the browser supports WebRTC.
### `rtcninja.hasWebRTC()` function
Returns `true` if the browser supports WebRTC.
### `rtcninja.called` read attribute
Returns `true` if `rtcninja()` was already called.
### `rtcninja.version` read attribute
Returns a String with the version of the library.
```javascript
rtcninja.version
=> "X.Y.Z"
```
### `rtcninja.debug`
Provides access to the [debug](https://github.com/visionmedia/debug) module.
### `rtcninja.getUserMedia(constraints, successCallback, errorCallback)` function
Provides a wrapper over the native `navigator.(webkit|moz)getUserMedia()` function. As a feature, if WebRTC is not supported this function fires the given `errorCallback` instead of throwing an error.
### `rtcninja.getMediaDevices(successCallback)` function
Provides a wrapper over the native `navigator.getMediaDevices()` or `MediaStreamTrack.getSources()`.
**NOTE:** This method does not exist (`rtcninja.getMediaDevices === undefined`) if the browser does not support any of the native implementations to get the list of media devices.
### `rtcninja.RTCPeerConnection` class
Provides access to the [`rtcninja.RTCPeerConnection`](RTCPeerConnection.md) class, which wrappes a native `(webkit|moz)RTCPeerConnection`.
### `rtcninja.RTCSessionDescription` class
Wrapper for the native `RTCSessionDescription` class.
### `rtcninja.RTCIceCandidate` class
Wrapper for the native `RTCIceCandidate` class.
### `rtcninja.MediaStreamTrack` class
Wrapper for the native `MediaStreamTrack` class.
### `rtcninja.attachMediaStream(element, stream)` function
Sets the given `stream` (of type `MediaStream`) as the source of the `