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
|
||||
// current active or focused speaker.
|
||||
if (!focusedVideoSrc && !VideoLayout.getActiveSpeakerResourceJid())
|
||||
if (!focusedVideoSrc && !VideoLayout.getDominantSpeakerResourceJid())
|
||||
VideoLayout.updateLargeVideo(videoelem.attr('src'), 1);
|
||||
|
||||
VideoLayout.showFocusIndicator();
|
||||
|
|
33
chat.js
33
chat.js
|
@ -115,8 +115,7 @@ var Chat = (function (my) {
|
|||
+ '</div>');
|
||||
$('#chatconversation').animate(
|
||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the subject to the UI
|
||||
|
@ -135,8 +134,7 @@ var Chat = (function (my) {
|
|||
{
|
||||
$("#subject").css({display: "block"});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Opens / closes the chat area.
|
||||
|
@ -159,6 +157,10 @@ var Chat = (function (my) {
|
|||
var horizontalIndent = videoPosition[0];
|
||||
var verticalIndent = videoPosition[1];
|
||||
|
||||
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
|
||||
var thumbnailsWidth = thumbnailSize[0];
|
||||
var thumbnailsHeight = thumbnailSize[1];
|
||||
|
||||
if (chatspace.is(":visible")) {
|
||||
videospace.animate({right: chatSize[0],
|
||||
width: videospaceWidth,
|
||||
|
@ -166,6 +168,15 @@ var Chat = (function (my) {
|
|||
{queue: false,
|
||||
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,
|
||||
height: videospaceHeight},
|
||||
{queue: false,
|
||||
|
@ -187,6 +198,9 @@ var Chat = (function (my) {
|
|||
duration: 500});
|
||||
}
|
||||
else {
|
||||
// Undock the toolbar when the chat is shown.
|
||||
Toolbar.dockToolbar(false);
|
||||
|
||||
videospace.animate({right: chatSize[0],
|
||||
width: videospaceWidth,
|
||||
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,
|
||||
height: videospaceHeight},
|
||||
{queue: false,
|
||||
|
@ -290,7 +313,7 @@ var Chat = (function (my) {
|
|||
if (unreadMessages) {
|
||||
unreadMsgElement.innerHTML = unreadMessages.toString();
|
||||
|
||||
Toolbar.showToolbar();
|
||||
Toolbar.dockToolbar(true);
|
||||
|
||||
var chatButtonElement
|
||||
= document.getElementById('chatButton').parentNode;
|
||||
|
|
|
@ -13,6 +13,7 @@ var config = {
|
|||
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
|
||||
minChromeExtVersion: '0.1', // Required version of Chrome extension
|
||||
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
|
||||
};
|
||||
|
|
23
css/main.css
23
css/main.css
|
@ -131,15 +131,24 @@ html, body{
|
|||
}
|
||||
|
||||
#chatButton {
|
||||
-webkit-transition: all .5s ease-in-out;;
|
||||
-moz-transition: all .5s ease-in-out;;
|
||||
transition: all .5s ease-in-out;;
|
||||
-webkit-transition: all .5s ease-in-out;
|
||||
-moz-transition: all .5s ease-in-out;
|
||||
transition: all .5s ease-in-out;
|
||||
}
|
||||
|
||||
/*#ffde00*/
|
||||
#chatButton.active {
|
||||
-webkit-text-shadow: 0 0 10px #ffffff;
|
||||
-moz-text-shadow: 0 0 10px #ffffff;
|
||||
text-shadow: 0 0 10px #ffffff;
|
||||
-webkit-text-shadow: -1px 0 10px #00ccff,
|
||||
0 1px 10px #00ccff,
|
||||
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 {
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.activespeaker {
|
||||
.dominantspeaker {
|
||||
background: #000 !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ function onDataChannel(event)
|
|||
|
||||
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
|
||||
// Sends String message to the bridge
|
||||
|
@ -26,18 +26,56 @@ function onDataChannel(event)
|
|||
|
||||
dataChannel.onmessage = function (event)
|
||||
{
|
||||
var msgData = event.data;
|
||||
console.info("Got Data Channel Message:", msgData, dataChannel);
|
||||
var data = event.data;
|
||||
// JSON
|
||||
var obj;
|
||||
|
||||
// Active speaker event
|
||||
if (msgData.indexOf('activeSpeaker') === 0)
|
||||
try
|
||||
{
|
||||
// Endpoint ID from the bridge
|
||||
var resourceJid = msgData.split(":")[1];
|
||||
obj = JSON.parse(data);
|
||||
}
|
||||
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(
|
||||
"Data channel new active speaker event: " + resourceJid);
|
||||
$(document).trigger('activespeakerchanged', [resourceJid]);
|
||||
if ("DominantSpeakerEndpointChangeEvent" === colibriClass)
|
||||
{
|
||||
// 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);
|
||||
};*/
|
||||
}
|
||||
|
||||
|
|
12
index.html
12
index.html
|
@ -27,9 +27,9 @@
|
|||
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
|
||||
<script src="desktopsharing.js?v=2"></script><!-- desktop sharing -->
|
||||
<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="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="etherpad.js?v=8"></script><!-- etherpad 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="rtp_stats.js?v=1"></script><!-- RTP stats processing -->
|
||||
<script src="local_stats.js?v=1"></script><!-- Local stats processing -->
|
||||
<script src="videolayout.js?v=4"></script><!-- video ui -->
|
||||
<script src="toolbar.js?v=2"></script><!-- toolbar ui -->
|
||||
<script src="videolayout.js?v=6"></script><!-- video 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 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" href="css/jquery-impromptu.css?v=4">
|
||||
<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 -->
|
||||
</span>
|
||||
<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>
|
||||
<audio id="userJoined" src="sounds/joined.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.
|
||||
* @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
|
||||
if (config.openSctp)
|
||||
{
|
||||
this.media = ['audio', 'video', 'data'];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.media = ['audio', 'video'];
|
||||
}
|
||||
|
||||
this.connection.jingle.sessions[this.sid] = this;
|
||||
this.mychannel = [];
|
||||
|
@ -202,29 +207,33 @@ ColibriFocus.prototype._makeConference = function () {
|
|||
elem.c('conference', {xmlns: 'http://jitsi.org/protocol/colibri'});
|
||||
|
||||
this.media.forEach(function (name) {
|
||||
var isData = name === 'data';
|
||||
var channel = isData ? 'sctpconnection' : 'channel';
|
||||
var elemName;
|
||||
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(channel, {
|
||||
initiator: 'true',
|
||||
expire: '15',
|
||||
endpoint: self.myMucResource
|
||||
});
|
||||
if (isData)
|
||||
elem.attrs({port: 5000});
|
||||
elem.up();// end of channel
|
||||
elem.c(elemName, elemAttrs);
|
||||
elem.attrs({ endpoint: self.myMucResource });
|
||||
elem.up();// end of channel/sctpconnection
|
||||
|
||||
for (var j = 0; j < self.peers.length; j++) {
|
||||
elem.c(channel, {
|
||||
initiator: 'true',
|
||||
expire: '15',
|
||||
endpoint: self.peers[j].substr(1 + self.peers[j].lastIndexOf('/'))
|
||||
});
|
||||
if (isData)
|
||||
elem.attrs({port: 5000});
|
||||
elem.up(); // end of channel
|
||||
var peer = self.peers[j];
|
||||
|
||||
elem.c(elemName, elemAttrs);
|
||||
elem.attrs({ endpoint: peer.substr(1 + peer.lastIndexOf('/')) });
|
||||
elem.up(); // end of channel/sctpconnection
|
||||
}
|
||||
elem.up(); // end of content
|
||||
});
|
||||
|
@ -233,7 +242,7 @@ ColibriFocus.prototype._makeConference = function () {
|
|||
localSDP.media.forEach(function (media, channel) {
|
||||
var name = SDPUtil.parse_mline(media.split('\r\n')[0]).media;
|
||||
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
|
||||
var mline = SDPUtil.parse_mline(media.split('\r\n')[0]);
|
||||
|
@ -247,7 +256,7 @@ ColibriFocus.prototype._makeConference = function () {
|
|||
|
||||
elem.up(); // end of channel
|
||||
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
|
||||
});
|
||||
|
@ -540,7 +549,8 @@ ColibriFocus.prototype.initiate = function (peer, isInitiator) {
|
|||
if (1) { //i > 0) { // not for audio FIXME: does not work as intended
|
||||
// re-add all remote a=ssrcs
|
||||
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];
|
||||
}
|
||||
// and local a=ssrc lines
|
||||
|
@ -661,24 +671,28 @@ ColibriFocus.prototype.addNewParticipant = function (peer) {
|
|||
var localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
||||
localSDP.media.forEach(function (media, channel) {
|
||||
var name = SDPUtil.parse_mid(SDPUtil.find_line(media, 'a=mid:'));
|
||||
elem.c('content', {name: name});
|
||||
if (name !== 'data')
|
||||
{
|
||||
elem.c('channel', {
|
||||
var elemName;
|
||||
var elemAttrs
|
||||
= {
|
||||
initiator: 'true',
|
||||
expire: self.channelExpire,
|
||||
endpoint: peer.substr(1 + peer.lastIndexOf('/'))
|
||||
});
|
||||
};
|
||||
|
||||
if ('data' == name)
|
||||
{
|
||||
elemName = 'sctpconnection';
|
||||
elemAttrs['port'] = 5000;
|
||||
}
|
||||
else
|
||||
{
|
||||
elem.c('sctpconnection', {
|
||||
endpoint: peer.substr(1 + peer.lastIndexOf('/')),
|
||||
initiator: 'true',
|
||||
expire: self.channelExpire,
|
||||
port: 5000
|
||||
});
|
||||
elemName = 'channel';
|
||||
if (('video' === name) && (this.channelLastN >= 0))
|
||||
elemAttrs['last-n'] = this.channelLastN;
|
||||
}
|
||||
|
||||
elem.c('content', {name: name});
|
||||
elem.c(elemName, elemAttrs);
|
||||
elem.up(); // end of channel/sctpconnection
|
||||
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});
|
||||
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:'));
|
||||
change.c('content', {name: name});
|
||||
if (name !== 'data')
|
||||
|
@ -894,6 +911,9 @@ ColibriFocus.prototype.setRemoteDescription = function (session, elem, desctype)
|
|||
this.remotessrc[session.peerjid] = [];
|
||||
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
||||
//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)
|
||||
{
|
||||
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
|
||||
for (channel = 0; channel < this.channels[participant].length; channel++) {
|
||||
//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) {
|
||||
this.peerconnection.enqueueAddSsrc(
|
||||
channel,
|
||||
|
@ -1153,3 +1176,73 @@ ColibriFocus.prototype.sendTerminate = function (session, reason, text) {
|
|||
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 = {
|
||||
mandatory: {
|
||||
chromeMediaSource: "screen",
|
||||
googLeakyBucket: true,
|
||||
maxWidth: window.screen.width,
|
||||
maxHeight: window.screen.height,
|
||||
maxFrameRate: 3
|
||||
|
@ -530,6 +531,7 @@ function getUserMediaWithConstraints(um, success_callback, failure_callback, res
|
|||
mandatory: {
|
||||
chromeMediaSource: "desktop",
|
||||
chromeMediaSourceId: desktopStream,
|
||||
googLeakyBucket: true,
|
||||
maxWidth: window.screen.width,
|
||||
maxHeight: window.screen.height,
|
||||
maxFrameRate: 3
|
||||
|
|
82
toolbar.js
82
toolbar.js
|
@ -5,7 +5,7 @@ var Toolbar = (function (my) {
|
|||
/**
|
||||
* Opens the lock room dialog.
|
||||
*/
|
||||
my.openLockDialog = function() {
|
||||
my.openLockDialog = function () {
|
||||
// Only the focus is able to set a shared key.
|
||||
if (focus === null) {
|
||||
if (sharedKey)
|
||||
|
@ -70,24 +70,75 @@ var Toolbar = (function (my) {
|
|||
/**
|
||||
* 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="' +
|
||||
encodeURI(roomUrl) + '" onclick="this.select();" readonly>',
|
||||
{
|
||||
title: "Share this link with everyone you want to invite",
|
||||
persistent: false,
|
||||
buttons: { "Cancel": false},
|
||||
loaded: function (event) {
|
||||
document.getElementById('inviteLinkRef').select();
|
||||
inviteLink + '" onclick="this.select();" readonly>',
|
||||
{
|
||||
title: "Share this link with everyone you want to invite",
|
||||
persistent: false,
|
||||
buttons: { "Invite": true, "Cancel": false},
|
||||
defaultButton: 1,
|
||||
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.
|
||||
*/
|
||||
my.openSettingsDialog = function() {
|
||||
my.openSettingsDialog = function () {
|
||||
$.prompt('<h2>Configure your conference</h2>' +
|
||||
'<input type="checkbox" id="initMuted"> Participants join muted<br/>' +
|
||||
'<input type="checkbox" id="requireNicknames"> Require nicknames<br/><br/>' +
|
||||
|
@ -185,9 +236,12 @@ var Toolbar = (function (my) {
|
|||
if (!$('#header').is(':visible')) {
|
||||
Toolbar.showToolbar();
|
||||
}
|
||||
|
||||
// Then clear the time out, to dock the toolbar.
|
||||
clearTimeout(toolbarTimeout);
|
||||
toolbarTimeout = null;
|
||||
if (toolbarTimeout) {
|
||||
clearTimeout(toolbarTimeout);
|
||||
toolbarTimeout = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!$('#header').is(':visible')) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var VideoLayout = (function (my) {
|
||||
var preMuted = false;
|
||||
var currentActiveSpeaker = null;
|
||||
var currentDominantSpeaker = null;
|
||||
|
||||
my.changeLocalAudio = function(stream) {
|
||||
connection.jingle.localAudio = stream;
|
||||
|
@ -139,19 +139,19 @@ var VideoLayout = (function (my) {
|
|||
|
||||
if (isVisible) {
|
||||
// Only if the large video is currently visible.
|
||||
// Disable previous active speaker video.
|
||||
// Disable previous dominant speaker video.
|
||||
var oldJid = getJidFromVideoSrc(oldSrc);
|
||||
if (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);
|
||||
if (userJid)
|
||||
{
|
||||
var resourceJid = Strophe.getResourceFromJid(userJid);
|
||||
VideoLayout.enableActiveSpeaker(resourceJid, true);
|
||||
VideoLayout.enableDominantSpeaker(resourceJid, true);
|
||||
}
|
||||
|
||||
$(this).fadeIn(300);
|
||||
|
@ -173,15 +173,15 @@ var VideoLayout = (function (my) {
|
|||
if (focusedVideoSrc === videoSrc)
|
||||
{
|
||||
focusedVideoSrc = null;
|
||||
var activeSpeakerVideo = null;
|
||||
// Enable the currently set active speaker.
|
||||
if (currentActiveSpeaker) {
|
||||
activeSpeakerVideo
|
||||
= $('#participant_' + currentActiveSpeaker + '>video')
|
||||
var dominantSpeakerVideo = null;
|
||||
// Enable the currently set dominant speaker.
|
||||
if (currentDominantSpeaker) {
|
||||
dominantSpeakerVideo
|
||||
= $('#participant_' + currentDominantSpeaker + '>video')
|
||||
.get(0);
|
||||
|
||||
if (activeSpeakerVideo)
|
||||
VideoLayout.updateLargeVideo(activeSpeakerVideo.src, 1);
|
||||
if (dominantSpeakerVideo)
|
||||
VideoLayout.updateLargeVideo(dominantSpeakerVideo.src, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -254,12 +254,12 @@ var VideoLayout = (function (my) {
|
|||
if (isVisible) {
|
||||
$('#largeVideo').css({visibility: 'visible'});
|
||||
$('.watermark').css({visibility: 'visible'});
|
||||
VideoLayout.enableActiveSpeaker(resourceJid, true);
|
||||
VideoLayout.enableDominantSpeaker(resourceJid, true);
|
||||
}
|
||||
else {
|
||||
$('#largeVideo').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) {
|
||||
indicatorSpan = document.createElement('span');
|
||||
indicatorSpan.className = 'focusindicator';
|
||||
Util.setTooltip(indicatorSpan,
|
||||
"The owner of<br/>this conference",
|
||||
"top");
|
||||
|
||||
focusContainer.appendChild(indicatorSpan);
|
||||
|
||||
createFocusIndicatorElement(indicatorSpan);
|
||||
|
@ -570,7 +568,9 @@ var VideoLayout = (function (my) {
|
|||
* Resizes thumbnails.
|
||||
*/
|
||||
my.resizeThumbnails = function() {
|
||||
var thumbnailSize = calculateThumbnailSize();
|
||||
var videoSpaceWidth = $('#remoteVideos').width();
|
||||
|
||||
var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
|
||||
var width = thumbnailSize[0];
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
my.enableActiveSpeaker = function(resourceJid, isEnable) {
|
||||
my.enableDominantSpeaker = function(resourceJid, isEnable) {
|
||||
var displayName = resourceJid;
|
||||
var nameSpan = $('#participant_' + resourceJid + '>span.displayname');
|
||||
if (nameSpan.length > 0)
|
||||
displayName = nameSpan.text();
|
||||
|
||||
console.log("UI enable active speaker",
|
||||
console.log("UI enable dominant speaker",
|
||||
displayName,
|
||||
resourceJid,
|
||||
isEnable);
|
||||
|
@ -625,16 +625,16 @@ var VideoLayout = (function (my) {
|
|||
if (isEnable) {
|
||||
VideoLayout.showDisplayName(videoContainerId, true);
|
||||
|
||||
if (!videoSpan.classList.contains("activespeaker"))
|
||||
videoSpan.classList.add("activespeaker");
|
||||
if (!videoSpan.classList.contains("dominantspeaker"))
|
||||
videoSpan.classList.add("dominantspeaker");
|
||||
|
||||
video.css({visibility: 'hidden'});
|
||||
}
|
||||
else {
|
||||
VideoLayout.showDisplayName(videoContainerId, false);
|
||||
|
||||
if (videoSpan.classList.contains("activespeaker"))
|
||||
videoSpan.classList.remove("activespeaker");
|
||||
if (videoSpan.classList.contains("dominantspeaker"))
|
||||
videoSpan.classList.remove("dominantspeaker");
|
||||
|
||||
video.css({visibility: 'visible'});
|
||||
}
|
||||
|
@ -682,7 +682,7 @@ var VideoLayout = (function (my) {
|
|||
/**
|
||||
* Calculates the thumbnail size.
|
||||
*/
|
||||
var calculateThumbnailSize = function () {
|
||||
my.calculateThumbnailSize = function (videoSpaceWidth) {
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
// Remove the 1px borders arround videos and the chat width.
|
||||
var availableWinWidth = $('#remoteVideos').width() - 2 * numvids - 50;
|
||||
// Remove the 3px borders arround videos and border around the remote
|
||||
// videos area
|
||||
var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 50;
|
||||
|
||||
var availableWidth = availableWinWidth / numvids;
|
||||
var aspectRatio = 16.0 / 9.0;
|
||||
var maxHeight = Math.min(160, availableHeight);
|
||||
|
@ -768,6 +770,10 @@ var VideoLayout = (function (my) {
|
|||
var focusIndicator = document.createElement('i');
|
||||
focusIndicator.className = 'fa fa-star';
|
||||
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 () {
|
||||
return currentActiveSpeaker;
|
||||
my.getDominantSpeakerResourceJid = function () {
|
||||
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.
|
||||
if (resourceJid
|
||||
=== Strophe.getResourceFromJid(connection.emuc.myroomjid))
|
||||
return;
|
||||
|
||||
// Obtain container for new active speaker.
|
||||
// Obtain container for new dominant speaker.
|
||||
var container = document.getElementById(
|
||||
'participant_' + resourceJid);
|
||||
|
||||
// Update the current active speaker.
|
||||
if (resourceJid !== currentActiveSpeaker)
|
||||
currentActiveSpeaker = resourceJid;
|
||||
// Update the current dominant speaker.
|
||||
if (resourceJid !== currentDominantSpeaker)
|
||||
currentDominantSpeaker = resourceJid;
|
||||
else
|
||||
return;
|
||||
|
||||
|
|
Loading…
Reference in New Issue