Adds IE support through Temasys WebRTC plugin.
This commit is contained in:
parent
cd6928d770
commit
ae759fab5b
5
app.js
5
app.js
|
@ -21,14 +21,11 @@ var APP =
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|
||||||
|
APP.desktopsharing.init();
|
||||||
APP.RTC.start();
|
APP.RTC.start();
|
||||||
APP.xmpp.start();
|
APP.xmpp.start();
|
||||||
APP.statistics.start();
|
APP.statistics.start();
|
||||||
APP.connectionquality.init();
|
APP.connectionquality.init();
|
||||||
|
|
||||||
// Set default desktop sharing method
|
|
||||||
APP.desktopsharing.init();
|
|
||||||
|
|
||||||
APP.keyboardshortcut.init();
|
APP.keyboardshortcut.init();
|
||||||
APP.members.start();
|
APP.members.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,28 +60,31 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#remoteVideos .videocontainer:hover {
|
#remoteVideos .videocontainer:hover {
|
||||||
-webkit-box-shadow: inset 0 0 10px #FFFFFF, 0 0 10px #FFFFFF;
|
box-shadow: inset 0 0 10px #FFFFFF, 0 0 10px #FFFFFF;
|
||||||
border: 2px solid #FFFFFF;
|
border: 2px solid #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
#remoteVideos .videocontainer.videoContainerFocused {
|
#remoteVideos .videocontainer.videoContainerFocused {
|
||||||
-webkit-box-shadow: inset 0 0 28px #006d91;
|
box-shadow: inset 0 0 28px #006d91;
|
||||||
border: 2px solid #006d91;
|
border: 2px solid #006d91;
|
||||||
}
|
}
|
||||||
|
|
||||||
#remoteVideos .videocontainer.videoContainerFocused:hover {
|
#remoteVideos .videocontainer.videoContainerFocused:hover {
|
||||||
-webkit-box-shadow: inset 0 0 5px #FFFFFF, 0 0 10px #FFFFFF, inset 0 0 60px #006d91;
|
box-shadow: inset 0 0 5px #FFFFFF, 0 0 10px #FFFFFF, inset 0 0 60px #006d91;
|
||||||
border: 2px solid #FFFFFF;
|
border: 2px solid #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
#localVideoWrapper {
|
#localVideoWrapper {
|
||||||
display:inline-block;
|
display:inline-block;
|
||||||
-webkit-mask-box-image: url(../images/videomask.svg);
|
-webkit-mask-box-image: url(../images/videomask.svg);
|
||||||
border-radius:0px !important;
|
border-radius:4px !important;
|
||||||
border: 0px !important;
|
border: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#remoteVideos .videocontainer>video {
|
/* With TemasysWebRTC plugin <object/> element is used
|
||||||
|
instead of <video/> */
|
||||||
|
#remoteVideos .videocontainer>video,
|
||||||
|
#remoteVideos .videocontainer>object {
|
||||||
border-radius:4px;
|
border-radius:4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,8 +95,9 @@
|
||||||
-o-transform: scale(-1, 1);
|
-o-transform: scale(-1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#localVideoWrapper>video {
|
#localVideoWrapper>video,
|
||||||
border-radius:0px !important;
|
#localVideoWrapper>object {
|
||||||
|
border-radius:4px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#largeVideo,
|
#largeVideo,
|
||||||
|
@ -110,8 +114,10 @@
|
||||||
#presentation,
|
#presentation,
|
||||||
#etherpad,
|
#etherpad,
|
||||||
#localVideoWrapper>video,
|
#localVideoWrapper>video,
|
||||||
|
#localVideoWrapper>object,
|
||||||
#localVideoWrapper,
|
#localVideoWrapper,
|
||||||
.videocontainer>video {
|
.videocontainer>video,
|
||||||
|
.videocontainer>object {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
@ -363,7 +369,7 @@
|
||||||
margin-right: 40%;
|
margin-right: 40%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background: linear-gradient(to bottom, rgba(255,255,255,.85) , rgba(255,255,255,.35));
|
background: linear-gradient(to bottom, rgba(255,255,255,.85) , rgba(255,255,255,.35));
|
||||||
-webkit-box-shadow: 0 0 2px #000000, 0 0 10px #000000;
|
box-shadow: 0 0 2px #000000, 0 0 10px #000000;
|
||||||
border-bottom-left-radius: 12px;
|
border-bottom-left-radius: 12px;
|
||||||
border-bottom-right-radius: 12px;
|
border-bottom-right-radius: 12px;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
|
||||||
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
|
||||||
<script src="interface_config.js?v=5"></script>
|
<script src="interface_config.js?v=5"></script>
|
||||||
<script src="libs/app.bundle.js?v=98"></script>
|
<script src="libs/app.bundle.js?v=99"></script>
|
||||||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||||
<link rel="stylesheet" href="css/font.css?v=7"/>
|
<link rel="stylesheet" href="css/font.css?v=7"/>
|
||||||
<link rel="stylesheet" href="css/toastr.css?v=1">
|
<link rel="stylesheet" href="css/toastr.css?v=1">
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=30"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=30"/>
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=17" id="videolayout_default"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=18" id="videolayout_default"/>
|
||||||
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
|
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
|
||||||
<link rel="stylesheet" href="css/modaldialog.css?v=3">
|
<link rel="stylesheet" href="css/modaldialog.css?v=3">
|
||||||
|
|
2387
libs/app.bundle.js
2387
libs/app.bundle.js
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,5 @@
|
||||||
var EventEmitter = require("events");
|
var EventEmitter = require("events");
|
||||||
|
var RTCBrowserType = require("./RTCBrowserType");
|
||||||
var RTCUtils = require("./RTCUtils.js");
|
var RTCUtils = require("./RTCUtils.js");
|
||||||
var LocalStream = require("./LocalStream.js");
|
var LocalStream = require("./LocalStream.js");
|
||||||
var DataChannels = require("./DataChannels");
|
var DataChannels = require("./DataChannels");
|
||||||
|
@ -99,7 +100,7 @@ var RTC = {
|
||||||
},
|
},
|
||||||
createRemoteStream: function (data, sid, thessrc) {
|
createRemoteStream: function (data, sid, thessrc) {
|
||||||
var remoteStream = new MediaStream(data, sid, thessrc,
|
var remoteStream = new MediaStream(data, sid, thessrc,
|
||||||
this.getBrowserType(), eventEmitter);
|
RTCBrowserType.getBrowserType(), eventEmitter);
|
||||||
var jid = data.peerjid || APP.xmpp.myJid();
|
var jid = data.peerjid || APP.xmpp.myJid();
|
||||||
if(!this.remoteStreams[jid]) {
|
if(!this.remoteStreams[jid]) {
|
||||||
this.remoteStreams[jid] = {};
|
this.remoteStreams[jid] = {};
|
||||||
|
@ -108,9 +109,6 @@ var RTC = {
|
||||||
eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
|
eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
|
||||||
return remoteStream;
|
return remoteStream;
|
||||||
},
|
},
|
||||||
getBrowserType: function () {
|
|
||||||
return this.rtcUtils.browser;
|
|
||||||
},
|
|
||||||
getPCConstraints: function () {
|
getPCConstraints: function () {
|
||||||
return this.rtcUtils.pc_constraints;
|
return this.rtcUtils.pc_constraints;
|
||||||
},
|
},
|
||||||
|
@ -133,6 +131,9 @@ var RTC = {
|
||||||
setVideoSrc: function (element, src) {
|
setVideoSrc: function (element, src) {
|
||||||
this.rtcUtils.setVideoSrc(element, src);
|
this.rtcUtils.setVideoSrc(element, src);
|
||||||
},
|
},
|
||||||
|
getVideoElementName: function () {
|
||||||
|
return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video';
|
||||||
|
},
|
||||||
dispose: function() {
|
dispose: function() {
|
||||||
if (this.rtcUtils) {
|
if (this.rtcUtils) {
|
||||||
this.rtcUtils = null;
|
this.rtcUtils = null;
|
||||||
|
@ -168,9 +169,22 @@ var RTC = {
|
||||||
DataChannels.handleSelectedEndpointEvent);
|
DataChannels.handleSelectedEndpointEvent);
|
||||||
APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
|
APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
|
||||||
DataChannels.handlePinnedEndpointEvent);
|
DataChannels.handlePinnedEndpointEvent);
|
||||||
this.rtcUtils = new RTCUtils(this);
|
|
||||||
this.rtcUtils.obtainAudioAndVideoPermissions(
|
// In case of IE we continue from 'onReady' callback
|
||||||
null, null, getMediaStreamUsage());
|
// passed to RTCUtils constructor. It will be invoked by Temasys plugin
|
||||||
|
// once it is initialized.
|
||||||
|
var onReady = function () {
|
||||||
|
eventEmitter.emit(RTCEvents.RTC_READY, true);
|
||||||
|
self.rtcUtils.obtainAudioAndVideoPermissions(
|
||||||
|
null, null, getMediaStreamUsage());
|
||||||
|
};
|
||||||
|
|
||||||
|
this.rtcUtils = new RTCUtils(this, onReady);
|
||||||
|
|
||||||
|
// Call onReady() if Temasys plugin is not used
|
||||||
|
if (!RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
onReady();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
muteRemoteVideoStream: function (jid, value) {
|
muteRemoteVideoStream: function (jid, value) {
|
||||||
var stream;
|
var stream;
|
||||||
|
@ -211,6 +225,10 @@ var RTC = {
|
||||||
callback();
|
callback();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// FIXME: Workaround for FF/IE/Safari
|
||||||
|
if (stream && stream.videoStream) {
|
||||||
|
stream = stream.videoStream;
|
||||||
|
}
|
||||||
var videoStream = this.rtcUtils.createStream(stream, true);
|
var videoStream = this.rtcUtils.createStream(stream, true);
|
||||||
this.localVideo = this.createLocalStream(videoStream, "video", true, type);
|
this.localVideo = this.createLocalStream(videoStream, "video", true, type);
|
||||||
// Stop the stream to trigger onended event for old stream
|
// Stop the stream to trigger onended event for old stream
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
|
||||||
|
var currentBrowser;
|
||||||
|
|
||||||
|
var browserVersion;
|
||||||
|
|
||||||
|
var RTCBrowserType = {
|
||||||
|
|
||||||
|
RTC_BROWSER_CHROME: "rtc_browser.chrome",
|
||||||
|
|
||||||
|
RTC_BROWSER_OPERA: "rtc_browser.opera",
|
||||||
|
|
||||||
|
RTC_BROWSER_FIREFOX: "rtc_browser.firefox",
|
||||||
|
|
||||||
|
RTC_BROWSER_IEXPLORER: "rtc_browser.iexplorer",
|
||||||
|
|
||||||
|
RTC_BROWSER_SAFARI: "rtc_browser.safari",
|
||||||
|
|
||||||
|
getBrowserType: function () {
|
||||||
|
return currentBrowser;
|
||||||
|
},
|
||||||
|
|
||||||
|
isChrome: function () {
|
||||||
|
return currentBrowser === RTCBrowserType.RTC_BROWSER_CHROME;
|
||||||
|
},
|
||||||
|
|
||||||
|
isOpera: function () {
|
||||||
|
return currentBrowser === RTCBrowserType.RTC_BROWSER_OPERA;
|
||||||
|
},
|
||||||
|
isFirefox: function () {
|
||||||
|
return currentBrowser === RTCBrowserType.RTC_BROWSER_FIREFOX;
|
||||||
|
},
|
||||||
|
|
||||||
|
isIExplorer: function () {
|
||||||
|
return currentBrowser === RTCBrowserType.RTC_BROWSER_IEXPLORER;
|
||||||
|
},
|
||||||
|
|
||||||
|
isSafari: function () {
|
||||||
|
return currentBrowser === RTCBrowserType.RTC_BROWSER_SAFARI;
|
||||||
|
},
|
||||||
|
isTemasysPluginUsed: function () {
|
||||||
|
return RTCBrowserType.isIExplorer() || RTCBrowserType.isSafari();
|
||||||
|
},
|
||||||
|
getFirefoxVersion: function () {
|
||||||
|
return RTCBrowserType.isFirefox() ? browserVersion : null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getChromeVersion: function () {
|
||||||
|
return RTCBrowserType.isChrome() ? browserVersion : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add version getters for other browsers when needed
|
||||||
|
};
|
||||||
|
|
||||||
|
// detectOpera() must be called before detectChrome() !!!
|
||||||
|
// otherwise Opera wil be detected as Chrome
|
||||||
|
function detectChrome() {
|
||||||
|
if (navigator.webkitGetUserMedia) {
|
||||||
|
currentBrowser = RTCBrowserType.RTC_BROWSER_CHROME;
|
||||||
|
var userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
// We can assume that user agent is chrome, because it's
|
||||||
|
// enforced when 'ext' streaming method is set
|
||||||
|
var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10);
|
||||||
|
console.log("This appears to be Chrome, ver: " + ver);
|
||||||
|
return ver;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectOpera() {
|
||||||
|
var userAgent = navigator.userAgent;
|
||||||
|
if (userAgent.match(/Opera|OPR/)) {
|
||||||
|
currentBrowser = RTCBrowserType.RTC_BROWSER_OPERA;
|
||||||
|
var version = userAgent.match(/(Opera|OPR) ?\/?(\d+)\.?/)[2];
|
||||||
|
console.info("This appears to be Opera, ver: " + version);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectFirefox() {
|
||||||
|
if (navigator.mozGetUserMedia) {
|
||||||
|
currentBrowser = RTCBrowserType.RTC_BROWSER_FIREFOX;
|
||||||
|
var version = parseInt(
|
||||||
|
navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
|
||||||
|
console.log('This appears to be Firefox, ver: ' + version);
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectSafari() {
|
||||||
|
if ((/^((?!chrome).)*safari/i.test(navigator.userAgent))) {
|
||||||
|
currentBrowser = RTCBrowserType.RTC_BROWSER_SAFARI;
|
||||||
|
console.info("This appears to be Safari");
|
||||||
|
// FIXME detect Safari version when needed
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectIE() {
|
||||||
|
var version;
|
||||||
|
var ua = window.navigator.userAgent;
|
||||||
|
|
||||||
|
var msie = ua.indexOf('MSIE ');
|
||||||
|
if (msie > 0) {
|
||||||
|
// IE 10 or older => return version number
|
||||||
|
version = parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
var trident = ua.indexOf('Trident/');
|
||||||
|
if (!version && trident > 0) {
|
||||||
|
// IE 11 => return version number
|
||||||
|
var rv = ua.indexOf('rv:');
|
||||||
|
version = parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
var edge = ua.indexOf('Edge/');
|
||||||
|
if (!version && edge > 0) {
|
||||||
|
// IE 12 => return version number
|
||||||
|
version = parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version) {
|
||||||
|
currentBrowser = RTCBrowserType.RTC_BROWSER_IEXPLORER;
|
||||||
|
console.info("This appears to be IExplorer, ver: " + version);
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectBrowser() {
|
||||||
|
var version;
|
||||||
|
var detectors = [
|
||||||
|
detectOpera,
|
||||||
|
detectChrome,
|
||||||
|
detectFirefox,
|
||||||
|
detectIE,
|
||||||
|
detectSafari
|
||||||
|
];
|
||||||
|
// Try all browser detectors
|
||||||
|
for (var i = 0; i < detectors.length; i++) {
|
||||||
|
version = detectors[i]();
|
||||||
|
if (version)
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
console.error("Failed to detect browser type");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
browserVersion = detectBrowser();
|
||||||
|
|
||||||
|
module.exports = RTCBrowserType;
|
|
@ -1,5 +1,7 @@
|
||||||
var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
|
var RTCBrowserType = require("./RTCBrowserType");
|
||||||
var Resolutions = require("../../service/RTC/Resolutions");
|
var Resolutions = require("../../service/RTC/Resolutions");
|
||||||
|
var AdapterJS = require("./adapter.screenshare");
|
||||||
|
var SDPUtil = require("../xmpp/SDPUtil");
|
||||||
|
|
||||||
var currentResolution = null;
|
var currentResolution = null;
|
||||||
|
|
||||||
|
@ -58,16 +60,30 @@ function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid
|
||||||
constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
|
constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
|
||||||
}
|
}
|
||||||
if (um.indexOf('screen') >= 0) {
|
if (um.indexOf('screen') >= 0) {
|
||||||
constraints.video = {
|
if (RTCBrowserType.isChrome()) {
|
||||||
mandatory: {
|
constraints.video = {
|
||||||
chromeMediaSource: "screen",
|
mandatory: {
|
||||||
googLeakyBucket: true,
|
chromeMediaSource: "screen",
|
||||||
maxWidth: window.screen.width,
|
googLeakyBucket: true,
|
||||||
maxHeight: window.screen.height,
|
maxWidth: window.screen.width,
|
||||||
maxFrameRate: 3
|
maxHeight: window.screen.height,
|
||||||
},
|
maxFrameRate: 3
|
||||||
optional: []
|
},
|
||||||
};
|
optional: []
|
||||||
|
};
|
||||||
|
} else if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
constraints.video = {
|
||||||
|
optional: [
|
||||||
|
{
|
||||||
|
sourceId: AdapterJS.WebRTCPlugin.plugin.screensharingKey
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
"'screen' WebRTC media source is supported only in Chrome" +
|
||||||
|
" and with Temasys plugin");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (um.indexOf('desktop') >= 0) {
|
if (um.indexOf('desktop') >= 0) {
|
||||||
constraints.video = {
|
constraints.video = {
|
||||||
|
@ -124,16 +140,14 @@ function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function RTCUtils(RTCService)
|
function RTCUtils(RTCService, onTemasysPluginReady)
|
||||||
{
|
{
|
||||||
|
var self = this;
|
||||||
this.service = RTCService;
|
this.service = RTCService;
|
||||||
if (navigator.mozGetUserMedia) {
|
if (RTCBrowserType.isFirefox()) {
|
||||||
console.log('This appears to be Firefox');
|
var FFversion = RTCBrowserType.getFirefoxVersion();
|
||||||
var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
|
if (FFversion >= 40 && config.useBundle && config.useRtcpMux) {
|
||||||
if (version >= 40
|
|
||||||
&& config.useBundle && config.useRtcpMux) {
|
|
||||||
this.peerconnection = mozRTCPeerConnection;
|
this.peerconnection = mozRTCPeerConnection;
|
||||||
this.browser = RTCBrowserType.RTC_BROWSER_FIREFOX;
|
|
||||||
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
|
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
|
||||||
this.pc_constraints = {};
|
this.pc_constraints = {};
|
||||||
this.attachMediaStream = function (element, stream) {
|
this.attachMediaStream = function (element, stream) {
|
||||||
|
@ -155,7 +169,7 @@ function RTCUtils(RTCService)
|
||||||
{
|
{
|
||||||
tracks = stream.getAudioTracks();
|
tracks = stream.getAudioTracks();
|
||||||
}
|
}
|
||||||
return tracks[0].id.replace(/[\{,\}]/g,"");
|
return SDPUtil.filter_special_chars(tracks[0].id);
|
||||||
};
|
};
|
||||||
this.getVideoSrc = function (element) {
|
this.getVideoSrc = function (element) {
|
||||||
if(!element)
|
if(!element)
|
||||||
|
@ -169,14 +183,16 @@ function RTCUtils(RTCService)
|
||||||
RTCSessionDescription = mozRTCSessionDescription;
|
RTCSessionDescription = mozRTCSessionDescription;
|
||||||
RTCIceCandidate = mozRTCIceCandidate;
|
RTCIceCandidate = mozRTCIceCandidate;
|
||||||
} else {
|
} else {
|
||||||
|
console.error(
|
||||||
|
"Firefox requirements not met, ver: " + FFversion +
|
||||||
|
", bundle: " + config.useBundle +
|
||||||
|
", rtcp-mux: " + config.useRtcpMux);
|
||||||
window.location.href = 'unsupported_browser.html';
|
window.location.href = 'unsupported_browser.html';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (navigator.webkitGetUserMedia) {
|
} else if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) {
|
||||||
console.log('This appears to be Chrome');
|
|
||||||
this.peerconnection = webkitRTCPeerConnection;
|
this.peerconnection = webkitRTCPeerConnection;
|
||||||
this.browser = RTCBrowserType.RTC_BROWSER_CHROME;
|
|
||||||
this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
|
this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
|
||||||
this.attachMediaStream = function (element, stream) {
|
this.attachMediaStream = function (element, stream) {
|
||||||
element.attr('src', webkitURL.createObjectURL(stream));
|
element.attr('src', webkitURL.createObjectURL(stream));
|
||||||
|
@ -184,7 +200,7 @@ function RTCUtils(RTCService)
|
||||||
this.getStreamID = function (stream) {
|
this.getStreamID = function (stream) {
|
||||||
// streams from FF endpoints have the characters '{' and '}'
|
// streams from FF endpoints have the characters '{' and '}'
|
||||||
// that make jQuery choke.
|
// that make jQuery choke.
|
||||||
return stream.id.replace(/[\{,\}]/g,"");
|
return SDPUtil.filter_special_chars(stream.id);
|
||||||
};
|
};
|
||||||
this.getVideoSrc = function (element) {
|
this.getVideoSrc = function (element) {
|
||||||
if(!element)
|
if(!element)
|
||||||
|
@ -211,12 +227,62 @@ function RTCUtils(RTCService)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
// Detect IE/Safari
|
||||||
{
|
else if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
|
|
||||||
|
|
||||||
|
AdapterJS.WebRTCPlugin.setLogLevel(
|
||||||
|
AdapterJS.WebRTCPlugin.PLUGIN_LOG_LEVELS.VERBOSE);
|
||||||
|
|
||||||
|
AdapterJS.webRTCReady(function (isPlugin) {
|
||||||
|
|
||||||
|
self.peerconnection = RTCPeerConnection;
|
||||||
|
self.getUserMedia = getUserMedia;
|
||||||
|
self.attachMediaStream = function (element, stream) {
|
||||||
|
|
||||||
|
if (stream.id === "dummyAudio" || stream.id === "dummyVideo") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachMediaStream(element[0], stream);
|
||||||
|
};
|
||||||
|
self.getStreamID = function (stream) {
|
||||||
|
var id = SDPUtil.filter_special_chars(stream.label);
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
self.getVideoSrc = function (element) {
|
||||||
|
if (!element) {
|
||||||
|
console.warn("Attempt to get video SRC of null element");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var src = null;
|
||||||
|
var children = element.children;
|
||||||
|
for (var i = 0; i !== children.length; ++i) {
|
||||||
|
if (children[i].name === 'streamId') {
|
||||||
|
return children[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.info(element.id + " SRC: " + src);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
self.setVideoSrc = function (element, src) {
|
||||||
|
//console.info("Set video src: ", element, src);
|
||||||
|
if (!src) {
|
||||||
|
console.warn("Not attaching video stream, 'src' is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AdapterJS.WebRTCPlugin.WaitForPluginReady();
|
||||||
|
var stream = AdapterJS.WebRTCPlugin.plugin
|
||||||
|
.getStreamWithId(AdapterJS.WebRTCPlugin.pageId, src);
|
||||||
|
attachMediaStream(element, stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
onTemasysPluginReady(isPlugin);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
console.log('Browser does not appear to be WebRTC-capable');
|
||||||
|
} catch (e) { }
|
||||||
window.location.href = 'unsupported_browser.html';
|
window.location.href = 'unsupported_browser.html';
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +298,7 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
|
||||||
var constraints = getConstraints(
|
var constraints = getConstraints(
|
||||||
um, resolution, bandwidth, fps, desktopStream, isAndroid);
|
um, resolution, bandwidth, fps, desktopStream, isAndroid);
|
||||||
|
|
||||||
var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
console.info("Get media constraints", constraints);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
@ -311,9 +377,9 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions =
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (navigator.mozGetUserMedia) {
|
if (RTCBrowserType.isFirefox() || RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
|
||||||
// With FF we can't split the stream into audio and video because FF
|
// With FF/IE we can't split the stream into audio and video because FF
|
||||||
// doesn't support media stream constructors. So, we need to get the
|
// doesn't support media stream constructors. So, we need to get the
|
||||||
// audio stream separately from the video stream using two distinct GUM
|
// audio stream separately from the video stream using two distinct GUM
|
||||||
// calls. Not very user friendly :-( but we don't have many other
|
// calls. Not very user friendly :-( but we don't have many other
|
||||||
|
@ -321,31 +387,41 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions =
|
||||||
//
|
//
|
||||||
// Note that we pack those 2 streams in a single object and pass it to
|
// Note that we pack those 2 streams in a single object and pass it to
|
||||||
// the successCallback method.
|
// the successCallback method.
|
||||||
|
var obtainVideo = function (audioStream) {
|
||||||
self.getUserMediaWithConstraints(
|
self.getUserMediaWithConstraints(
|
||||||
['audio'],
|
['video'],
|
||||||
function (audioStream) {
|
function (videoStream) {
|
||||||
self.getUserMediaWithConstraints(
|
return successCallback({
|
||||||
['video'],
|
audioStream: audioStream,
|
||||||
function (videoStream) {
|
videoStream: videoStream
|
||||||
return self.successCallback({
|
});
|
||||||
audioStream: audioStream,
|
},
|
||||||
videoStream: videoStream
|
function (error) {
|
||||||
});
|
console.error(
|
||||||
},
|
'failed to obtain video stream - stop', error);
|
||||||
function (error) {
|
self.errorCallback(error);
|
||||||
console.error('failed to obtain video stream - stop',
|
},
|
||||||
error);
|
config.resolution || '360');
|
||||||
return self.successCallback(null);
|
};
|
||||||
},
|
var obtainAudio = function () {
|
||||||
config.resolution || '360');
|
self.getUserMediaWithConstraints(
|
||||||
},
|
['audio'],
|
||||||
function (error) {
|
function (audioStream) {
|
||||||
console.error('failed to obtain audio stream - stop',
|
if (newDevices.indexOf('video') !== -1)
|
||||||
error);
|
obtainVideo(audioStream);
|
||||||
return self.successCallback(null);
|
},
|
||||||
}
|
function (error) {
|
||||||
);
|
console.error(
|
||||||
|
'failed to obtain audio stream - stop', error);
|
||||||
|
self.errorCallback(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if (newDevices.indexOf('audio') !== -1) {
|
||||||
|
obtainAudio();
|
||||||
|
} else {
|
||||||
|
obtainVideo(null);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.getUserMediaWithConstraints(
|
this.getUserMediaWithConstraints(
|
||||||
newDevices,
|
newDevices,
|
||||||
|
@ -358,12 +434,12 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions =
|
||||||
config.resolution || '360');
|
config.resolution || '360');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
RTCUtils.prototype.successCallback = function (stream, usageOptions) {
|
RTCUtils.prototype.successCallback = function (stream, usageOptions) {
|
||||||
// If this is FF, the stream parameter is *not* a MediaStream object, it's
|
// If this is FF or IE, the stream parameter is *not* a MediaStream object,
|
||||||
// an object with two properties: audioStream, videoStream.
|
// it's an object with two properties: audioStream, videoStream.
|
||||||
if(stream && !navigator.mozGetUserMedia)
|
if (stream && stream.getAudioTracks && stream.getVideoTracks)
|
||||||
console.log('got', stream, stream.getAudioTracks().length,
|
console.log('got', stream, stream.getAudioTracks().length,
|
||||||
stream.getVideoTracks().length);
|
stream.getVideoTracks().length);
|
||||||
this.handleLocalStream(stream, usageOptions);
|
this.handleLocalStream(stream, usageOptions);
|
||||||
|
@ -427,10 +503,17 @@ RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (RTCBrowserType.isFirefox() || RTCBrowserType.isTemasysPluginUsed())
|
||||||
{//firefox
|
{ // Firefox and Temasys plugin
|
||||||
audioStream = stream.audioStream;
|
if (stream && stream.audioStream)
|
||||||
videoStream = stream.videoStream;
|
audioStream = stream.audioStream;
|
||||||
|
else
|
||||||
|
audioStream = new DummyMediaStream("dummyAudio");
|
||||||
|
|
||||||
|
if (stream && stream.videoStream)
|
||||||
|
videoStream = stream.videoStream;
|
||||||
|
else
|
||||||
|
videoStream = new DummyMediaStream("dummyVideo");
|
||||||
}
|
}
|
||||||
|
|
||||||
var audioMuted = (usageOptions && usageOptions.audio === false),
|
var audioMuted = (usageOptions && usageOptions.audio === false),
|
||||||
|
@ -447,15 +530,20 @@ RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
|
||||||
videoMuted, videoGUM);
|
videoMuted, videoGUM);
|
||||||
};
|
};
|
||||||
|
|
||||||
RTCUtils.prototype.createStream = function(stream, isVideo)
|
function DummyMediaStream(id) {
|
||||||
{
|
this.id = id;
|
||||||
|
this.label = id;
|
||||||
|
this.stop = function() { };
|
||||||
|
this.getAudioTracks = function() { return []; }
|
||||||
|
this.getVideoTracks = function() { return []; }
|
||||||
|
}
|
||||||
|
|
||||||
|
RTCUtils.prototype.createStream = function(stream, isVideo) {
|
||||||
var newStream = null;
|
var newStream = null;
|
||||||
if(window.webkitMediaStream)
|
if (window.webkitMediaStream) {
|
||||||
{
|
|
||||||
newStream = new webkitMediaStream();
|
newStream = new webkitMediaStream();
|
||||||
if(newStream)
|
if (newStream) {
|
||||||
{
|
var tracks = (isVideo ? stream.getVideoTracks() : stream.getAudioTracks());
|
||||||
var tracks = (isVideo? stream.getVideoTracks() : stream.getAudioTracks());
|
|
||||||
|
|
||||||
for (i = 0; i < tracks.length; i++) {
|
for (i = 0; i < tracks.length; i++) {
|
||||||
newStream.addTrack(tracks[i]);
|
newStream.addTrack(tracks[i]);
|
||||||
|
@ -463,8 +551,14 @@ RTCUtils.prototype.createStream = function(stream, isVideo)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
newStream = stream;
|
// FIXME: this is duplicated with 'handleLocalStream' !!!
|
||||||
|
if (stream) {
|
||||||
|
newStream = stream;
|
||||||
|
} else {
|
||||||
|
newStream = new DummyMediaStream(isVideo ? "dummyVideo" : "dummyAudio");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newStream;
|
return newStream;
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,6 +24,7 @@ var CQEvents = require("../../service/connectionquality/CQEvents");
|
||||||
var DesktopSharingEventTypes
|
var DesktopSharingEventTypes
|
||||||
= require("../../service/desktopsharing/DesktopSharingEventTypes");
|
= require("../../service/desktopsharing/DesktopSharingEventTypes");
|
||||||
var RTCEvents = require("../../service/RTC/RTCEvents");
|
var RTCEvents = require("../../service/RTC/RTCEvents");
|
||||||
|
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||||
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
|
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
|
||||||
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
||||||
var MemberEvents = require("../../service/members/Events");
|
var MemberEvents = require("../../service/members/Events");
|
||||||
|
@ -253,7 +254,7 @@ function registerListeners() {
|
||||||
{
|
{
|
||||||
// might need to update the direction if participant just went from sendrecv to recvonly
|
// might need to update the direction if participant just went from sendrecv to recvonly
|
||||||
if (stream.type === 'video' || stream.type === 'screen') {
|
if (stream.type === 'video' || stream.type === 'screen') {
|
||||||
var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
|
var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>' + APP.RTC.getVideoElementName());
|
||||||
switch (stream.direction) {
|
switch (stream.direction) {
|
||||||
case 'sendrecv':
|
case 'sendrecv':
|
||||||
el.show();
|
el.show();
|
||||||
|
@ -405,7 +406,9 @@ UI.start = function (init) {
|
||||||
$('#notice').css({display: 'block'});
|
$('#notice').css({display: 'block'});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById('largeVideo').volume = 0;
|
if (!RTCBrowserType.isIExplorer()) {
|
||||||
|
document.getElementById('largeVideo').volume = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(config.requireDisplayName) {
|
if(config.requireDisplayName) {
|
||||||
var currentSettings = Settings.getSettings();
|
var currentSettings = Settings.getSettings();
|
||||||
|
|
|
@ -336,7 +336,10 @@ ConnectionIndicator.prototype.create = function () {
|
||||||
*/
|
*/
|
||||||
ConnectionIndicator.prototype.remove = function()
|
ConnectionIndicator.prototype.remove = function()
|
||||||
{
|
{
|
||||||
this.connectionIndicatorContainer.remove();
|
if (this.connectionIndicatorContainer.parentNode) {
|
||||||
|
this.connectionIndicatorContainer.parentNode.removeChild(
|
||||||
|
this.connectionIndicatorContainer);
|
||||||
|
}
|
||||||
this.popover.forceHide();
|
this.popover.forceHide();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
var Avatar = require("../avatar/Avatar");
|
var Avatar = require("../avatar/Avatar");
|
||||||
|
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||||
var UIUtil = require("../util/UIUtil");
|
var UIUtil = require("../util/UIUtil");
|
||||||
var UIEvents = require("../../../service/UI/UIEvents");
|
var UIEvents = require("../../../service/UI/UIEvents");
|
||||||
var xmpp = require("../../xmpp/xmpp");
|
var xmpp = require("../../xmpp/xmpp");
|
||||||
|
|
||||||
var video = $('#largeVideo');
|
// FIXME: With Temasys we have to re-select everytime
|
||||||
|
//var video = $('#largeVideo');
|
||||||
|
|
||||||
var currentVideoWidth = null;
|
var currentVideoWidth = null;
|
||||||
var currentVideoHeight = null;
|
var currentVideoHeight = null;
|
||||||
|
@ -244,9 +246,7 @@ function changeVideo(isVisible) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
// using "this" should be ok because we're called
|
$('#largeVideo').fadeIn(300);
|
||||||
// from within the fadeOut event.
|
|
||||||
$(this).fadeIn(300);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(oldSmallVideo)
|
if(oldSmallVideo)
|
||||||
|
@ -260,12 +260,16 @@ var LargeVideo = {
|
||||||
this.eventEmitter = emitter;
|
this.eventEmitter = emitter;
|
||||||
var self = this;
|
var self = this;
|
||||||
// Listen for large video size updates
|
// Listen for large video size updates
|
||||||
document.getElementById('largeVideo')
|
var largeVideo = $('#largeVideo')[0];
|
||||||
.addEventListener('loadedmetadata', function (e) {
|
var onplaying = function (arg1, arg2, arg3) {
|
||||||
currentVideoWidth = this.videoWidth;
|
// re-select
|
||||||
currentVideoHeight = this.videoHeight;
|
if (RTCBrowserType.isTemasysPluginUsed())
|
||||||
self.position(currentVideoWidth, currentVideoHeight);
|
largeVideo = $('#largeVideo')[0];
|
||||||
});
|
currentVideoWidth = largeVideo.videoWidth;
|
||||||
|
currentVideoHeight = largeVideo.videoHeight;
|
||||||
|
self.position(currentVideoWidth, currentVideoHeight);
|
||||||
|
};
|
||||||
|
largeVideo.onplaying = onplaying;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Indicates if the large video is currently visible.
|
* Indicates if the large video is currently visible.
|
||||||
|
@ -273,14 +277,14 @@ var LargeVideo = {
|
||||||
* @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
|
* @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
|
||||||
*/
|
*/
|
||||||
isLargeVideoVisible: function() {
|
isLargeVideoVisible: function() {
|
||||||
return video.is(':visible');
|
return $('#largeVideo').is(':visible');
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Updates the large video with the given new video source.
|
* Updates the large video with the given new video source.
|
||||||
*/
|
*/
|
||||||
updateLargeVideo: function(resourceJid, forceUpdate) {
|
updateLargeVideo: function(resourceJid, forceUpdate) {
|
||||||
console.log('hover in', resourceJid);
|
|
||||||
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
|
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
|
||||||
|
console.log('hover in ' + resourceJid + ', video: ', newSmallVideo);
|
||||||
|
|
||||||
if ((currentSmallVideo && currentSmallVideo.resourceJid !== resourceJid)
|
if ((currentSmallVideo && currentSmallVideo.resourceJid !== resourceJid)
|
||||||
|| forceUpdate) {
|
|| forceUpdate) {
|
||||||
|
@ -303,8 +307,8 @@ var LargeVideo = {
|
||||||
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
|
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
|
||||||
resourceJid);
|
resourceJid);
|
||||||
}
|
}
|
||||||
|
$('#largeVideo').fadeOut(300,
|
||||||
video.fadeOut(300, changeVideo.bind(video, this.isLargeVideoVisible()));
|
changeVideo.bind($('#largeVideo'), this.isLargeVideoVisible()));
|
||||||
} else {
|
} else {
|
||||||
if(currentSmallVideo) {
|
if(currentSmallVideo) {
|
||||||
currentSmallVideo.showAvatar();
|
currentSmallVideo.showAvatar();
|
||||||
|
|
|
@ -3,6 +3,7 @@ var ConnectionIndicator = require("./ConnectionIndicator");
|
||||||
var NicknameHandler = require("../util/NicknameHandler");
|
var NicknameHandler = require("../util/NicknameHandler");
|
||||||
var UIUtil = require("../util/UIUtil");
|
var UIUtil = require("../util/UIUtil");
|
||||||
var LargeVideo = require("./LargeVideo");
|
var LargeVideo = require("./LargeVideo");
|
||||||
|
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||||
|
|
||||||
function LocalVideo(VideoLayout)
|
function LocalVideo(VideoLayout)
|
||||||
{
|
{
|
||||||
|
@ -163,13 +164,18 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
function localVideoClick(event) {
|
function localVideoClick(event) {
|
||||||
event.stopPropagation();
|
// FIXME: with Temasys plugin event arg is not an event, but
|
||||||
|
// the clicked object itself, so we have to skip this call
|
||||||
|
if (event.stopPropagation) {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
self.VideoLayout.handleVideoThumbClicked(
|
self.VideoLayout.handleVideoThumbClicked(
|
||||||
false,
|
false,
|
||||||
APP.xmpp.myResource());
|
APP.xmpp.myResource());
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#localVideoContainer').click(localVideoClick);
|
$('#localVideoContainer').off('click');
|
||||||
|
$('#localVideoContainer').on('click', localVideoClick);
|
||||||
|
|
||||||
// Add hover handler
|
// Add hover handler
|
||||||
$('#localVideoContainer').hover(
|
$('#localVideoContainer').hover(
|
||||||
|
@ -192,8 +198,10 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||||
var localVideo = document.createElement('video');
|
var localVideo = document.createElement('video');
|
||||||
localVideo.id = 'localVideo_' +
|
localVideo.id = 'localVideo_' +
|
||||||
APP.RTC.getStreamID(stream.getOriginalStream());
|
APP.RTC.getStreamID(stream.getOriginalStream());
|
||||||
localVideo.autoplay = true;
|
if (!RTCBrowserType.isIExplorer()) {
|
||||||
localVideo.volume = 0; // is it required if audio is separated ?
|
localVideo.autoplay = true;
|
||||||
|
localVideo.volume = 0; // is it required if audio is separated ?
|
||||||
|
}
|
||||||
localVideo.oncontextmenu = function () { return false; };
|
localVideo.oncontextmenu = function () { return false; };
|
||||||
|
|
||||||
var localVideoContainer = document.getElementById('localVideoWrapper');
|
var localVideoContainer = document.getElementById('localVideoWrapper');
|
||||||
|
@ -203,7 +211,9 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||||
|
|
||||||
// Add click handler to both video and video wrapper elements in case
|
// Add click handler to both video and video wrapper elements in case
|
||||||
// there's no video.
|
// there's no video.
|
||||||
localVideoSelector.click(localVideoClick);
|
|
||||||
|
// onclick has to be used with Temasys plugin
|
||||||
|
localVideo.onclick = localVideoClick;
|
||||||
|
|
||||||
if (this.flipX) {
|
if (this.flipX) {
|
||||||
localVideoSelector.addClass("flipVideoX");
|
localVideoSelector.addClass("flipVideoX");
|
||||||
|
@ -214,6 +224,9 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
|
||||||
|
|
||||||
// Add stream ended handler
|
// Add stream ended handler
|
||||||
stream.getOriginalStream().onended = function () {
|
stream.getOriginalStream().onended = function () {
|
||||||
|
// We have to re-select after attach when Temasys plugin is used,
|
||||||
|
// because <video> element is replaced with <object>
|
||||||
|
localVideo = $('#' + localVideo.id)[0];
|
||||||
localVideoContainer.removeChild(localVideo);
|
localVideoContainer.removeChild(localVideo);
|
||||||
self.VideoLayout.updateRemovedVideo(APP.xmpp.myResource());
|
self.VideoLayout.updateRemovedVideo(APP.xmpp.myResource());
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ var SmallVideo = require("./SmallVideo");
|
||||||
var AudioLevels = require("../audio_levels/AudioLevels");
|
var AudioLevels = require("../audio_levels/AudioLevels");
|
||||||
var LargeVideo = require("./LargeVideo");
|
var LargeVideo = require("./LargeVideo");
|
||||||
var Avatar = require("../avatar/Avatar");
|
var Avatar = require("../avatar/Avatar");
|
||||||
|
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||||
|
|
||||||
function RemoteVideo(peerJid, VideoLayout)
|
function RemoteVideo(peerJid, VideoLayout)
|
||||||
{
|
{
|
||||||
|
@ -146,14 +147,15 @@ RemoteVideo.prototype.removeRemoteStreamElement = function (stream, isVideo, id)
|
||||||
select.remove();
|
select.remove();
|
||||||
|
|
||||||
var audioCount = $('#' + this.videoSpanId + '>audio').length;
|
var audioCount = $('#' + this.videoSpanId + '>audio').length;
|
||||||
var videoCount = $('#' + this.videoSpanId + '>video').length;
|
var videoCount = $('#' + this.videoSpanId + '>' + APP.RTC.getVideoElementName()).length;
|
||||||
|
|
||||||
if (!audioCount && !videoCount) {
|
if (!audioCount && !videoCount) {
|
||||||
console.log("Remove whole user", this.videoSpanId);
|
console.log("Remove whole user", this.videoSpanId);
|
||||||
if(this.connectionIndicator)
|
if(this.connectionIndicator)
|
||||||
this.connectionIndicator.remove();
|
this.connectionIndicator.remove();
|
||||||
// Remove whole container
|
// Remove whole container
|
||||||
this.container.remove();
|
if (this.container.parentNode)
|
||||||
|
this.container.parentNode.removeChild(this.container);
|
||||||
|
|
||||||
this.VideoLayout.resizeThumbnails();
|
this.VideoLayout.resizeThumbnails();
|
||||||
}
|
}
|
||||||
|
@ -185,11 +187,21 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
|
||||||
if (isVideo && stream.id !== 'mixedmslabel') {
|
if (isVideo && stream.id !== 'mixedmslabel') {
|
||||||
var onPlayingHandler = function () {
|
var onPlayingHandler = function () {
|
||||||
// FIXME: why do i have to do this for FF?
|
// FIXME: why do i have to do this for FF?
|
||||||
APP.RTC.attachMediaStream(sel, stream);
|
if (RTCBrowserType.isFirefox()) {
|
||||||
|
APP.RTC.attachMediaStream(sel, stream);
|
||||||
|
}
|
||||||
|
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
sel = $('#' + newElementId);
|
||||||
|
}
|
||||||
self.VideoLayout.videoactive(sel, self.resourceJid);
|
self.VideoLayout.videoactive(sel, self.resourceJid);
|
||||||
sel.off("playing", onPlayingHandler);
|
sel[0].onplaying = null;
|
||||||
|
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
// 'currentTime' is used to check if the video has started
|
||||||
|
// and the value is not set by the plugin, so we do it
|
||||||
|
sel[0].currentTime = 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
sel.on("playing", onPlayingHandler);
|
sel[0].onplaying = onPlayingHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
APP.RTC.attachMediaStream(sel, stream);
|
APP.RTC.attachMediaStream(sel, stream);
|
||||||
|
@ -203,23 +215,35 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Name of video element name is different for IE/Safari
|
||||||
|
var videoElem = APP.RTC.getVideoElementName();
|
||||||
|
|
||||||
// Add click handler.
|
// Add click handler.
|
||||||
this.container.onclick = function (event) {
|
var onClickHandler = function (event) {
|
||||||
/*
|
/*
|
||||||
* FIXME It turns out that videoThumb may not exist (if there is
|
* FIXME It turns out that videoThumb may not exist (if there is
|
||||||
* no actual video).
|
* no actual video).
|
||||||
*/
|
*/
|
||||||
var videoThumb = $('#' + self.videoSpanId + '>video').get(0);
|
var videoThumb = $('#' + self.videoSpanId + '>' + videoElem).get(0);
|
||||||
if (videoThumb) {
|
if (videoThumb) {
|
||||||
self.VideoLayout.handleVideoThumbClicked(
|
self.VideoLayout.handleVideoThumbClicked(
|
||||||
false,
|
false,
|
||||||
self.resourceJid);
|
self.resourceJid);
|
||||||
}
|
}
|
||||||
|
// On IE we need to populate this handler on video <object>
|
||||||
event.stopPropagation();
|
// and it does not give event instance as an argument,
|
||||||
event.preventDefault();
|
// so we check here for methods.
|
||||||
|
if (event.stopPropagation && event.preventDefault) {
|
||||||
|
event.stopPropagation();
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
this.container.onclick = onClickHandler;
|
||||||
|
// reselect
|
||||||
|
if (RTCBrowserType.isTemasysPluginUsed())
|
||||||
|
sel = $('#' + newElementId);
|
||||||
|
sel[0].onclick = onClickHandler;
|
||||||
|
|
||||||
//FIXME
|
//FIXME
|
||||||
// Add hover handler
|
// Add hover handler
|
||||||
|
@ -229,9 +253,9 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
|
||||||
},
|
},
|
||||||
function() {
|
function() {
|
||||||
var videoSrc = null;
|
var videoSrc = null;
|
||||||
if ($('#' + self.videoSpanId + '>video')
|
var videoSelector = $('#' + self.videoSpanId + '>' + videoElem);
|
||||||
&& $('#' + self.videoSpanId + '>video').length > 0) {
|
if (videoSelector && videoSelector.length > 0) {
|
||||||
videoSrc = APP.RTC.getVideoSrc($('#' + self.videoSpanId + '>video').get(0));
|
videoSrc = APP.RTC.getVideoSrc(videoSelector.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the video has been "pinned" by the user we want to
|
// If the video has been "pinned" by the user we want to
|
||||||
|
@ -241,7 +265,7 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
|
||||||
self.showDisplayName(false);
|
self.showDisplayName(false);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show/hide peer container for the given resourceJid.
|
* Show/hide peer container for the given resourceJid.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
var UIUtil = require("../util/UIUtil");
|
var UIUtil = require("../util/UIUtil");
|
||||||
var LargeVideo = require("./LargeVideo");
|
var LargeVideo = require("./LargeVideo");
|
||||||
|
var RTCBrowserType = require("../../RTC/RTCBrowserType");
|
||||||
|
|
||||||
function SmallVideo(){
|
function SmallVideo(){
|
||||||
this.isMuted = false;
|
this.isMuted = false;
|
||||||
|
@ -96,7 +97,9 @@ SmallVideo.createStreamElement = function (sid, stream) {
|
||||||
+ sid + '_' + APP.RTC.getStreamID(stream);
|
+ sid + '_' + APP.RTC.getStreamID(stream);
|
||||||
|
|
||||||
element.id = id;
|
element.id = id;
|
||||||
element.autoplay = true;
|
if (!RTCBrowserType.isIExplorer()) {
|
||||||
|
element.autoplay = true;
|
||||||
|
}
|
||||||
element.oncontextmenu = function () { return false; };
|
element.oncontextmenu = function () { return false; };
|
||||||
|
|
||||||
return element;
|
return element;
|
||||||
|
@ -204,7 +207,7 @@ SmallVideo.prototype.enableDominantSpeaker = function (isEnable)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var video = $('#' + this.videoSpanId + '>video');
|
var video = $('#' + this.videoSpanId + '>' + APP.RTC.getVideoElementName());
|
||||||
|
|
||||||
if (video && video.length > 0) {
|
if (video && video.length > 0) {
|
||||||
if (isEnable) {
|
if (isEnable) {
|
||||||
|
@ -275,8 +278,10 @@ SmallVideo.prototype.createModeratorIndicatorElement = function () {
|
||||||
|
|
||||||
|
|
||||||
SmallVideo.prototype.getSrc = function () {
|
SmallVideo.prototype.getSrc = function () {
|
||||||
return APP.RTC.getVideoSrc($('#' + this.videoSpanId).find("video").get(0));
|
var videoElement = APP.RTC.getVideoElementName();
|
||||||
}
|
return APP.RTC.getVideoSrc(
|
||||||
|
$('#' + this.videoSpanId).find(videoElement).get(0));
|
||||||
|
},
|
||||||
|
|
||||||
SmallVideo.prototype.focus = function(isFocused)
|
SmallVideo.prototype.focus = function(isFocused)
|
||||||
{
|
{
|
||||||
|
@ -290,7 +295,8 @@ SmallVideo.prototype.focus = function(isFocused)
|
||||||
}
|
}
|
||||||
|
|
||||||
SmallVideo.prototype.hasVideo = function () {
|
SmallVideo.prototype.hasVideo = function () {
|
||||||
return $("#" + this.videoSpanId).find("video").length !== 0;
|
return $("#" + this.videoSpanId).find(
|
||||||
|
APP.RTC.getVideoElementName()).length !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,7 +308,8 @@ SmallVideo.prototype.showAvatar = function (show) {
|
||||||
if(!this.hasAvatar)
|
if(!this.hasAvatar)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var video = $('#' + this.videoSpanId).find("video");
|
var videoElem = APP.RTC.getVideoElementName();
|
||||||
|
var video = $('#' + this.videoSpanId).find(videoElem);
|
||||||
var avatar = $('#avatar_' + this.resourceJid);
|
var avatar = $('#avatar_' + this.resourceJid);
|
||||||
|
|
||||||
if (show === undefined || show === null) {
|
if (show === undefined || show === null) {
|
||||||
|
|
|
@ -3,6 +3,10 @@ var Avatar = require("../avatar/Avatar");
|
||||||
var ContactList = require("../side_pannels/contactlist/ContactList");
|
var ContactList = require("../side_pannels/contactlist/ContactList");
|
||||||
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
|
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
|
||||||
var UIEvents = require("../../../service/UI/UIEvents");
|
var UIEvents = require("../../../service/UI/UIEvents");
|
||||||
|
|
||||||
|
var RTC = require("../../RTC/RTC");
|
||||||
|
var RTCBrowserType = require('../../RTC/RTCBrowserType');
|
||||||
|
|
||||||
var RemoteVideo = require("./RemoteVideo");
|
var RemoteVideo = require("./RemoteVideo");
|
||||||
var LargeVideo = require("./LargeVideo");
|
var LargeVideo = require("./LargeVideo");
|
||||||
var LocalVideo = require("./LocalVideo");
|
var LocalVideo = require("./LocalVideo");
|
||||||
|
@ -48,11 +52,15 @@ var VideoLayout = (function (my) {
|
||||||
};
|
};
|
||||||
|
|
||||||
my.changeLocalAudio = function(stream, isMuted) {
|
my.changeLocalAudio = function(stream, isMuted) {
|
||||||
if(isMuted)
|
if (isMuted)
|
||||||
APP.UI.setAudioMuted(true, true);
|
APP.UI.setAudioMuted(true, true);
|
||||||
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
|
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
|
||||||
document.getElementById('localAudio').autoplay = true;
|
var localAudio = document.getElementById('localAudio');
|
||||||
document.getElementById('localAudio').volume = 0;
|
// Writing volume not allowed in IE
|
||||||
|
if (!RTCBrowserType.isIExplorer()) {
|
||||||
|
localAudio.autoplay = true;
|
||||||
|
localAudio.volume = 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
my.changeLocalVideo = function(stream, isMuted) {
|
my.changeLocalVideo = function(stream, isMuted) {
|
||||||
|
@ -107,22 +115,26 @@ var VideoLayout = (function (my) {
|
||||||
* @param removedVideoSrc src stream identifier of the video.
|
* @param removedVideoSrc src stream identifier of the video.
|
||||||
*/
|
*/
|
||||||
my.updateRemovedVideo = function(resourceJid) {
|
my.updateRemovedVideo = function(resourceJid) {
|
||||||
|
|
||||||
|
var videoElem = RTC.getVideoElementName();
|
||||||
|
|
||||||
if (resourceJid === LargeVideo.getResourceJid()) {
|
if (resourceJid === LargeVideo.getResourceJid()) {
|
||||||
// this is currently displayed as large
|
// this is currently displayed as large
|
||||||
// pick the last visible video in the row
|
// pick the last visible video in the row
|
||||||
// if nobody else is left, this picks the local video
|
// if nobody else is left, this picks the local video
|
||||||
var pick
|
var pick
|
||||||
= $('#remoteVideos>span[id!="mixedstream"]:visible:last>video')
|
= $('#remoteVideos>' +
|
||||||
.get(0);
|
'span[id!="mixedstream"]:visible:last>' + videoElem).get(0);
|
||||||
|
|
||||||
if (!pick) {
|
if (!pick) {
|
||||||
console.info("Last visible video no longer exists");
|
console.info("Last visible video no longer exists");
|
||||||
pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
|
pick = $('#remoteVideos>' +
|
||||||
|
'span[id!="mixedstream"]>' + videoElem).get(0);
|
||||||
|
|
||||||
if (!pick || !APP.RTC.getVideoSrc(pick)) {
|
if (!pick || !APP.RTC.getVideoSrc(pick)) {
|
||||||
// Try local video
|
// Try local video
|
||||||
console.info("Fallback to local video...");
|
console.info("Fallback to local video...");
|
||||||
pick = $('#remoteVideos>span>span>video').get(0);
|
pick = $('#remoteVideos>span>span>' + videoElem).get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,10 +235,13 @@ var VideoLayout = (function (my) {
|
||||||
|
|
||||||
LargeVideo.updateLargeVideo(resourceJid);
|
LargeVideo.updateLargeVideo(resourceJid);
|
||||||
|
|
||||||
$('audio').each(function (idx, el) {
|
// Writing volume not allowed in IE
|
||||||
el.volume = 0;
|
if (!RTCBrowserType.isIExplorer()) {
|
||||||
el.volume = 1;
|
$('audio').each(function (idx, el) {
|
||||||
});
|
el.volume = 0;
|
||||||
|
el.volume = 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -452,7 +467,8 @@ var VideoLayout = (function (my) {
|
||||||
var resource = Strophe.getResourceFromJid(jid);
|
var resource = Strophe.getResourceFromJid(jid);
|
||||||
var videoContainer = $("#participant_" + resource);
|
var videoContainer = $("#participant_" + resource);
|
||||||
if (videoContainer.length > 0) {
|
if (videoContainer.length > 0) {
|
||||||
var videoThumb = $('video', videoContainer).get(0);
|
var videoThumb
|
||||||
|
= $(RTC.getVideoElementName(), videoContainer).get(0);
|
||||||
// It is not always the case that a videoThumb exists (if there is
|
// It is not always the case that a videoThumb exists (if there is
|
||||||
// no actual video).
|
// no actual video).
|
||||||
if (videoThumb) {
|
if (videoThumb) {
|
||||||
|
@ -571,7 +587,8 @@ var VideoLayout = (function (my) {
|
||||||
// since we don't want to switch to local video.
|
// since we don't want to switch to local video.
|
||||||
if (container && !focusedVideoResourceJid)
|
if (container && !focusedVideoResourceJid)
|
||||||
{
|
{
|
||||||
var video = container.getElementsByTagName("video");
|
var video
|
||||||
|
= container.getElementsByTagName(RTC.getVideoElementName());
|
||||||
|
|
||||||
// Update the large video if the video source is already available,
|
// Update the large video if the video source is already available,
|
||||||
// otherwise wait for the "videoactive.jingle" event.
|
// otherwise wait for the "videoactive.jingle" event.
|
||||||
|
@ -673,7 +690,8 @@ var VideoLayout = (function (my) {
|
||||||
|
|
||||||
var jid = APP.xmpp.findJidFromResource(resourceJid);
|
var jid = APP.xmpp.findJidFromResource(resourceJid);
|
||||||
var mediaStream = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
|
var mediaStream = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
|
||||||
var sel = $('#participant_' + resourceJid + '>video');
|
var sel = $('#participant_' + resourceJid +
|
||||||
|
'>' + RTC.getVideoElementName());
|
||||||
|
|
||||||
APP.RTC.attachMediaStream(sel, mediaStream.stream);
|
APP.RTC.attachMediaStream(sel, mediaStream.stream);
|
||||||
if (lastNPickupJid == mediaStream.peerjid) {
|
if (lastNPickupJid == mediaStream.peerjid) {
|
||||||
|
|
|
@ -31,13 +31,7 @@ var extInstalled = false;
|
||||||
*/
|
*/
|
||||||
var extUpdateRequired = false;
|
var extUpdateRequired = false;
|
||||||
|
|
||||||
/**
|
var AdapterJS = require("../RTC/adapter.screenshare");
|
||||||
* Flag used to cache desktop sharing enabled state. Do not use directly as
|
|
||||||
* it can be <tt>null</tt>.
|
|
||||||
*
|
|
||||||
* @type {null|boolean}
|
|
||||||
*/
|
|
||||||
var _desktopSharingEnabled = null;
|
|
||||||
|
|
||||||
var EventEmitter = require("events");
|
var EventEmitter = require("events");
|
||||||
|
|
||||||
|
@ -46,6 +40,10 @@ var eventEmitter = new EventEmitter();
|
||||||
var DesktopSharingEventTypes
|
var DesktopSharingEventTypes
|
||||||
= require("../../service/desktopsharing/DesktopSharingEventTypes");
|
= require("../../service/desktopsharing/DesktopSharingEventTypes");
|
||||||
|
|
||||||
|
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||||
|
|
||||||
|
var RTCEvents = require("../../service/RTC/RTCEvents");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method obtains desktop stream from WebRTC 'screen' source.
|
* Method obtains desktop stream from WebRTC 'screen' source.
|
||||||
* Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
|
* Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
|
||||||
|
@ -116,7 +114,7 @@ function isUpdateRequired(minVersion, extVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkExtInstalled(callback) {
|
function checkChromeExtInstalled(callback) {
|
||||||
if (!chrome.runtime) {
|
if (!chrome.runtime) {
|
||||||
// No API, so no extension for sure
|
// No API, so no extension for sure
|
||||||
callback(false, false);
|
callback(false, false);
|
||||||
|
@ -213,20 +211,39 @@ function obtainScreenFromExtension(streamCallback, failCallback) {
|
||||||
* feature completely.
|
* feature completely.
|
||||||
*/
|
*/
|
||||||
function setDesktopSharing(method) {
|
function setDesktopSharing(method) {
|
||||||
// Check if we are running chrome
|
|
||||||
if (!navigator.webkitGetUserMedia) {
|
obtainDesktopStream = null;
|
||||||
obtainDesktopStream = null;
|
|
||||||
console.info("Desktop sharing disabled");
|
// When TemasysWebRTC plugin is used we always use getUserMedia, so we don't
|
||||||
} else if (method == "ext") {
|
// care about 'method' parameter
|
||||||
obtainDesktopStream = obtainScreenFromExtension;
|
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
console.info("Using Chrome extension for desktop sharing");
|
if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
|
||||||
} else if (method == "webrtc") {
|
console.info("Screensharing not supported by this plugin version");
|
||||||
obtainDesktopStream = obtainWebRTCScreen;
|
} else if (!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) {
|
||||||
console.info("Using Chrome WebRTC for desktop sharing");
|
console.info(
|
||||||
|
"Screensharing not available with Temasys plugin on this site");
|
||||||
|
} else {
|
||||||
|
obtainDesktopStream = obtainWebRTCScreen;
|
||||||
|
console.info("Using Temasys plugin for desktop sharing");
|
||||||
|
}
|
||||||
|
} else if (RTCBrowserType.isChrome()) {
|
||||||
|
if (method == "ext") {
|
||||||
|
if (RTCBrowserType.getChromeVersion() >= 34) {
|
||||||
|
obtainDesktopStream = obtainScreenFromExtension;
|
||||||
|
console.info("Using Chrome extension for desktop sharing");
|
||||||
|
initChromeExtension();
|
||||||
|
} else {
|
||||||
|
console.info("Chrome extension not supported until ver 34");
|
||||||
|
}
|
||||||
|
} else if (method == "webrtc") {
|
||||||
|
obtainDesktopStream = obtainWebRTCScreen;
|
||||||
|
console.info("Using Chrome WebRTC for desktop sharing");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset enabled cache
|
if (!obtainDesktopStream) {
|
||||||
_desktopSharingEnabled = null;
|
console.info("Desktop sharing disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -239,6 +256,19 @@ function initInlineInstalls()
|
||||||
$("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
|
$("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initChromeExtension() {
|
||||||
|
// Initialize Chrome extension inline installs
|
||||||
|
initInlineInstalls();
|
||||||
|
// Check if extension is installed
|
||||||
|
checkChromeExtInstalled(function (installed, updateRequired) {
|
||||||
|
extInstalled = installed;
|
||||||
|
extUpdateRequired = updateRequired;
|
||||||
|
console.info(
|
||||||
|
"Chrome extension installed: " + extInstalled +
|
||||||
|
" updateRequired: " + extUpdateRequired);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getVideoStreamFailed(error) {
|
function getVideoStreamFailed(error) {
|
||||||
console.error("Failed to obtain the stream to switch to", error);
|
console.error("Failed to obtain the stream to switch to", error);
|
||||||
switchInProgress = false;
|
switchInProgress = false;
|
||||||
|
@ -264,6 +294,25 @@ function newStreamCreated(stream)
|
||||||
stream, isUsingScreenStream, streamSwitchDone);
|
stream, isUsingScreenStream, streamSwitchDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onEndedHandler(stream) {
|
||||||
|
if (!switchInProgress && isUsingScreenStream) {
|
||||||
|
APP.desktopsharing.toggleScreenSharing();
|
||||||
|
}
|
||||||
|
//FIXME: to be verified
|
||||||
|
if (stream.removeEventListener) {
|
||||||
|
stream.removeEventListener('ended', onEndedHandler);
|
||||||
|
} else {
|
||||||
|
stream.detachEvent('ended', onEndedHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when RTC finishes initialization
|
||||||
|
function onWebRtcReady() {
|
||||||
|
|
||||||
|
setDesktopSharing(config.desktopSharing);
|
||||||
|
|
||||||
|
eventEmitter.emit(DesktopSharingEventTypes.INIT);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isUsingScreenStream: function () {
|
isUsingScreenStream: function () {
|
||||||
|
@ -274,43 +323,10 @@ module.exports = {
|
||||||
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available
|
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available
|
||||||
* and enabled.
|
* and enabled.
|
||||||
*/
|
*/
|
||||||
isDesktopSharingEnabled: function () {
|
isDesktopSharingEnabled: function () { return !!obtainDesktopStream; },
|
||||||
if (_desktopSharingEnabled === null) {
|
|
||||||
if (obtainDesktopStream === obtainScreenFromExtension) {
|
|
||||||
// Parse chrome version
|
|
||||||
var userAgent = navigator.userAgent.toLowerCase();
|
|
||||||
// We can assume that user agent is chrome, because it's
|
|
||||||
// enforced when 'ext' streaming method is set
|
|
||||||
var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10);
|
|
||||||
console.log("Chrome version" + userAgent, ver);
|
|
||||||
_desktopSharingEnabled = ver >= 34;
|
|
||||||
} else {
|
|
||||||
_desktopSharingEnabled =
|
|
||||||
obtainDesktopStream === obtainWebRTCScreen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _desktopSharingEnabled;
|
|
||||||
},
|
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
setDesktopSharing(config.desktopSharing);
|
APP.RTC.addListener(RTCEvents.RTC_READY, onWebRtcReady);
|
||||||
|
|
||||||
// Initialize Chrome extension inline installs
|
|
||||||
if (config.chromeExtensionId) {
|
|
||||||
|
|
||||||
initInlineInstalls();
|
|
||||||
|
|
||||||
// Check if extension is installed
|
|
||||||
checkExtInstalled(function (installed, updateRequired) {
|
|
||||||
extInstalled = installed;
|
|
||||||
extUpdateRequired = updateRequired;
|
|
||||||
console.info(
|
|
||||||
"Chrome extension installed: " + extInstalled +
|
|
||||||
" updateRequired: " + extUpdateRequired);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
eventEmitter.emit(DesktopSharingEventTypes.INIT);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addListener: function (listener, type)
|
addListener: function (listener, type)
|
||||||
|
@ -341,13 +357,16 @@ module.exports = {
|
||||||
isUsingScreenStream = true;
|
isUsingScreenStream = true;
|
||||||
// Hook 'ended' event to restore camera
|
// Hook 'ended' event to restore camera
|
||||||
// when screen stream stops
|
// when screen stream stops
|
||||||
stream.addEventListener('ended',
|
//FIXME: to be verified
|
||||||
function (e) {
|
if (stream.addEventListener) {
|
||||||
if (!switchInProgress && isUsingScreenStream) {
|
stream.addEventListener('ended', function () {
|
||||||
APP.desktopsharing.toggleScreenSharing();
|
onEndedHandler(stream);
|
||||||
}
|
});
|
||||||
}
|
} else {
|
||||||
);
|
stream.attachEvent('ended', function () {
|
||||||
|
onEndedHandler(stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
newStreamCreated(stream);
|
newStreamCreated(stream);
|
||||||
},
|
},
|
||||||
getDesktopStreamFailed);
|
getDesktopStreamFailed);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global ssrc2jid */
|
/* global ssrc2jid */
|
||||||
/* jshint -W117 */
|
/* jshint -W117 */
|
||||||
var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
|
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,10 +17,12 @@ function calculatePacketLoss(lostPackets, totalPackets) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStatValue(item, name) {
|
function getStatValue(item, name) {
|
||||||
if(!keyMap[APP.RTC.getBrowserType()][name])
|
var browserType = RTCBrowserType.getBrowserType();
|
||||||
|
if (!keyMap[browserType][name])
|
||||||
throw "The property isn't supported!";
|
throw "The property isn't supported!";
|
||||||
var key = keyMap[APP.RTC.getBrowserType()][name];
|
var key = keyMap[browserType][name];
|
||||||
return APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
|
return (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) ?
|
||||||
|
item.stat(key) : item[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -415,6 +417,8 @@ keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
|
||||||
"audioInputLevel": "audioInputLevel",
|
"audioInputLevel": "audioInputLevel",
|
||||||
"audioOutputLevel": "audioOutputLevel"
|
"audioOutputLevel": "audioOutputLevel"
|
||||||
};
|
};
|
||||||
|
keyMap[RTCBrowserType.RTC_BROWSER_OPERA] =
|
||||||
|
keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,6 +6,7 @@ var SDP = require("./SDP");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var transform = require("sdp-transform");
|
var transform = require("sdp-transform");
|
||||||
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
||||||
|
var RTCBrowserType = require("../RTC/RTCBrowserType");
|
||||||
|
|
||||||
// Jingle stuff
|
// Jingle stuff
|
||||||
function JingleSession(me, sid, connection, service, eventEmitter) {
|
function JingleSession(me, sid, connection, service, eventEmitter) {
|
||||||
|
@ -1332,9 +1333,10 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var thessrc;
|
var thessrc;
|
||||||
var ssrc2jid = this.connection.emuc.ssrc2jid;
|
var ssrc2jid = this.connection.emuc.ssrc2jid;
|
||||||
|
var streamId = APP.RTC.getStreamID(data.stream);
|
||||||
|
|
||||||
// look up an associated JID for a stream id
|
// look up an associated JID for a stream id
|
||||||
if (data.stream.id && data.stream.id.indexOf('mixedmslabel') === -1) {
|
if (streamId && streamId.indexOf('mixedmslabel') === -1) {
|
||||||
// look only at a=ssrc: and _not_ at a=ssrc-group: lines
|
// look only at a=ssrc: and _not_ at a=ssrc-group: lines
|
||||||
|
|
||||||
var ssrclines
|
var ssrclines
|
||||||
|
@ -1344,7 +1346,11 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
|
||||||
// is not always present.
|
// is not always present.
|
||||||
// return line.indexOf('mslabel:' + data.stream.label) !== -1;
|
// return line.indexOf('mslabel:' + data.stream.label) !== -1;
|
||||||
|
|
||||||
return ((line.indexOf('msid:' + data.stream.id) !== -1));
|
if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
return ((line.indexOf('mslabel:' + streamId) !== -1));
|
||||||
|
} else {
|
||||||
|
return ((line.indexOf('msid:' + streamId) !== -1));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (ssrclines.length) {
|
if (ssrclines.length) {
|
||||||
thessrc = ssrclines[0].substring(7).split(' ')[0];
|
thessrc = ssrclines[0].substring(7).split(' ')[0];
|
||||||
|
@ -1379,7 +1385,7 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok to overwrite the one from focus? might save work in colibri.js
|
// ok to overwrite the one from focus? might save work in colibri.js
|
||||||
console.log('associated jid', ssrc2jid[thessrc], data.peerjid);
|
console.log('associated jid', ssrc2jid[thessrc], thessrc);
|
||||||
if (ssrc2jid[thessrc]) {
|
if (ssrc2jid[thessrc]) {
|
||||||
data.peerjid = ssrc2jid[thessrc];
|
data.peerjid = ssrc2jid[thessrc];
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,8 +218,12 @@ SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
|
||||||
if (kv.indexOf(':') == -1) {
|
if (kv.indexOf(':') == -1) {
|
||||||
elem.attrs({ name: kv });
|
elem.attrs({ name: kv });
|
||||||
} else {
|
} else {
|
||||||
elem.attrs({ name: kv.split(':', 2)[0] });
|
var k = kv.split(':', 2)[0];
|
||||||
elem.attrs({ value: kv.split(':', 2)[1] });
|
elem.attrs({ name: k });
|
||||||
|
|
||||||
|
var v = kv.split(':', 2)[1];
|
||||||
|
v = SDPUtil.filter_special_chars(v);
|
||||||
|
elem.attrs({ value: v });
|
||||||
}
|
}
|
||||||
elem.up();
|
elem.up();
|
||||||
});
|
});
|
||||||
|
@ -243,7 +247,7 @@ SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
|
||||||
}
|
}
|
||||||
if(msid != null)
|
if(msid != null)
|
||||||
{
|
{
|
||||||
msid = msid.replace(/[\{,\}]/g,"");
|
msid = SDPUtil.filter_special_chars(msid);
|
||||||
elem.c('parameter');
|
elem.c('parameter');
|
||||||
elem.attrs({name: "msid", value:msid});
|
elem.attrs({name: "msid", value:msid});
|
||||||
elem.up();
|
elem.up();
|
||||||
|
@ -605,9 +609,12 @@ SDP.prototype.jingle2media = function (content) {
|
||||||
tmp.each(function () {
|
tmp.each(function () {
|
||||||
var ssrc = this.getAttribute('ssrc');
|
var ssrc = this.getAttribute('ssrc');
|
||||||
$(this).find('>parameter').each(function () {
|
$(this).find('>parameter').each(function () {
|
||||||
media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
|
var name = this.getAttribute('name');
|
||||||
if (this.getAttribute('value') && this.getAttribute('value').length)
|
var value = this.getAttribute('value');
|
||||||
media += ':' + this.getAttribute('value');
|
value = SDPUtil.filter_special_chars(value);
|
||||||
|
media += 'a=ssrc:' + ssrc + ' ' + name;
|
||||||
|
if (value && value.length)
|
||||||
|
media += ':' + value;
|
||||||
media += '\r\n';
|
media += '\r\n';
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
var SDPUtil = require("./SDPUtil");
|
||||||
|
|
||||||
function SDPDiffer(mySDP, otherSDP) {
|
function SDPDiffer(mySDP, otherSDP) {
|
||||||
this.mySDP = mySDP;
|
this.mySDP = mySDP;
|
||||||
this.otherSDP = otherSDP;
|
this.otherSDP = otherSDP;
|
||||||
|
@ -130,8 +133,11 @@ SDPDiffer.prototype.toJingle = function(modify) {
|
||||||
if (kv.indexOf(':') == -1) {
|
if (kv.indexOf(':') == -1) {
|
||||||
modify.attrs({ name: kv });
|
modify.attrs({ name: kv });
|
||||||
} else {
|
} else {
|
||||||
modify.attrs({ name: kv.split(':', 2)[0] });
|
var nv = kv.split(':', 2);
|
||||||
modify.attrs({ value: kv.split(':', 2)[1] });
|
var name = nv[0];
|
||||||
|
var value = SDPUtil.filter_special_chars(nv[1]);
|
||||||
|
modify.attrs({ name: name });
|
||||||
|
modify.attrs({ value: value });
|
||||||
}
|
}
|
||||||
modify.up(); // end of parameter
|
modify.up(); // end of parameter
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
SDPUtil = {
|
SDPUtil = {
|
||||||
|
filter_special_chars: function (text) {
|
||||||
|
return text.replace(/[\\\/\{,\}\+]/g, "");
|
||||||
|
},
|
||||||
iceparams: function (mediadesc, sessiondesc) {
|
iceparams: function (mediadesc, sessiondesc) {
|
||||||
var data = null;
|
var data = null;
|
||||||
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
|
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
|
var RTC = require('../RTC/RTC');
|
||||||
|
var RTCBrowserType = require("../RTC/RTCBrowserType.js");
|
||||||
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
|
||||||
|
|
||||||
function TraceablePeerConnection(ice_config, constraints, session) {
|
function TraceablePeerConnection(ice_config, constraints, session) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
|
var RTCPeerconnectionType = null;
|
||||||
this.peerconnection = new RTCPeerconnection(ice_config, constraints);
|
if (RTCBrowserType.isFirefox()) {
|
||||||
|
RTCPeerconnectionType = mozRTCPeerConnection;
|
||||||
|
} else if (RTCBrowserType.isTemasysPluginUsed()) {
|
||||||
|
RTCPeerconnectionType = RTCPeerConnection;
|
||||||
|
} else {
|
||||||
|
RTCPeerconnectionType = webkitRTCPeerConnection;
|
||||||
|
}
|
||||||
|
this.peerconnection = new RTCPeerconnectionType(ice_config, constraints);
|
||||||
this.updateLog = [];
|
this.updateLog = [];
|
||||||
this.stats = {};
|
this.stats = {};
|
||||||
this.statsinterval = null;
|
this.statsinterval = null;
|
||||||
|
@ -15,7 +24,15 @@ function TraceablePeerConnection(ice_config, constraints, session) {
|
||||||
|
|
||||||
// override as desired
|
// override as desired
|
||||||
this.trace = function (what, info) {
|
this.trace = function (what, info) {
|
||||||
//console.warn('WTRACE', what, info);
|
/*console.warn('WTRACE', what, info);
|
||||||
|
if (info && RTCBrowserType.isIExplorer()) {
|
||||||
|
if (info.length > 1024) {
|
||||||
|
console.warn('WTRACE', what, info.substr(1024));
|
||||||
|
}
|
||||||
|
if (info.length > 2048) {
|
||||||
|
console.warn('WTRACE', what, info.substr(2048));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
self.updateLog.push({
|
self.updateLog.push({
|
||||||
time: new Date(),
|
time: new Date(),
|
||||||
type: what,
|
type: what,
|
||||||
|
@ -24,7 +41,9 @@ function TraceablePeerConnection(ice_config, constraints, session) {
|
||||||
};
|
};
|
||||||
this.onicecandidate = null;
|
this.onicecandidate = null;
|
||||||
this.peerconnection.onicecandidate = function (event) {
|
this.peerconnection.onicecandidate = function (event) {
|
||||||
self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
|
// FIXME: this causes stack overflow with Temasys Plugin
|
||||||
|
if (!RTCBrowserType.isTemasysPluginUsed())
|
||||||
|
self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
|
||||||
if (self.onicecandidate !== null) {
|
if (self.onicecandidate !== null) {
|
||||||
self.onicecandidate(event);
|
self.onicecandidate(event);
|
||||||
}
|
}
|
||||||
|
@ -155,16 +174,26 @@ TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams)
|
||||||
this.trace('removeStream', stream.id);
|
this.trace('removeStream', stream.id);
|
||||||
if(stopStreams) {
|
if(stopStreams) {
|
||||||
stream.getAudioTracks().forEach(function (track) {
|
stream.getAudioTracks().forEach(function (track) {
|
||||||
track.stop();
|
// stop() not supported with IE
|
||||||
|
if (track.stop) {
|
||||||
|
track.stop();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
stream.getVideoTracks().forEach(function (track) {
|
stream.getVideoTracks().forEach(function (track) {
|
||||||
track.stop();
|
// stop() not supported with IE
|
||||||
|
if (track.stop) {
|
||||||
|
track.stop();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
if (stream.stop) {
|
||||||
|
stream.stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// FF doesn't support this yet.
|
// FF doesn't support this yet.
|
||||||
this.peerconnection.removeStream(stream);
|
if (this.peerconnection.removeStream)
|
||||||
|
this.peerconnection.removeStream(stream);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,11 @@ module.exports = function(XMPP, eventEmitter) {
|
||||||
initPresenceMap: function (myroomjid) {
|
initPresenceMap: function (myroomjid) {
|
||||||
this.presMap['to'] = myroomjid;
|
this.presMap['to'] = myroomjid;
|
||||||
this.presMap['xns'] = 'http://jabber.org/protocol/muc';
|
this.presMap['xns'] = 'http://jabber.org/protocol/muc';
|
||||||
if(APP.RTC.localAudio.isMuted())
|
if (APP.RTC.localAudio && APP.RTC.localAudio.isMuted())
|
||||||
{
|
{
|
||||||
this.addAudioInfoToPresence(true);
|
this.addAudioInfoToPresence(true);
|
||||||
}
|
}
|
||||||
|
if (APP.RTC.localVideo && APP.RTC.localVideo.isMuted())
|
||||||
if(APP.RTC.localVideo.isMuted())
|
|
||||||
{
|
{
|
||||||
this.addVideoInfoToPresence(true);
|
this.addVideoInfoToPresence(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
var RTCBrowserType = {
|
|
||||||
RTC_BROWSER_CHROME: "rtc_browser.chrome",
|
|
||||||
|
|
||||||
RTC_BROWSER_FIREFOX: "rtc_browser.firefox"
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = RTCBrowserType;
|
|
|
@ -1,4 +1,5 @@
|
||||||
var RTCEvents = {
|
var RTCEvents = {
|
||||||
|
RTC_READY: "rtc.ready",
|
||||||
LASTN_CHANGED: "rtc.lastn_changed",
|
LASTN_CHANGED: "rtc.lastn_changed",
|
||||||
DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
|
DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
|
||||||
LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
|
LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
|
||||||
|
|
Loading…
Reference in New Issue