Adds IE support through Temasys WebRTC plugin.

This commit is contained in:
paweldomas 2015-07-10 11:57:20 +02:00
parent cd6928d770
commit ae759fab5b
25 changed files with 4009 additions and 582 deletions

5
app.js
View File

@ -21,14 +21,11 @@ var APP =
function init() {
APP.desktopsharing.init();
APP.RTC.start();
APP.xmpp.start();
APP.statistics.start();
APP.connectionquality.init();
// Set default desktop sharing method
APP.desktopsharing.init();
APP.keyboardshortcut.init();
APP.members.start();
}

View File

@ -60,28 +60,31 @@
}
#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;
}
#remoteVideos .videocontainer.videoContainerFocused {
-webkit-box-shadow: inset 0 0 28px #006d91;
box-shadow: inset 0 0 28px #006d91;
border: 2px solid #006d91;
}
#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;
}
#localVideoWrapper {
display:inline-block;
-webkit-mask-box-image: url(../images/videomask.svg);
border-radius:0px !important;
border-radius:4px !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;
}
@ -92,8 +95,9 @@
-o-transform: scale(-1, 1);
}
#localVideoWrapper>video {
border-radius:0px !important;
#localVideoWrapper>video,
#localVideoWrapper>object {
border-radius:4px !important;
}
#largeVideo,
@ -110,8 +114,10 @@
#presentation,
#etherpad,
#localVideoWrapper>video,
#localVideoWrapper>object,
#localVideoWrapper,
.videocontainer>video {
.videocontainer>video,
.videocontainer>object {
position: absolute;
left: 0;
top: 0;
@ -363,7 +369,7 @@
margin-right: 40%;
text-align: center;
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-right-radius: 12px;
display: none;

View File

@ -22,12 +22,12 @@
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<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 -->
<link rel="stylesheet" href="css/font.css?v=7"/>
<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/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 rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3">

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
var EventEmitter = require("events");
var RTCBrowserType = require("./RTCBrowserType");
var RTCUtils = require("./RTCUtils.js");
var LocalStream = require("./LocalStream.js");
var DataChannels = require("./DataChannels");
@ -99,7 +100,7 @@ var RTC = {
},
createRemoteStream: function (data, sid, thessrc) {
var remoteStream = new MediaStream(data, sid, thessrc,
this.getBrowserType(), eventEmitter);
RTCBrowserType.getBrowserType(), eventEmitter);
var jid = data.peerjid || APP.xmpp.myJid();
if(!this.remoteStreams[jid]) {
this.remoteStreams[jid] = {};
@ -108,9 +109,6 @@ var RTC = {
eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
return remoteStream;
},
getBrowserType: function () {
return this.rtcUtils.browser;
},
getPCConstraints: function () {
return this.rtcUtils.pc_constraints;
},
@ -133,6 +131,9 @@ var RTC = {
setVideoSrc: function (element, src) {
this.rtcUtils.setVideoSrc(element, src);
},
getVideoElementName: function () {
return RTCBrowserType.isTemasysPluginUsed() ? 'object' : 'video';
},
dispose: function() {
if (this.rtcUtils) {
this.rtcUtils = null;
@ -168,9 +169,22 @@ var RTC = {
DataChannels.handleSelectedEndpointEvent);
APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
DataChannels.handlePinnedEndpointEvent);
this.rtcUtils = new RTCUtils(this);
this.rtcUtils.obtainAudioAndVideoPermissions(
null, null, getMediaStreamUsage());
// In case of IE we continue from 'onReady' callback
// 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) {
var stream;
@ -211,6 +225,10 @@ var RTC = {
callback();
};
}
// FIXME: Workaround for FF/IE/Safari
if (stream && stream.videoStream) {
stream = stream.videoStream;
}
var videoStream = this.rtcUtils.createStream(stream, true);
this.localVideo = this.createLocalStream(videoStream, "video", true, type);
// Stop the stream to trigger onended event for old stream

View File

@ -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;

View File

@ -1,5 +1,7 @@
var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
var RTCBrowserType = require("./RTCBrowserType");
var Resolutions = require("../../service/RTC/Resolutions");
var AdapterJS = require("./adapter.screenshare");
var SDPUtil = require("../xmpp/SDPUtil");
var currentResolution = null;
@ -58,16 +60,30 @@ function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid
constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
}
if (um.indexOf('screen') >= 0) {
constraints.video = {
mandatory: {
chromeMediaSource: "screen",
googLeakyBucket: true,
maxWidth: window.screen.width,
maxHeight: window.screen.height,
maxFrameRate: 3
},
optional: []
};
if (RTCBrowserType.isChrome()) {
constraints.video = {
mandatory: {
chromeMediaSource: "screen",
googLeakyBucket: true,
maxWidth: window.screen.width,
maxHeight: window.screen.height,
maxFrameRate: 3
},
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) {
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;
if (navigator.mozGetUserMedia) {
console.log('This appears to be Firefox');
var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
if (version >= 40
&& config.useBundle && config.useRtcpMux) {
if (RTCBrowserType.isFirefox()) {
var FFversion = RTCBrowserType.getFirefoxVersion();
if (FFversion >= 40 && config.useBundle && config.useRtcpMux) {
this.peerconnection = mozRTCPeerConnection;
this.browser = RTCBrowserType.RTC_BROWSER_FIREFOX;
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
this.pc_constraints = {};
this.attachMediaStream = function (element, stream) {
@ -155,7 +169,7 @@ function RTCUtils(RTCService)
{
tracks = stream.getAudioTracks();
}
return tracks[0].id.replace(/[\{,\}]/g,"");
return SDPUtil.filter_special_chars(tracks[0].id);
};
this.getVideoSrc = function (element) {
if(!element)
@ -169,14 +183,16 @@ function RTCUtils(RTCService)
RTCSessionDescription = mozRTCSessionDescription;
RTCIceCandidate = mozRTCIceCandidate;
} else {
console.error(
"Firefox requirements not met, ver: " + FFversion +
", bundle: " + config.useBundle +
", rtcp-mux: " + config.useRtcpMux);
window.location.href = 'unsupported_browser.html';
return;
}
} else if (navigator.webkitGetUserMedia) {
console.log('This appears to be Chrome');
} else if (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) {
this.peerconnection = webkitRTCPeerConnection;
this.browser = RTCBrowserType.RTC_BROWSER_CHROME;
this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
this.attachMediaStream = function (element, stream) {
element.attr('src', webkitURL.createObjectURL(stream));
@ -184,7 +200,7 @@ function RTCUtils(RTCService)
this.getStreamID = function (stream) {
// streams from FF endpoints have the characters '{' and '}'
// that make jQuery choke.
return stream.id.replace(/[\{,\}]/g,"");
return SDPUtil.filter_special_chars(stream.id);
};
this.getVideoSrc = function (element) {
if(!element)
@ -211,12 +227,62 @@ function RTCUtils(RTCService)
};
}
}
else
{
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
// Detect IE/Safari
else if (RTCBrowserType.isTemasysPluginUsed()) {
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';
return;
}
}
@ -232,7 +298,7 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
var constraints = getConstraints(
um, resolution, bandwidth, fps, desktopStream, isAndroid);
var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
console.info("Get media constraints", constraints);
var self = this;
@ -311,9 +377,9 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions =
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
// audio stream separately from the video stream using two distinct GUM
// 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
// the successCallback method.
self.getUserMediaWithConstraints(
['audio'],
function (audioStream) {
self.getUserMediaWithConstraints(
['video'],
function (videoStream) {
return self.successCallback({
audioStream: audioStream,
videoStream: videoStream
});
},
function (error) {
console.error('failed to obtain video stream - stop',
error);
return self.successCallback(null);
},
config.resolution || '360');
},
function (error) {
console.error('failed to obtain audio stream - stop',
error);
return self.successCallback(null);
}
);
var obtainVideo = function (audioStream) {
self.getUserMediaWithConstraints(
['video'],
function (videoStream) {
return successCallback({
audioStream: audioStream,
videoStream: videoStream
});
},
function (error) {
console.error(
'failed to obtain video stream - stop', error);
self.errorCallback(error);
},
config.resolution || '360');
};
var obtainAudio = function () {
self.getUserMediaWithConstraints(
['audio'],
function (audioStream) {
if (newDevices.indexOf('video') !== -1)
obtainVideo(audioStream);
},
function (error) {
console.error(
'failed to obtain audio stream - stop', error);
self.errorCallback(error);
}
);
};
if (newDevices.indexOf('audio') !== -1) {
obtainAudio();
} else {
obtainVideo(null);
}
} else {
this.getUserMediaWithConstraints(
newDevices,
@ -358,12 +434,12 @@ RTCUtils.prototype.obtainAudioAndVideoPermissions =
config.resolution || '360');
}
}
};
RTCUtils.prototype.successCallback = function (stream, usageOptions) {
// If this is FF, the stream parameter is *not* a MediaStream object, it's
// an object with two properties: audioStream, videoStream.
if(stream && !navigator.mozGetUserMedia)
// If this is FF or IE, the stream parameter is *not* a MediaStream object,
// it's an object with two properties: audioStream, videoStream.
if (stream && stream.getAudioTracks && stream.getVideoTracks)
console.log('got', stream, stream.getAudioTracks().length,
stream.getVideoTracks().length);
this.handleLocalStream(stream, usageOptions);
@ -427,10 +503,17 @@ RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
}
}
}
else
{//firefox
audioStream = stream.audioStream;
videoStream = stream.videoStream;
else if (RTCBrowserType.isFirefox() || RTCBrowserType.isTemasysPluginUsed())
{ // Firefox and Temasys plugin
if (stream && stream.audioStream)
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),
@ -447,15 +530,20 @@ RTCUtils.prototype.handleLocalStream = function(stream, usageOptions)
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;
if(window.webkitMediaStream)
{
if (window.webkitMediaStream) {
newStream = new webkitMediaStream();
if(newStream)
{
var tracks = (isVideo? stream.getVideoTracks() : stream.getAudioTracks());
if (newStream) {
var tracks = (isVideo ? stream.getVideoTracks() : stream.getAudioTracks());
for (i = 0; i < tracks.length; i++) {
newStream.addTrack(tracks[i]);
@ -463,8 +551,14 @@ RTCUtils.prototype.createStream = function(stream, isVideo)
}
}
else
newStream = stream;
else {
// FIXME: this is duplicated with 'handleLocalStream' !!!
if (stream) {
newStream = stream;
} else {
newStream = new DummyMediaStream(isVideo ? "dummyVideo" : "dummyAudio");
}
}
return newStream;
};

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@ var CQEvents = require("../../service/connectionquality/CQEvents");
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
var RTCEvents = require("../../service/RTC/RTCEvents");
var RTCBrowserType = require("../RTC/RTCBrowserType");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
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
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) {
case 'sendrecv':
el.show();
@ -405,7 +406,9 @@ UI.start = function (init) {
$('#notice').css({display: 'block'});
}
document.getElementById('largeVideo').volume = 0;
if (!RTCBrowserType.isIExplorer()) {
document.getElementById('largeVideo').volume = 0;
}
if(config.requireDisplayName) {
var currentSettings = Settings.getSettings();

View File

@ -336,7 +336,10 @@ ConnectionIndicator.prototype.create = function () {
*/
ConnectionIndicator.prototype.remove = function()
{
this.connectionIndicatorContainer.remove();
if (this.connectionIndicatorContainer.parentNode) {
this.connectionIndicatorContainer.parentNode.removeChild(
this.connectionIndicatorContainer);
}
this.popover.forceHide();
};

View File

@ -1,9 +1,11 @@
var Avatar = require("../avatar/Avatar");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
var UIUtil = require("../util/UIUtil");
var UIEvents = require("../../../service/UI/UIEvents");
var xmpp = require("../../xmpp/xmpp");
var video = $('#largeVideo');
// FIXME: With Temasys we have to re-select everytime
//var video = $('#largeVideo');
var currentVideoWidth = null;
var currentVideoHeight = null;
@ -244,9 +246,7 @@ function changeVideo(isVisible) {
}
if (isVisible) {
// using "this" should be ok because we're called
// from within the fadeOut event.
$(this).fadeIn(300);
$('#largeVideo').fadeIn(300);
}
if(oldSmallVideo)
@ -260,12 +260,16 @@ var LargeVideo = {
this.eventEmitter = emitter;
var self = this;
// Listen for large video size updates
document.getElementById('largeVideo')
.addEventListener('loadedmetadata', function (e) {
currentVideoWidth = this.videoWidth;
currentVideoHeight = this.videoHeight;
self.position(currentVideoWidth, currentVideoHeight);
});
var largeVideo = $('#largeVideo')[0];
var onplaying = function (arg1, arg2, arg3) {
// re-select
if (RTCBrowserType.isTemasysPluginUsed())
largeVideo = $('#largeVideo')[0];
currentVideoWidth = largeVideo.videoWidth;
currentVideoHeight = largeVideo.videoHeight;
self.position(currentVideoWidth, currentVideoHeight);
};
largeVideo.onplaying = onplaying;
},
/**
* Indicates if the large video is currently visible.
@ -273,14 +277,14 @@ var LargeVideo = {
* @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
*/
isLargeVideoVisible: function() {
return video.is(':visible');
return $('#largeVideo').is(':visible');
},
/**
* Updates the large video with the given new video source.
*/
updateLargeVideo: function(resourceJid, forceUpdate) {
console.log('hover in', resourceJid);
var newSmallVideo = this.VideoLayout.getSmallVideo(resourceJid);
console.log('hover in ' + resourceJid + ', video: ', newSmallVideo);
if ((currentSmallVideo && currentSmallVideo.resourceJid !== resourceJid)
|| forceUpdate) {
@ -303,8 +307,8 @@ var LargeVideo = {
this.eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
resourceJid);
}
video.fadeOut(300, changeVideo.bind(video, this.isLargeVideoVisible()));
$('#largeVideo').fadeOut(300,
changeVideo.bind($('#largeVideo'), this.isLargeVideoVisible()));
} else {
if(currentSmallVideo) {
currentSmallVideo.showAvatar();

View File

@ -3,6 +3,7 @@ var ConnectionIndicator = require("./ConnectionIndicator");
var NicknameHandler = require("../util/NicknameHandler");
var UIUtil = require("../util/UIUtil");
var LargeVideo = require("./LargeVideo");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function LocalVideo(VideoLayout)
{
@ -163,13 +164,18 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
var self = this;
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(
false,
APP.xmpp.myResource());
}
$('#localVideoContainer').click(localVideoClick);
$('#localVideoContainer').off('click');
$('#localVideoContainer').on('click', localVideoClick);
// Add hover handler
$('#localVideoContainer').hover(
@ -192,8 +198,10 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
var localVideo = document.createElement('video');
localVideo.id = 'localVideo_' +
APP.RTC.getStreamID(stream.getOriginalStream());
localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ?
if (!RTCBrowserType.isIExplorer()) {
localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ?
}
localVideo.oncontextmenu = function () { return false; };
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
// there's no video.
localVideoSelector.click(localVideoClick);
// onclick has to be used with Temasys plugin
localVideo.onclick = localVideoClick;
if (this.flipX) {
localVideoSelector.addClass("flipVideoX");
@ -214,6 +224,9 @@ LocalVideo.prototype.changeVideo = function (stream, isMuted) {
// Add stream ended handler
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);
self.VideoLayout.updateRemovedVideo(APP.xmpp.myResource());
};

View File

@ -3,6 +3,7 @@ var SmallVideo = require("./SmallVideo");
var AudioLevels = require("../audio_levels/AudioLevels");
var LargeVideo = require("./LargeVideo");
var Avatar = require("../avatar/Avatar");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function RemoteVideo(peerJid, VideoLayout)
{
@ -146,14 +147,15 @@ RemoteVideo.prototype.removeRemoteStreamElement = function (stream, isVideo, id)
select.remove();
var audioCount = $('#' + this.videoSpanId + '>audio').length;
var videoCount = $('#' + this.videoSpanId + '>video').length;
var videoCount = $('#' + this.videoSpanId + '>' + APP.RTC.getVideoElementName()).length;
if (!audioCount && !videoCount) {
console.log("Remove whole user", this.videoSpanId);
if(this.connectionIndicator)
this.connectionIndicator.remove();
// Remove whole container
this.container.remove();
if (this.container.parentNode)
this.container.parentNode.removeChild(this.container);
this.VideoLayout.resizeThumbnails();
}
@ -185,11 +187,21 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
if (isVideo && stream.id !== 'mixedmslabel') {
var onPlayingHandler = function () {
// 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);
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);
@ -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.
this.container.onclick = function (event) {
var onClickHandler = function (event) {
/*
* FIXME It turns out that videoThumb may not exist (if there is
* no actual video).
*/
var videoThumb = $('#' + self.videoSpanId + '>video').get(0);
var videoThumb = $('#' + self.videoSpanId + '>' + videoElem).get(0);
if (videoThumb) {
self.VideoLayout.handleVideoThumbClicked(
false,
self.resourceJid);
}
event.stopPropagation();
event.preventDefault();
// On IE we need to populate this handler on video <object>
// and it does not give event instance as an argument,
// so we check here for methods.
if (event.stopPropagation && event.preventDefault) {
event.stopPropagation();
event.preventDefault();
}
return false;
};
this.container.onclick = onClickHandler;
// reselect
if (RTCBrowserType.isTemasysPluginUsed())
sel = $('#' + newElementId);
sel[0].onclick = onClickHandler;
//FIXME
// Add hover handler
@ -229,9 +253,9 @@ RemoteVideo.prototype.addRemoteStreamElement = function (sid, stream, thessrc) {
},
function() {
var videoSrc = null;
if ($('#' + self.videoSpanId + '>video')
&& $('#' + self.videoSpanId + '>video').length > 0) {
videoSrc = APP.RTC.getVideoSrc($('#' + self.videoSpanId + '>video').get(0));
var videoSelector = $('#' + self.videoSpanId + '>' + videoElem);
if (videoSelector && videoSelector.length > 0) {
videoSrc = APP.RTC.getVideoSrc(videoSelector.get(0));
}
// 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);
}
);
}
},
/**
* Show/hide peer container for the given resourceJid.

View File

@ -1,5 +1,6 @@
var UIUtil = require("../util/UIUtil");
var LargeVideo = require("./LargeVideo");
var RTCBrowserType = require("../../RTC/RTCBrowserType");
function SmallVideo(){
this.isMuted = false;
@ -96,7 +97,9 @@ SmallVideo.createStreamElement = function (sid, stream) {
+ sid + '_' + APP.RTC.getStreamID(stream);
element.id = id;
element.autoplay = true;
if (!RTCBrowserType.isIExplorer()) {
element.autoplay = true;
}
element.oncontextmenu = function () { return false; };
return element;
@ -204,7 +207,7 @@ SmallVideo.prototype.enableDominantSpeaker = function (isEnable)
return;
}
var video = $('#' + this.videoSpanId + '>video');
var video = $('#' + this.videoSpanId + '>' + APP.RTC.getVideoElementName());
if (video && video.length > 0) {
if (isEnable) {
@ -275,8 +278,10 @@ SmallVideo.prototype.createModeratorIndicatorElement = 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)
{
@ -290,7 +295,8 @@ SmallVideo.prototype.focus = function(isFocused)
}
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)
return;
var video = $('#' + this.videoSpanId).find("video");
var videoElem = APP.RTC.getVideoElementName();
var video = $('#' + this.videoSpanId).find(videoElem);
var avatar = $('#avatar_' + this.resourceJid);
if (show === undefined || show === null) {

View File

@ -3,6 +3,10 @@ var Avatar = require("../avatar/Avatar");
var ContactList = require("../side_pannels/contactlist/ContactList");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
var UIEvents = require("../../../service/UI/UIEvents");
var RTC = require("../../RTC/RTC");
var RTCBrowserType = require('../../RTC/RTCBrowserType');
var RemoteVideo = require("./RemoteVideo");
var LargeVideo = require("./LargeVideo");
var LocalVideo = require("./LocalVideo");
@ -48,11 +52,15 @@ var VideoLayout = (function (my) {
};
my.changeLocalAudio = function(stream, isMuted) {
if(isMuted)
if (isMuted)
APP.UI.setAudioMuted(true, true);
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
document.getElementById('localAudio').autoplay = true;
document.getElementById('localAudio').volume = 0;
var localAudio = document.getElementById('localAudio');
// Writing volume not allowed in IE
if (!RTCBrowserType.isIExplorer()) {
localAudio.autoplay = true;
localAudio.volume = 0;
}
};
my.changeLocalVideo = function(stream, isMuted) {
@ -107,22 +115,26 @@ var VideoLayout = (function (my) {
* @param removedVideoSrc src stream identifier of the video.
*/
my.updateRemovedVideo = function(resourceJid) {
var videoElem = RTC.getVideoElementName();
if (resourceJid === LargeVideo.getResourceJid()) {
// this is currently displayed as large
// pick the last visible video in the row
// if nobody else is left, this picks the local video
var pick
= $('#remoteVideos>span[id!="mixedstream"]:visible:last>video')
.get(0);
= $('#remoteVideos>' +
'span[id!="mixedstream"]:visible:last>' + videoElem).get(0);
if (!pick) {
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)) {
// Try 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);
$('audio').each(function (idx, el) {
el.volume = 0;
el.volume = 1;
});
// Writing volume not allowed in IE
if (!RTCBrowserType.isIExplorer()) {
$('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 videoContainer = $("#participant_" + resource);
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
// no actual video).
if (videoThumb) {
@ -571,7 +587,8 @@ var VideoLayout = (function (my) {
// since we don't want to switch to local video.
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,
// otherwise wait for the "videoactive.jingle" event.
@ -673,7 +690,8 @@ var VideoLayout = (function (my) {
var jid = APP.xmpp.findJidFromResource(resourceJid);
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);
if (lastNPickupJid == mediaStream.peerjid) {

View File

@ -31,13 +31,7 @@ var extInstalled = false;
*/
var extUpdateRequired = false;
/**
* 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 AdapterJS = require("../RTC/adapter.screenshare");
var EventEmitter = require("events");
@ -46,6 +40,10 @@ var eventEmitter = new EventEmitter();
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
var RTCBrowserType = require("../RTC/RTCBrowserType");
var RTCEvents = require("../../service/RTC/RTCEvents");
/**
* Method obtains desktop stream from WebRTC 'screen' source.
* 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) {
// No API, so no extension for sure
callback(false, false);
@ -213,20 +211,39 @@ function obtainScreenFromExtension(streamCallback, failCallback) {
* feature completely.
*/
function setDesktopSharing(method) {
// Check if we are running chrome
if (!navigator.webkitGetUserMedia) {
obtainDesktopStream = null;
console.info("Desktop sharing disabled");
} else if (method == "ext") {
obtainDesktopStream = obtainScreenFromExtension;
console.info("Using Chrome extension for desktop sharing");
} else if (method == "webrtc") {
obtainDesktopStream = obtainWebRTCScreen;
console.info("Using Chrome WebRTC for desktop sharing");
obtainDesktopStream = null;
// When TemasysWebRTC plugin is used we always use getUserMedia, so we don't
// care about 'method' parameter
if (RTCBrowserType.isTemasysPluginUsed()) {
if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
console.info("Screensharing not supported by this plugin version");
} else if (!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) {
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
_desktopSharingEnabled = null;
if (!obtainDesktopStream) {
console.info("Desktop sharing disabled");
}
}
/**
@ -239,6 +256,19 @@ function initInlineInstalls()
$("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) {
console.error("Failed to obtain the stream to switch to", error);
switchInProgress = false;
@ -264,6 +294,25 @@ function newStreamCreated(stream)
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 = {
isUsingScreenStream: function () {
@ -274,43 +323,10 @@ module.exports = {
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available
* and enabled.
*/
isDesktopSharingEnabled: function () {
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;
},
isDesktopSharingEnabled: function () { return !!obtainDesktopStream; },
init: function () {
setDesktopSharing(config.desktopSharing);
// 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);
APP.RTC.addListener(RTCEvents.RTC_READY, onWebRtcReady);
},
addListener: function (listener, type)
@ -341,13 +357,16 @@ module.exports = {
isUsingScreenStream = true;
// Hook 'ended' event to restore camera
// when screen stream stops
stream.addEventListener('ended',
function (e) {
if (!switchInProgress && isUsingScreenStream) {
APP.desktopsharing.toggleScreenSharing();
}
}
);
//FIXME: to be verified
if (stream.addEventListener) {
stream.addEventListener('ended', function () {
onEndedHandler(stream);
});
} else {
stream.attachEvent('ended', function () {
onEndedHandler(stream);
});
}
newStreamCreated(stream);
},
getDesktopStreamFailed);

View File

@ -1,6 +1,6 @@
/* global ssrc2jid */
/* 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) {
if(!keyMap[APP.RTC.getBrowserType()][name])
var browserType = RTCBrowserType.getBrowserType();
if (!keyMap[browserType][name])
throw "The property isn't supported!";
var key = keyMap[APP.RTC.getBrowserType()][name];
return APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
var key = keyMap[browserType][name];
return (RTCBrowserType.isChrome() || RTCBrowserType.isOpera()) ?
item.stat(key) : item[key];
}
/**
@ -415,6 +417,8 @@ keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
"audioInputLevel": "audioInputLevel",
"audioOutputLevel": "audioOutputLevel"
};
keyMap[RTCBrowserType.RTC_BROWSER_OPERA] =
keyMap[RTCBrowserType.RTC_BROWSER_CHROME];
/**

View File

@ -6,6 +6,7 @@ var SDP = require("./SDP");
var async = require("async");
var transform = require("sdp-transform");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var RTCBrowserType = require("../RTC/RTCBrowserType");
// Jingle stuff
function JingleSession(me, sid, connection, service, eventEmitter) {
@ -1332,9 +1333,10 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
var self = this;
var thessrc;
var ssrc2jid = this.connection.emuc.ssrc2jid;
var streamId = APP.RTC.getStreamID(data.stream);
// 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
var ssrclines
@ -1344,7 +1346,11 @@ JingleSession.prototype.remoteStreamAdded = function (data, times) {
// is not always present.
// 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) {
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
console.log('associated jid', ssrc2jid[thessrc], data.peerjid);
console.log('associated jid', ssrc2jid[thessrc], thessrc);
if (ssrc2jid[thessrc]) {
data.peerjid = ssrc2jid[thessrc];
}

View File

@ -218,8 +218,12 @@ SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
if (kv.indexOf(':') == -1) {
elem.attrs({ name: kv });
} else {
elem.attrs({ name: kv.split(':', 2)[0] });
elem.attrs({ value: kv.split(':', 2)[1] });
var k = kv.split(':', 2)[0];
elem.attrs({ name: k });
var v = kv.split(':', 2)[1];
v = SDPUtil.filter_special_chars(v);
elem.attrs({ value: v });
}
elem.up();
});
@ -243,7 +247,7 @@ SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
}
if(msid != null)
{
msid = msid.replace(/[\{,\}]/g,"");
msid = SDPUtil.filter_special_chars(msid);
elem.c('parameter');
elem.attrs({name: "msid", value:msid});
elem.up();
@ -605,9 +609,12 @@ SDP.prototype.jingle2media = function (content) {
tmp.each(function () {
var ssrc = this.getAttribute('ssrc');
$(this).find('>parameter').each(function () {
media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
if (this.getAttribute('value') && this.getAttribute('value').length)
media += ':' + this.getAttribute('value');
var name = this.getAttribute('name');
var value = this.getAttribute('value');
value = SDPUtil.filter_special_chars(value);
media += 'a=ssrc:' + ssrc + ' ' + name;
if (value && value.length)
media += ':' + value;
media += '\r\n';
});
});

View File

@ -1,3 +1,6 @@
var SDPUtil = require("./SDPUtil");
function SDPDiffer(mySDP, otherSDP) {
this.mySDP = mySDP;
this.otherSDP = otherSDP;
@ -130,8 +133,11 @@ SDPDiffer.prototype.toJingle = function(modify) {
if (kv.indexOf(':') == -1) {
modify.attrs({ name: kv });
} else {
modify.attrs({ name: kv.split(':', 2)[0] });
modify.attrs({ value: kv.split(':', 2)[1] });
var nv = kv.split(':', 2);
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
});

View File

@ -1,4 +1,7 @@
SDPUtil = {
filter_special_chars: function (text) {
return text.replace(/[\\\/\{,\}\+]/g, "");
},
iceparams: function (mediadesc, sessiondesc) {
var data = null;
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&

View File

@ -1,9 +1,18 @@
var RTC = require('../RTC/RTC');
var RTCBrowserType = require("../RTC/RTCBrowserType.js");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
function TraceablePeerConnection(ice_config, constraints, session) {
var self = this;
var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
this.peerconnection = new RTCPeerconnection(ice_config, constraints);
var RTCPeerconnectionType = null;
if (RTCBrowserType.isFirefox()) {
RTCPeerconnectionType = mozRTCPeerConnection;
} else if (RTCBrowserType.isTemasysPluginUsed()) {
RTCPeerconnectionType = RTCPeerConnection;
} else {
RTCPeerconnectionType = webkitRTCPeerConnection;
}
this.peerconnection = new RTCPeerconnectionType(ice_config, constraints);
this.updateLog = [];
this.stats = {};
this.statsinterval = null;
@ -15,7 +24,15 @@ function TraceablePeerConnection(ice_config, constraints, session) {
// override as desired
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({
time: new Date(),
type: what,
@ -24,7 +41,9 @@ function TraceablePeerConnection(ice_config, constraints, session) {
};
this.onicecandidate = null;
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) {
self.onicecandidate(event);
}
@ -155,16 +174,26 @@ TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams)
this.trace('removeStream', stream.id);
if(stopStreams) {
stream.getAudioTracks().forEach(function (track) {
track.stop();
// stop() not supported with IE
if (track.stop) {
track.stop();
}
});
stream.getVideoTracks().forEach(function (track) {
track.stop();
// stop() not supported with IE
if (track.stop) {
track.stop();
}
});
if (stream.stop) {
stream.stop();
}
}
try {
// FF doesn't support this yet.
this.peerconnection.removeStream(stream);
if (this.peerconnection.removeStream)
this.peerconnection.removeStream(stream);
} catch (e) {
console.error(e);
}

View File

@ -28,12 +28,11 @@ module.exports = function(XMPP, eventEmitter) {
initPresenceMap: function (myroomjid) {
this.presMap['to'] = myroomjid;
this.presMap['xns'] = 'http://jabber.org/protocol/muc';
if(APP.RTC.localAudio.isMuted())
if (APP.RTC.localAudio && APP.RTC.localAudio.isMuted())
{
this.addAudioInfoToPresence(true);
}
if(APP.RTC.localVideo.isMuted())
if (APP.RTC.localVideo && APP.RTC.localVideo.isMuted())
{
this.addVideoInfoToPresence(true);
}

View File

@ -1,7 +0,0 @@
var RTCBrowserType = {
RTC_BROWSER_CHROME: "rtc_browser.chrome",
RTC_BROWSER_FIREFOX: "rtc_browser.firefox"
};
module.exports = RTCBrowserType;

View File

@ -1,4 +1,5 @@
var RTCEvents = {
RTC_READY: "rtc.ready",
LASTN_CHANGED: "rtc.lastn_changed",
DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",