Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
f90c277a49
2
app.js
2
app.js
|
@ -562,7 +562,7 @@ $(document).bind('callactive.jingle', function (event, videoelem, sid) {
|
||||||
|
|
||||||
// Update the large video to the last added video only if there's no
|
// Update the large video to the last added video only if there's no
|
||||||
// current active or focused speaker.
|
// current active or focused speaker.
|
||||||
if (!focusedVideoSrc && !VideoLayout.getActiveSpeakerResourceJid())
|
if (!focusedVideoSrc && !VideoLayout.getDominantSpeakerResourceJid())
|
||||||
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
|
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
|
||||||
|
|
||||||
VideoLayout.showFocusIndicator();
|
VideoLayout.showFocusIndicator();
|
||||||
|
|
33
chat.js
33
chat.js
|
@ -115,8 +115,7 @@ var Chat = (function (my) {
|
||||||
+ '</div>');
|
+ '</div>');
|
||||||
$('#chatconversation').animate(
|
$('#chatconversation').animate(
|
||||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the subject to the UI
|
* Sets the subject to the UI
|
||||||
|
@ -135,8 +134,7 @@ var Chat = (function (my) {
|
||||||
{
|
{
|
||||||
$("#subject").css({display: "block"});
|
$("#subject").css({display: "block"});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens / closes the chat area.
|
* Opens / closes the chat area.
|
||||||
|
@ -159,6 +157,10 @@ var Chat = (function (my) {
|
||||||
var horizontalIndent = videoPosition[0];
|
var horizontalIndent = videoPosition[0];
|
||||||
var verticalIndent = videoPosition[1];
|
var verticalIndent = videoPosition[1];
|
||||||
|
|
||||||
|
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
|
||||||
|
var thumbnailsWidth = thumbnailSize[0];
|
||||||
|
var thumbnailsHeight = thumbnailSize[1];
|
||||||
|
|
||||||
if (chatspace.is(":visible")) {
|
if (chatspace.is(":visible")) {
|
||||||
videospace.animate({right: chatSize[0],
|
videospace.animate({right: chatSize[0],
|
||||||
width: videospaceWidth,
|
width: videospaceWidth,
|
||||||
|
@ -166,6 +168,15 @@ var Chat = (function (my) {
|
||||||
{queue: false,
|
{queue: false,
|
||||||
duration: 500});
|
duration: 500});
|
||||||
|
|
||||||
|
$('#remoteVideos').animate({height: thumbnailsHeight},
|
||||||
|
{queue: false,
|
||||||
|
duration: 500});
|
||||||
|
|
||||||
|
$('#remoteVideos>span').animate({height: thumbnailsHeight,
|
||||||
|
width: thumbnailsWidth},
|
||||||
|
{queue: false,
|
||||||
|
duration: 500});
|
||||||
|
|
||||||
$('#largeVideoContainer').animate({ width: videospaceWidth,
|
$('#largeVideoContainer').animate({ width: videospaceWidth,
|
||||||
height: videospaceHeight},
|
height: videospaceHeight},
|
||||||
{queue: false,
|
{queue: false,
|
||||||
|
@ -187,6 +198,9 @@ var Chat = (function (my) {
|
||||||
duration: 500});
|
duration: 500});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Undock the toolbar when the chat is shown.
|
||||||
|
Toolbar.dockToolbar(false);
|
||||||
|
|
||||||
videospace.animate({right: chatSize[0],
|
videospace.animate({right: chatSize[0],
|
||||||
width: videospaceWidth,
|
width: videospaceWidth,
|
||||||
height: videospaceHeight},
|
height: videospaceHeight},
|
||||||
|
@ -198,6 +212,15 @@ var Chat = (function (my) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#remoteVideos').animate({height: thumbnailsHeight},
|
||||||
|
{queue: false,
|
||||||
|
duration: 500});
|
||||||
|
|
||||||
|
$('#remoteVideos>span').animate({height: thumbnailsHeight,
|
||||||
|
width: thumbnailsWidth},
|
||||||
|
{queue: false,
|
||||||
|
duration: 500});
|
||||||
|
|
||||||
$('#largeVideoContainer').animate({ width: videospaceWidth,
|
$('#largeVideoContainer').animate({ width: videospaceWidth,
|
||||||
height: videospaceHeight},
|
height: videospaceHeight},
|
||||||
{queue: false,
|
{queue: false,
|
||||||
|
@ -290,7 +313,7 @@ var Chat = (function (my) {
|
||||||
if (unreadMessages) {
|
if (unreadMessages) {
|
||||||
unreadMsgElement.innerHTML = unreadMessages.toString();
|
unreadMsgElement.innerHTML = unreadMessages.toString();
|
||||||
|
|
||||||
Toolbar.showToolbar();
|
Toolbar.dockToolbar(true);
|
||||||
|
|
||||||
var chatButtonElement
|
var chatButtonElement
|
||||||
= document.getElementById('chatButton').parentNode;
|
= document.getElementById('chatButton').parentNode;
|
||||||
|
|
|
@ -13,6 +13,7 @@ var config = {
|
||||||
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
|
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
|
||||||
minChromeExtVersion: '0.1', // Required version of Chrome extension
|
minChromeExtVersion: '0.1', // Required version of Chrome extension
|
||||||
enableRtpStats: false, // Enables RTP stats processing
|
enableRtpStats: false, // Enables RTP stats processing
|
||||||
openSctp: true, //Toggle to enable/disable SCTP channels
|
openSctp: true, // Toggle to enable/disable SCTP channels
|
||||||
|
// channelLastN: -1, // The default value of the channel attribute last-n.
|
||||||
enableRecording: false
|
enableRecording: false
|
||||||
};
|
};
|
||||||
|
|
23
css/main.css
23
css/main.css
|
@ -131,15 +131,24 @@ html, body{
|
||||||
}
|
}
|
||||||
|
|
||||||
#chatButton {
|
#chatButton {
|
||||||
-webkit-transition: all .5s ease-in-out;;
|
-webkit-transition: all .5s ease-in-out;
|
||||||
-moz-transition: all .5s ease-in-out;;
|
-moz-transition: all .5s ease-in-out;
|
||||||
transition: all .5s ease-in-out;;
|
transition: all .5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
/*#ffde00*/
|
||||||
#chatButton.active {
|
#chatButton.active {
|
||||||
-webkit-text-shadow: 0 0 10px #ffffff;
|
-webkit-text-shadow: -1px 0 10px #00ccff,
|
||||||
-moz-text-shadow: 0 0 10px #ffffff;
|
0 1px 10px #00ccff,
|
||||||
text-shadow: 0 0 10px #ffffff;
|
1px 0 10px #00ccff,
|
||||||
|
0 -1px 10px #00ccff;
|
||||||
|
-moz-text-shadow: 1px 0 10px #00ccff,
|
||||||
|
0 1px 10px #00ccff,
|
||||||
|
1px 0 10px #00ccff,
|
||||||
|
0 -1px 10px #00ccff;
|
||||||
|
text-shadow: -1px 0 10px #00ccff,
|
||||||
|
0 1px 10px #00ccff,
|
||||||
|
1px 0 10px #00ccff,
|
||||||
|
0 -1px 10px #00ccff;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.button:hover {
|
a.button:hover {
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.activespeaker {
|
.dominantspeaker {
|
||||||
background: #000 !important;
|
background: #000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ function onDataChannel(event)
|
||||||
|
|
||||||
dataChannel.onopen = function ()
|
dataChannel.onopen = function ()
|
||||||
{
|
{
|
||||||
console.info("Data channel opened by the bridge !!!", dataChannel);
|
console.info("Data channel opened by the Videobridge!", dataChannel);
|
||||||
|
|
||||||
// Code sample for sending string and/or binary data
|
// Code sample for sending string and/or binary data
|
||||||
// Sends String message to the bridge
|
// Sends String message to the bridge
|
||||||
|
@ -26,18 +26,56 @@ function onDataChannel(event)
|
||||||
|
|
||||||
dataChannel.onmessage = function (event)
|
dataChannel.onmessage = function (event)
|
||||||
{
|
{
|
||||||
var msgData = event.data;
|
var data = event.data;
|
||||||
console.info("Got Data Channel Message:", msgData, dataChannel);
|
// JSON
|
||||||
|
var obj;
|
||||||
|
|
||||||
// Active speaker event
|
try
|
||||||
if (msgData.indexOf('activeSpeaker') === 0)
|
|
||||||
{
|
{
|
||||||
// Endpoint ID from the bridge
|
obj = JSON.parse(data);
|
||||||
var resourceJid = msgData.split(":")[1];
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
console.error(
|
||||||
|
"Failed to parse data channel message as JSON: ",
|
||||||
|
data,
|
||||||
|
dataChannel);
|
||||||
|
}
|
||||||
|
if (('undefined' !== typeof(obj)) && (null !== obj))
|
||||||
|
{
|
||||||
|
var colibriClass = obj.colibriClass;
|
||||||
|
|
||||||
console.info(
|
if ("DominantSpeakerEndpointChangeEvent" === colibriClass)
|
||||||
"Data channel new active speaker event: " + resourceJid);
|
{
|
||||||
$(document).trigger('activespeakerchanged', [resourceJid]);
|
// Endpoint ID from the Videobridge.
|
||||||
|
var dominantSpeakerEndpoint = obj.dominantSpeakerEndpoint;
|
||||||
|
|
||||||
|
console.info(
|
||||||
|
"Data channel new dominant speaker event: ",
|
||||||
|
dominantSpeakerEndpoint);
|
||||||
|
$(document).trigger(
|
||||||
|
'dominantspeakerchanged',
|
||||||
|
[dominantSpeakerEndpoint]);
|
||||||
|
}
|
||||||
|
else if ("LastNEndpointsChangeEvent" === colibriClass)
|
||||||
|
{
|
||||||
|
// The new/latest list of last-n endpoint IDs.
|
||||||
|
var lastNEndpoints = obj.lastNEndpoints;
|
||||||
|
/*
|
||||||
|
* The list of endpoint IDs which are entering the list of
|
||||||
|
* last-n at this time i.e. were not in the old list of last-n
|
||||||
|
* endpoint IDs.
|
||||||
|
*/
|
||||||
|
var endpointsEnteringLastN = obj.endpointsEnteringLastN;
|
||||||
|
|
||||||
|
console.debug(
|
||||||
|
"Data channel new last-n event: ",
|
||||||
|
lastNEndpoints);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
console.debug("Data channel JSON-formatted message: ", obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,3 +116,4 @@ function bindDataChannelListener(peerConnection)
|
||||||
console.info("Got My Data Channel Message:", msgData, dataChannel);
|
console.info("Got My Data Channel Message:", msgData, dataChannel);
|
||||||
};*/
|
};*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
index.html
12
index.html
|
@ -27,9 +27,9 @@
|
||||||
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
|
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
|
||||||
<script src="desktopsharing.js?v=2"></script><!-- desktop sharing -->
|
<script src="desktopsharing.js?v=2"></script><!-- desktop sharing -->
|
||||||
<script src="data_channels.js?v=2"></script><!-- data channels -->
|
<script src="data_channels.js?v=2"></script><!-- data channels -->
|
||||||
<script src="app.js?v=29"></script><!-- application logic -->
|
<script src="app.js?v=3"></script><!-- application logic -->
|
||||||
<script src="commands.js?v=1"></script><!-- application logic -->
|
<script src="commands.js?v=1"></script><!-- application logic -->
|
||||||
<script src="chat.js?v=6"></script><!-- chat logic -->
|
<script src="chat.js?v=7"></script><!-- chat logic -->
|
||||||
<script src="util.js?v=5"></script><!-- utility functions -->
|
<script src="util.js?v=5"></script><!-- utility functions -->
|
||||||
<script src="etherpad.js?v=8"></script><!-- etherpad plugin -->
|
<script src="etherpad.js?v=8"></script><!-- etherpad plugin -->
|
||||||
<script src="prezi.js?v=4"></script><!-- prezi plugin -->
|
<script src="prezi.js?v=4"></script><!-- prezi plugin -->
|
||||||
|
@ -39,11 +39,11 @@
|
||||||
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
|
||||||
<script src="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
<script src="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
||||||
<script src="local_stats.js?v=1"></script><!-- Local stats processing -->
|
<script src="local_stats.js?v=1"></script><!-- Local stats processing -->
|
||||||
<script src="videolayout.js?v=4"></script><!-- video ui -->
|
<script src="videolayout.js?v=6"></script><!-- video ui -->
|
||||||
<script src="toolbar.js?v=2"></script><!-- toolbar ui -->
|
<script src="toolbar.js?v=3"></script><!-- toolbar ui -->
|
||||||
<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/font.css"/>
|
<link rel="stylesheet" href="css/font.css"/>
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=21"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=22"/>
|
||||||
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=7" id="videolayout_default"/>
|
<link rel="stylesheet" type="text/css" media="screen" href="css/videolayout_default.css?v=7" id="videolayout_default"/>
|
||||||
<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">
|
||||||
|
@ -123,7 +123,7 @@
|
||||||
<!--<video id="localVideo" autoplay oncontextmenu="return false;" muted></video> - is now per stream generated -->
|
<!--<video id="localVideo" autoplay oncontextmenu="return false;" muted></video> - is now per stream generated -->
|
||||||
</span>
|
</span>
|
||||||
<audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
|
<audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
|
||||||
<span class="focusindicator" data-content="The owner of this conference" data-toggle="popover" data-placement="top"></span>
|
<span class="focusindicator"></span>
|
||||||
</span>
|
</span>
|
||||||
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
|
||||||
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
|
||||||
|
|
|
@ -54,17 +54,22 @@ function ColibriFocus(connection, bridgejid) {
|
||||||
* Default channel expire value in seconds.
|
* Default channel expire value in seconds.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
this.channelExpire = 60;
|
this.channelExpire
|
||||||
|
= ('number' === typeof(config.channelExpire))
|
||||||
|
? config.channelExpire
|
||||||
|
: 15;
|
||||||
|
/**
|
||||||
|
* Default channel last-n value.
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
this.channelLastN
|
||||||
|
= ('number' === typeof(config.channelLastN)) ? config.channelLastN : -1;
|
||||||
|
|
||||||
// media types of the conference
|
// media types of the conference
|
||||||
if (config.openSctp)
|
if (config.openSctp)
|
||||||
{
|
|
||||||
this.media = ['audio', 'video', 'data'];
|
this.media = ['audio', 'video', 'data'];
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
this.media = ['audio', 'video'];
|
this.media = ['audio', 'video'];
|
||||||
}
|
|
||||||
|
|
||||||
this.connection.jingle.sessions[this.sid] = this;
|
this.connection.jingle.sessions[this.sid] = this;
|
||||||
this.mychannel = [];
|
this.mychannel = [];
|
||||||
|
@ -202,29 +207,33 @@ ColibriFocus.prototype._makeConference = function () {
|
||||||
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri'});
|
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri'});
|
||||||
|
|
||||||
this.media.forEach(function (name) {
|
this.media.forEach(function (name) {
|
||||||
var isData = name === 'data';
|
var elemName;
|
||||||
var channel = isData ? 'sctpconnection' : 'channel';
|
var elemAttrs = { initiator: 'true', expire: self.channelExpire };
|
||||||
|
|
||||||
|
if ('data' === name)
|
||||||
|
{
|
||||||
|
elemName = 'sctpconnection';
|
||||||
|
elemAttrs['port'] = 5000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
elemName = 'channel';
|
||||||
|
if (('video' === name) && (this.channelLastN >= 0))
|
||||||
|
elemAttrs['last-n'] = this.channelLastN;
|
||||||
|
}
|
||||||
|
|
||||||
elem.c('content', {name: name});
|
elem.c('content', {name: name});
|
||||||
|
|
||||||
elem.c(channel, {
|
elem.c(elemName, elemAttrs);
|
||||||
initiator: 'true',
|
elem.attrs({ endpoint: self.myMucResource });
|
||||||
expire: '15',
|
elem.up();// end of channel/sctpconnection
|
||||||
endpoint: self.myMucResource
|
|
||||||
});
|
|
||||||
if (isData)
|
|
||||||
elem.attrs({port: 5000});
|
|
||||||
elem.up();// end of channel
|
|
||||||
|
|
||||||
for (var j = 0; j < self.peers.length; j++) {
|
for (var j = 0; j < self.peers.length; j++) {
|
||||||
elem.c(channel, {
|
var peer = self.peers[j];
|
||||||
initiator: 'true',
|
|
||||||
expire: '15',
|
elem.c(elemName, elemAttrs);
|
||||||
endpoint: self.peers[j].substr(1 + self.peers[j].lastIndexOf('/'))
|
elem.attrs({ endpoint: peer.substr(1 + peer.lastIndexOf('/')) });
|
||||||
});
|
elem.up(); // end of channel/sctpconnection
|
||||||
if (isData)
|
|
||||||
elem.attrs({port: 5000});
|
|
||||||
elem.up(); // end of channel
|
|
||||||
}
|
}
|
||||||
elem.up(); // end of content
|
elem.up(); // end of content
|
||||||
});
|
});
|
||||||
|
@ -233,7 +242,7 @@ ColibriFocus.prototype._makeConference = function () {
|
||||||
localSDP.media.forEach(function (media, channel) {
|
localSDP.media.forEach(function (media, channel) {
|
||||||
var name = SDPUtil.parse_mline(media.split('\r\n')[0]).media;
|
var name = SDPUtil.parse_mline(media.split('\r\n')[0]).media;
|
||||||
elem.c('content', {name: name});
|
elem.c('content', {name: name});
|
||||||
elem.c('channel', {initiator: 'false', expire: '15'});
|
elem.c('channel', {initiator: 'false', expire: self.channelExpire});
|
||||||
|
|
||||||
// FIXME: should reuse code from .toJingle
|
// FIXME: should reuse code from .toJingle
|
||||||
var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
|
var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
|
||||||
|
@ -247,7 +256,7 @@ ColibriFocus.prototype._makeConference = function () {
|
||||||
|
|
||||||
elem.up(); // end of channel
|
elem.up(); // end of channel
|
||||||
for (j = 0; j < self.peers.length; j++) {
|
for (j = 0; j < self.peers.length; j++) {
|
||||||
elem.c('channel', {initiator: 'true', expire:'15' }).up();
|
elem.c('channel', {initiator: 'true', expire: self.channelExpire }).up();
|
||||||
}
|
}
|
||||||
elem.up(); // end of content
|
elem.up(); // end of content
|
||||||
});
|
});
|
||||||
|
@ -540,7 +549,8 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
||||||
if (1) { //i > 0) { // not for audio FIXME: does not work as intended
|
if (1) { //i > 0) { // not for audio FIXME: does not work as intended
|
||||||
// re-add all remote a=ssrcs
|
// re-add all remote a=ssrcs
|
||||||
for (var jid in this.remotessrc) {
|
for (var jid in this.remotessrc) {
|
||||||
if (jid == peer) continue;
|
if (jid == peer || !this.remotessrc[jid][i])
|
||||||
|
continue;
|
||||||
sdp.media[i] += this.remotessrc[jid][i];
|
sdp.media[i] += this.remotessrc[jid][i];
|
||||||
}
|
}
|
||||||
// and local a=ssrc lines
|
// and local a=ssrc lines
|
||||||
|
@ -661,24 +671,28 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
||||||
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
||||||
localSDP.media.forEach(function (media, channel) {
|
localSDP.media.forEach(function (media, channel) {
|
||||||
var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
||||||
elem.c('content', {name: name});
|
var elemName;
|
||||||
if (name !== 'data')
|
var elemAttrs
|
||||||
{
|
= {
|
||||||
elem.c('channel', {
|
|
||||||
initiator: 'true',
|
initiator: 'true',
|
||||||
expire: self.channelExpire,
|
expire: self.channelExpire,
|
||||||
endpoint: peer.substr(1 + peer.lastIndexOf('/'))
|
endpoint: peer.substr(1 + peer.lastIndexOf('/'))
|
||||||
});
|
};
|
||||||
|
|
||||||
|
if ('data' == name)
|
||||||
|
{
|
||||||
|
elemName = 'sctpconnection';
|
||||||
|
elemAttrs['port'] = 5000;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
elem.c('sctpconnection', {
|
elemName = 'channel';
|
||||||
endpoint: peer.substr(1 + peer.lastIndexOf('/')),
|
if (('video' === name) && (this.channelLastN >= 0))
|
||||||
initiator: 'true',
|
elemAttrs['last-n'] = this.channelLastN;
|
||||||
expire: self.channelExpire,
|
|
||||||
port: 5000
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elem.c('content', {name: name});
|
||||||
|
elem.c(elemName, elemAttrs);
|
||||||
elem.up(); // end of channel/sctpconnection
|
elem.up(); // end of channel/sctpconnection
|
||||||
elem.up(); // end of content
|
elem.up(); // end of content
|
||||||
});
|
});
|
||||||
|
@ -714,6 +728,9 @@ ColibriFocus.prototype.updateChannel = function (remoteSDP, participant) {
|
||||||
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
change.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri', id: this.confid});
|
||||||
for (channel = 0; channel < this.channels[participant].length; channel++)
|
for (channel = 0; channel < this.channels[participant].length; channel++)
|
||||||
{
|
{
|
||||||
|
if (!remoteSDP.media[channel])
|
||||||
|
continue;
|
||||||
|
|
||||||
var name = SDPUtil.parse_mid(SDPUtil.find_line(remoteSDP.media[channel], 'a=mid:'));
|
var name = SDPUtil.parse_mid(SDPUtil.find_line(remoteSDP.media[channel], 'a=mid:'));
|
||||||
change.c('content', {name: name});
|
change.c('content', {name: name});
|
||||||
if (name !== 'data')
|
if (name !== 'data')
|
||||||
|
@ -894,6 +911,9 @@ ColibriFocus.prototype.setRemoteDescription = function (session, elem, desctype)
|
||||||
this.remotessrc[session.peerjid] = [];
|
this.remotessrc[session.peerjid] = [];
|
||||||
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
||||||
//if (channel == 0) continue; FIXME: does not work as intended
|
//if (channel == 0) continue; FIXME: does not work as intended
|
||||||
|
if (!remoteSDP.media[channel])
|
||||||
|
continue;
|
||||||
|
|
||||||
if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length)
|
if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length)
|
||||||
{
|
{
|
||||||
this.remotessrc[session.peerjid][channel] =
|
this.remotessrc[session.peerjid][channel] =
|
||||||
|
@ -905,6 +925,9 @@ ColibriFocus.prototype.setRemoteDescription = function (session, elem, desctype)
|
||||||
// ACT 4: add new a=ssrc lines to local remotedescription
|
// ACT 4: add new a=ssrc lines to local remotedescription
|
||||||
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
||||||
//if (channel == 0) continue; FIXME: does not work as intended
|
//if (channel == 0) continue; FIXME: does not work as intended
|
||||||
|
if (!remoteSDP.media[channel])
|
||||||
|
continue;
|
||||||
|
|
||||||
if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length) {
|
if (SDPUtil.find_lines(remoteSDP.media[channel], 'a=ssrc:').length) {
|
||||||
this.peerconnection.enqueueAddSsrc(
|
this.peerconnection.enqueueAddSsrc(
|
||||||
channel,
|
channel,
|
||||||
|
@ -1153,3 +1176,73 @@ ColibriFocus.prototype.sendTerminate = function (session, reason, text) {
|
||||||
this.statsinterval = null;
|
this.statsinterval = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ColibriFocus.prototype.setRTCPTerminationStrategy = function (strategyFQN) {
|
||||||
|
var self = this;
|
||||||
|
var strategyIQ = $iq({to: this.bridgejid, type: 'set'});
|
||||||
|
strategyIQ.c('conference', {
|
||||||
|
xmlns: 'http://jitsi.org/protocol/colibri',
|
||||||
|
id: this.confid,
|
||||||
|
});
|
||||||
|
|
||||||
|
strategyIQ.c('rtcp-termination-strategy', {name: strategyFQN });
|
||||||
|
|
||||||
|
strategyIQ.c('content', {name: "video"});
|
||||||
|
strategyIQ.up(); // end of content
|
||||||
|
|
||||||
|
console.log('setting RTCP termination strategy', strategyFQN);
|
||||||
|
this.connection.sendIQ(strategyIQ,
|
||||||
|
function (res) {
|
||||||
|
console.log('got result');
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
console.error('got error', err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the default value of the channel last-n attribute in this conference and
|
||||||
|
* updates/patches the existing channels.
|
||||||
|
*/
|
||||||
|
ColibriFocus.prototype.setChannelLastN = function (channelLastN) {
|
||||||
|
if (('number' === typeof(channelLastN))
|
||||||
|
&& (this.channelLastN !== channelLastN))
|
||||||
|
{
|
||||||
|
this.channelLastN = channelLastN;
|
||||||
|
|
||||||
|
// Update/patch the existing channels.
|
||||||
|
var patch = $iq({ to:this.bridgejid, type:'set' });
|
||||||
|
|
||||||
|
patch.c(
|
||||||
|
'conference',
|
||||||
|
{ xmlns:'http://jitsi.org/protocol/colibri', id:this.confid });
|
||||||
|
patch.c('content', { name:'video' });
|
||||||
|
patch.c(
|
||||||
|
'channel',
|
||||||
|
{
|
||||||
|
id:$(this.mychannel[1 /* video */]).attr('id'),
|
||||||
|
'last-n':this.channelLastN
|
||||||
|
});
|
||||||
|
patch.up(); // end of channel
|
||||||
|
for (var p = 0; p < this.channels.length; p++)
|
||||||
|
{
|
||||||
|
patch.c(
|
||||||
|
'channel',
|
||||||
|
{
|
||||||
|
id:$(this.channels[p][1 /* video */]).attr('id'),
|
||||||
|
'last-n':this.channelLastN
|
||||||
|
});
|
||||||
|
patch.up(); // end of channel
|
||||||
|
}
|
||||||
|
this.connection.sendIQ(
|
||||||
|
patch,
|
||||||
|
function (res) {
|
||||||
|
console.info('Set channel last-n succeeded: ', res);
|
||||||
|
},
|
||||||
|
function (err) {
|
||||||
|
console.error('Set channel last-n failed: ', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -519,6 +519,7 @@ function getUserMediaWithConstraints(um, success_callback, failure_callback, res
|
||||||
constraints.video = {
|
constraints.video = {
|
||||||
mandatory: {
|
mandatory: {
|
||||||
chromeMediaSource: "screen",
|
chromeMediaSource: "screen",
|
||||||
|
googLeakyBucket: true,
|
||||||
maxWidth: window.screen.width,
|
maxWidth: window.screen.width,
|
||||||
maxHeight: window.screen.height,
|
maxHeight: window.screen.height,
|
||||||
maxFrameRate: 3
|
maxFrameRate: 3
|
||||||
|
@ -530,6 +531,7 @@ function getUserMediaWithConstraints(um, success_callback, failure_callback, res
|
||||||
mandatory: {
|
mandatory: {
|
||||||
chromeMediaSource: "desktop",
|
chromeMediaSource: "desktop",
|
||||||
chromeMediaSourceId: desktopStream,
|
chromeMediaSourceId: desktopStream,
|
||||||
|
googLeakyBucket: true,
|
||||||
maxWidth: window.screen.width,
|
maxWidth: window.screen.width,
|
||||||
maxHeight: window.screen.height,
|
maxHeight: window.screen.height,
|
||||||
maxFrameRate: 3
|
maxFrameRate: 3
|
||||||
|
|
82
toolbar.js
82
toolbar.js
|
@ -5,7 +5,7 @@ var Toolbar = (function (my) {
|
||||||
/**
|
/**
|
||||||
* Opens the lock room dialog.
|
* Opens the lock room dialog.
|
||||||
*/
|
*/
|
||||||
my.openLockDialog = function() {
|
my.openLockDialog = function () {
|
||||||
// Only the focus is able to set a shared key.
|
// Only the focus is able to set a shared key.
|
||||||
if (focus === null) {
|
if (focus === null) {
|
||||||
if (sharedKey)
|
if (sharedKey)
|
||||||
|
@ -70,24 +70,75 @@ var Toolbar = (function (my) {
|
||||||
/**
|
/**
|
||||||
* Opens the invite link dialog.
|
* Opens the invite link dialog.
|
||||||
*/
|
*/
|
||||||
my.openLinkDialog = function() {
|
my.openLinkDialog = function () {
|
||||||
|
var inviteLink;
|
||||||
|
if (roomUrl == null)
|
||||||
|
inviteLink = "Your conference is currently being created...";
|
||||||
|
else
|
||||||
|
inviteLink = encodeURI(roomUrl);
|
||||||
|
|
||||||
$.prompt('<input id="inviteLinkRef" type="text" value="' +
|
$.prompt('<input id="inviteLinkRef" type="text" value="' +
|
||||||
encodeURI(roomUrl) + '" onclick="this.select();" readonly>',
|
inviteLink + '" onclick="this.select();" readonly>',
|
||||||
{
|
{
|
||||||
title: "Share this link with everyone you want to invite",
|
title: "Share this link with everyone you want to invite",
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: { "Cancel": false},
|
buttons: { "Invite": true, "Cancel": false},
|
||||||
loaded: function (event) {
|
defaultButton: 1,
|
||||||
document.getElementById('inviteLinkRef').select();
|
loaded: function (event) {
|
||||||
|
if (roomUrl)
|
||||||
|
document.getElementById('inviteLinkRef').select();
|
||||||
|
else
|
||||||
|
document.getElementById('jqi_state0_buttonInvite')
|
||||||
|
.disabled = true;
|
||||||
|
},
|
||||||
|
submit: function (e, v, m, f) {
|
||||||
|
if (v) {
|
||||||
|
if (roomUrl) {
|
||||||
|
inviteParticipants();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invite participants to conference.
|
||||||
|
*/
|
||||||
|
function inviteParticipants() {
|
||||||
|
if (roomUrl == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var sharedKeyText = "";
|
||||||
|
if (sharedKey && sharedKey.length > 0)
|
||||||
|
sharedKeyText
|
||||||
|
= "This conference is password protected. Please use the "
|
||||||
|
+ "following pin when joining:%0D%0A%0D%0A"
|
||||||
|
+ sharedKey + "%0D%0A%0D%0A";
|
||||||
|
|
||||||
|
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
|
||||||
|
var subject = "Invitation to a Jitsi Meet (" + conferenceName + ")";
|
||||||
|
var body = "Hey there, I%27d like to invite you to a Jitsi Meet"
|
||||||
|
+ " conference I%27ve just set up.%0D%0A%0D%0A"
|
||||||
|
+ "Please click on the following link in order"
|
||||||
|
+ " to join the conference.%0D%0A%0D%0A"
|
||||||
|
+ roomUrl + "%0D%0A%0D%0A"
|
||||||
|
+ sharedKeyText
|
||||||
|
+ "Note that Jitsi Meet is currently only supported by Chromim,"
|
||||||
|
+ " Google Chrome and Opera, so you need"
|
||||||
|
+ " to be using one of these browsers.%0D%0A%0D%0A"
|
||||||
|
+ "Talk to you in a sec!";
|
||||||
|
|
||||||
|
if (window.localStorage.displayname)
|
||||||
|
body += "%0D%0A%0D%0A" + window.localStorage.displayname;
|
||||||
|
|
||||||
|
window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the settings dialog.
|
* Opens the settings dialog.
|
||||||
*/
|
*/
|
||||||
my.openSettingsDialog = function() {
|
my.openSettingsDialog = function () {
|
||||||
$.prompt('<h2>Configure your conference</h2>' +
|
$.prompt('<h2>Configure your conference</h2>' +
|
||||||
'<input type="checkbox" id="initMuted"> Participants join muted<br/>' +
|
'<input type="checkbox" id="initMuted"> Participants join muted<br/>' +
|
||||||
'<input type="checkbox" id="requireNicknames"> Require nicknames<br/><br/>' +
|
'<input type="checkbox" id="requireNicknames"> Require nicknames<br/><br/>' +
|
||||||
|
@ -185,9 +236,12 @@ var Toolbar = (function (my) {
|
||||||
if (!$('#header').is(':visible')) {
|
if (!$('#header').is(':visible')) {
|
||||||
Toolbar.showToolbar();
|
Toolbar.showToolbar();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then clear the time out, to dock the toolbar.
|
// Then clear the time out, to dock the toolbar.
|
||||||
clearTimeout(toolbarTimeout);
|
if (toolbarTimeout) {
|
||||||
toolbarTimeout = null;
|
clearTimeout(toolbarTimeout);
|
||||||
|
toolbarTimeout = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!$('#header').is(':visible')) {
|
if (!$('#header').is(':visible')) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var VideoLayout = (function (my) {
|
var VideoLayout = (function (my) {
|
||||||
var preMuted = false;
|
var preMuted = false;
|
||||||
var currentActiveSpeaker = null;
|
var currentDominantSpeaker = null;
|
||||||
|
|
||||||
my.changeLocalAudio = function(stream) {
|
my.changeLocalAudio = function(stream) {
|
||||||
connection.jingle.localAudio = stream;
|
connection.jingle.localAudio = stream;
|
||||||
|
@ -139,19 +139,19 @@ var VideoLayout = (function (my) {
|
||||||
|
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
// Only if the large video is currently visible.
|
// Only if the large video is currently visible.
|
||||||
// Disable previous active speaker video.
|
// Disable previous dominant speaker video.
|
||||||
var oldJid = getJidFromVideoSrc(oldSrc);
|
var oldJid = getJidFromVideoSrc(oldSrc);
|
||||||
if (oldJid) {
|
if (oldJid) {
|
||||||
var oldResourceJid = Strophe.getResourceFromJid(oldJid);
|
var oldResourceJid = Strophe.getResourceFromJid(oldJid);
|
||||||
VideoLayout.enableActiveSpeaker(oldResourceJid, false);
|
VideoLayout.enableDominantSpeaker(oldResourceJid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable new active speaker in the remote videos section.
|
// Enable new dominant speaker in the remote videos section.
|
||||||
var userJid = getJidFromVideoSrc(newSrc);
|
var userJid = getJidFromVideoSrc(newSrc);
|
||||||
if (userJid)
|
if (userJid)
|
||||||
{
|
{
|
||||||
var resourceJid = Strophe.getResourceFromJid(userJid);
|
var resourceJid = Strophe.getResourceFromJid(userJid);
|
||||||
VideoLayout.enableActiveSpeaker(resourceJid, true);
|
VideoLayout.enableDominantSpeaker(resourceJid, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$(this).fadeIn(300);
|
$(this).fadeIn(300);
|
||||||
|
@ -173,15 +173,15 @@ var VideoLayout = (function (my) {
|
||||||
if (focusedVideoSrc === videoSrc)
|
if (focusedVideoSrc === videoSrc)
|
||||||
{
|
{
|
||||||
focusedVideoSrc = null;
|
focusedVideoSrc = null;
|
||||||
var activeSpeakerVideo = null;
|
var dominantSpeakerVideo = null;
|
||||||
// Enable the currently set active speaker.
|
// Enable the currently set dominant speaker.
|
||||||
if (currentActiveSpeaker) {
|
if (currentDominantSpeaker) {
|
||||||
activeSpeakerVideo
|
dominantSpeakerVideo
|
||||||
= $('#participant_' + currentActiveSpeaker + '>video')
|
= $('#participant_' + currentDominantSpeaker + '>video')
|
||||||
.get(0);
|
.get(0);
|
||||||
|
|
||||||
if (activeSpeakerVideo)
|
if (dominantSpeakerVideo)
|
||||||
VideoLayout.updateLargeVideo(activeSpeakerVideo.src, 1);
|
VideoLayout.updateLargeVideo(dominantSpeakerVideo.src, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -254,12 +254,12 @@ var VideoLayout = (function (my) {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
$('#largeVideo').css({visibility: 'visible'});
|
$('#largeVideo').css({visibility: 'visible'});
|
||||||
$('.watermark').css({visibility: 'visible'});
|
$('.watermark').css({visibility: 'visible'});
|
||||||
VideoLayout.enableActiveSpeaker(resourceJid, true);
|
VideoLayout.enableDominantSpeaker(resourceJid, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$('#largeVideo').css({visibility: 'hidden'});
|
$('#largeVideo').css({visibility: 'hidden'});
|
||||||
$('.watermark').css({visibility: 'hidden'});
|
$('.watermark').css({visibility: 'hidden'});
|
||||||
VideoLayout.enableActiveSpeaker(resourceJid, false);
|
VideoLayout.enableDominantSpeaker(resourceJid, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -477,9 +477,7 @@ var VideoLayout = (function (my) {
|
||||||
if (!indicatorSpan || indicatorSpan.length === 0) {
|
if (!indicatorSpan || indicatorSpan.length === 0) {
|
||||||
indicatorSpan = document.createElement('span');
|
indicatorSpan = document.createElement('span');
|
||||||
indicatorSpan.className = 'focusindicator';
|
indicatorSpan.className = 'focusindicator';
|
||||||
Util.setTooltip(indicatorSpan,
|
|
||||||
"The owner of<br/>this conference",
|
|
||||||
"top");
|
|
||||||
focusContainer.appendChild(indicatorSpan);
|
focusContainer.appendChild(indicatorSpan);
|
||||||
|
|
||||||
createFocusIndicatorElement(indicatorSpan);
|
createFocusIndicatorElement(indicatorSpan);
|
||||||
|
@ -570,7 +568,9 @@ var VideoLayout = (function (my) {
|
||||||
* Resizes thumbnails.
|
* Resizes thumbnails.
|
||||||
*/
|
*/
|
||||||
my.resizeThumbnails = function() {
|
my.resizeThumbnails = function() {
|
||||||
var thumbnailSize = calculateThumbnailSize();
|
var videoSpaceWidth = $('#remoteVideos').width();
|
||||||
|
|
||||||
|
var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
|
||||||
var width = thumbnailSize[0];
|
var width = thumbnailSize[0];
|
||||||
var height = thumbnailSize[1];
|
var height = thumbnailSize[1];
|
||||||
|
|
||||||
|
@ -582,20 +582,20 @@ var VideoLayout = (function (my) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables the active speaker UI.
|
* Enables the dominant speaker UI.
|
||||||
*
|
*
|
||||||
* @param resourceJid the jid indicating the video element to
|
* @param resourceJid the jid indicating the video element to
|
||||||
* activate/deactivate
|
* activate/deactivate
|
||||||
* @param isEnable indicates if the active speaker should be enabled or
|
* @param isEnable indicates if the dominant speaker should be enabled or
|
||||||
* disabled
|
* disabled
|
||||||
*/
|
*/
|
||||||
my.enableActiveSpeaker = function(resourceJid, isEnable) {
|
my.enableDominantSpeaker = function(resourceJid, isEnable) {
|
||||||
var displayName = resourceJid;
|
var displayName = resourceJid;
|
||||||
var nameSpan = $('#participant_' + resourceJid + '>span.displayname');
|
var nameSpan = $('#participant_' + resourceJid + '>span.displayname');
|
||||||
if (nameSpan.length > 0)
|
if (nameSpan.length > 0)
|
||||||
displayName = nameSpan.text();
|
displayName = nameSpan.text();
|
||||||
|
|
||||||
console.log("UI enable active speaker",
|
console.log("UI enable dominant speaker",
|
||||||
displayName,
|
displayName,
|
||||||
resourceJid,
|
resourceJid,
|
||||||
isEnable);
|
isEnable);
|
||||||
|
@ -625,16 +625,16 @@ var VideoLayout = (function (my) {
|
||||||
if (isEnable) {
|
if (isEnable) {
|
||||||
VideoLayout.showDisplayName(videoContainerId, true);
|
VideoLayout.showDisplayName(videoContainerId, true);
|
||||||
|
|
||||||
if (!videoSpan.classList.contains("activespeaker"))
|
if (!videoSpan.classList.contains("dominantspeaker"))
|
||||||
videoSpan.classList.add("activespeaker");
|
videoSpan.classList.add("dominantspeaker");
|
||||||
|
|
||||||
video.css({visibility: 'hidden'});
|
video.css({visibility: 'hidden'});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VideoLayout.showDisplayName(videoContainerId, false);
|
VideoLayout.showDisplayName(videoContainerId, false);
|
||||||
|
|
||||||
if (videoSpan.classList.contains("activespeaker"))
|
if (videoSpan.classList.contains("dominantspeaker"))
|
||||||
videoSpan.classList.remove("activespeaker");
|
videoSpan.classList.remove("dominantspeaker");
|
||||||
|
|
||||||
video.css({visibility: 'visible'});
|
video.css({visibility: 'visible'});
|
||||||
}
|
}
|
||||||
|
@ -682,7 +682,7 @@ var VideoLayout = (function (my) {
|
||||||
/**
|
/**
|
||||||
* Calculates the thumbnail size.
|
* Calculates the thumbnail size.
|
||||||
*/
|
*/
|
||||||
var calculateThumbnailSize = function () {
|
my.calculateThumbnailSize = function (videoSpaceWidth) {
|
||||||
// Calculate the available height, which is the inner window height minus
|
// Calculate the available height, which is the inner window height minus
|
||||||
// 39px for the header minus 2px for the delimiter lines on the top and
|
// 39px for the header minus 2px for the delimiter lines on the top and
|
||||||
// bottom of the large video, minus the 36px space inside the remoteVideos
|
// bottom of the large video, minus the 36px space inside the remoteVideos
|
||||||
|
@ -691,8 +691,10 @@ var VideoLayout = (function (my) {
|
||||||
|
|
||||||
var numvids = $('#remoteVideos>span:visible').length;
|
var numvids = $('#remoteVideos>span:visible').length;
|
||||||
|
|
||||||
// Remove the 1px borders arround videos and the chat width.
|
// Remove the 3px borders arround videos and border around the remote
|
||||||
var availableWinWidth = $('#remoteVideos').width() - 2 * numvids - 50;
|
// videos area
|
||||||
|
var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 50;
|
||||||
|
|
||||||
var availableWidth = availableWinWidth / numvids;
|
var availableWidth = availableWinWidth / numvids;
|
||||||
var aspectRatio = 16.0 / 9.0;
|
var aspectRatio = 16.0 / 9.0;
|
||||||
var maxHeight = Math.min(160, availableHeight);
|
var maxHeight = Math.min(160, availableHeight);
|
||||||
|
@ -768,6 +770,10 @@ var VideoLayout = (function (my) {
|
||||||
var focusIndicator = document.createElement('i');
|
var focusIndicator = document.createElement('i');
|
||||||
focusIndicator.className = 'fa fa-star';
|
focusIndicator.className = 'fa fa-star';
|
||||||
parentElement.appendChild(focusIndicator);
|
parentElement.appendChild(focusIndicator);
|
||||||
|
|
||||||
|
Util.setTooltip(parentElement,
|
||||||
|
"The owner of<br/>this conference",
|
||||||
|
"top");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -799,10 +805,10 @@ var VideoLayout = (function (my) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current active speaker resource jid.
|
* Returns the current dominant speaker resource jid.
|
||||||
*/
|
*/
|
||||||
my.getActiveSpeakerResourceJid = function () {
|
my.getDominantSpeakerResourceJid = function () {
|
||||||
return currentActiveSpeaker;
|
return currentDominantSpeaker;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -920,21 +926,21 @@ var VideoLayout = (function (my) {
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On active speaker changed event.
|
* On dominant speaker changed event.
|
||||||
*/
|
*/
|
||||||
$(document).bind('activespeakerchanged', function (event, resourceJid) {
|
$(document).bind('dominantspeakerchanged', function (event, resourceJid) {
|
||||||
// We ignore local user events.
|
// We ignore local user events.
|
||||||
if (resourceJid
|
if (resourceJid
|
||||||
=== Strophe.getResourceFromJid(connection.emuc.myroomjid))
|
=== Strophe.getResourceFromJid(connection.emuc.myroomjid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Obtain container for new active speaker.
|
// Obtain container for new dominant speaker.
|
||||||
var container = document.getElementById(
|
var container = document.getElementById(
|
||||||
'participant_' + resourceJid);
|
'participant_' + resourceJid);
|
||||||
|
|
||||||
// Update the current active speaker.
|
// Update the current dominant speaker.
|
||||||
if (resourceJid !== currentActiveSpeaker)
|
if (resourceJid !== currentDominantSpeaker)
|
||||||
currentActiveSpeaker = resourceJid;
|
currentDominantSpeaker = resourceJid;
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue