Commit f2973b5f authored by Dele Olajide's avatar Dele Olajide Committed by dele

Jitsi Videobridge - Refresh jitmeet

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13980 b35dd754-fafc-0310-a699-88a17e54d16e
parent cb021ac3
/**
* Chat related user interface.
*/
var Chat = (function (my) {
var notificationInterval = false;
var unreadMessages = 0;
/**
* Initializes chat related interface.
*/
my.init = function () {
var storedDisplayName = window.localStorage.displayname;
if (storedDisplayName) {
nickname = storedDisplayName;
Chat.setChatConversationMode(true);
}
$('#nickinput').keydown(function(event) {
if (event.keyCode == 13) {
event.preventDefault();
var val = Util.escapeHtml(this.value);
this.value = '';
if (!nickname) {
nickname = val;
window.localStorage.displayname = nickname;
connection.emuc.addDisplayNameToPresence(nickname);
connection.emuc.sendPresence();
Chat.setChatConversationMode(true);
return;
}
}
});
$('#usermsg').keydown(function(event) {
if (event.keyCode == 13) {
event.preventDefault();
var message = Util.escapeHtml(this.value);
$('#usermsg').val('').trigger('autosize.resize');
this.focus();
connection.emuc.sendMessage(message, nickname);
}
});
var onTextAreaResize = function() {
resizeChatConversation();
scrollChatToBottom();
};
$('#usermsg').autosize({callback: onTextAreaResize});
$("#chatspace").bind("shown",
function() {
unreadMessages = 0;
setVisualNotification(false);
});
};
/**
* Appends the given message to the chat conversation.
*/
my.updateChatConversation = function (from, displayName, message) {
var divClassName = '';
if (connection.emuc.myroomjid == from) {
divClassName = "localuser";
}
else {
divClassName = "remoteuser";
if (!$('#chatspace').is(":visible")) {
unreadMessages++;
Util.playSoundNotification('chatNotification');
setVisualNotification(true);
}
}
//replace links and smileys
var escMessage = Util.escapeHtml(message);
var escDisplayName = Util.escapeHtml(displayName);
message = processReplacements(escMessage);
$('#chatconversation').append('<div class="' + divClassName + '"><b>'
+ escDisplayName + ': </b>'
+ message + '</div>');
$('#chatconversation').animate(
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
};
/**
* Opens / closes the chat area.
*/
my.toggleChat = function () {
var chatspace = $('#chatspace');
var videospace = $('#videospace');
var onShow = function () {
resizeLarge();
$('#chatspace').show("slide", { direction: "right", duration: 500});
};
var onHide = function () {
$('#chatspace').hide("slide", { direction: "right", duration: 500});
resizeLarge();
};
if (chatspace.is(":visible")) {
videospace.animate( {right: 0},
{queue: false,
duration: 500,
progress: onHide});
}
else {
videospace.animate({right: chatspace.width()},
{queue: false,
duration: 500,
progress: onShow,
complete: function() {
scrollChatToBottom();
chatspace.trigger('shown');
}
});
}
// Request the focus in the nickname field or the chat input field.
if ($('#nickname').css('visibility') == 'visible')
$('#nickinput').focus();
else {
$('#usermsg').focus();
}
};
/**
* Sets the chat conversation mode.
*/
my.setChatConversationMode = function (isConversationMode) {
if (isConversationMode) {
$('#nickname').css({visibility:"hidden"});
$('#chatconversation').css({visibility:'visible'});
$('#usermsg').css({visibility:'visible'});
$('#usermsg').focus();
}
};
/**
* Resizes the chat area.
*/
my.resizeChat = function () {
var availableHeight = window.innerHeight;
var availableWidth = window.innerWidth;
var chatWidth = 200;
if (availableWidth*0.2 < 200)
chatWidth = availableWidth*0.2;
$('#chatspace').width(chatWidth);
$('#chatspace').height(availableHeight - 40);
resizeChatConversation();
};
/**
* Resizes the chat conversation.
*/
function resizeChatConversation() {
var usermsgStyleHeight = document.getElementById("usermsg").style.height;
var usermsgHeight = usermsgStyleHeight
.substring(0, usermsgStyleHeight.indexOf('px'));
$('#chatconversation').width($('#chatspace').width() - 10);
$('#chatconversation')
.height(window.innerHeight - 50 - parseInt(usermsgHeight));
};
/**
* Shows/hides a visual notification, indicating that a message has arrived.
*/
function setVisualNotification(show) {
var unreadMsgElement = document.getElementById('unreadMessages');
if (unreadMessages) {
unreadMsgElement.innerHTML = unreadMessages.toString();
var chatButtonElement
= document.getElementById('chat').parentNode;
var leftIndent = (Util.getTextWidth(chatButtonElement)
- Util.getTextWidth(unreadMsgElement) - 5)/2;
var topIndent = (Util.getTextHeight(chatButtonElement)
- Util.getTextHeight(unreadMsgElement))/2 - 2;
unreadMsgElement.setAttribute(
'style',
'top:' + topIndent
+ '; left:' + leftIndent +';');
}
else
unreadMsgElement.innerHTML = '';
var glower = $('#chat');
if (show && !notificationInterval) {
notificationInterval = window.setInterval(function() {
glower.toggleClass('active');
}, 800);
}
else if (!show && notificationInterval) {
window.clearInterval(notificationInterval);
notificationInterval = false;
glower.removeClass('active');
}
}
/**
* Scrolls chat to the bottom.
*/
function scrollChatToBottom() {
setTimeout(function() {
$('#chatconversation').scrollTop(
$('#chatconversation')[0].scrollHeight);
}, 5);
}
return my;
}(Chat || {}));
\ No newline at end of file
<html>
<head>
<title></title>
<title>JitMeet: Unsupported Browser</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/chromeonly.css" />
</head>
......@@ -10,8 +10,9 @@
<a href="http://google.com/chrome"><div id="left"></div></a>
<div id="middle"></div>
<div id="text">
<p>This service only works with Chrome.</p>
<p>This application is currently only supported by <a href="http://google.com/chrome">Chrome</a>, <a href="http://www.chromium.org/">Chromium</a> and <a href="http://www.opera.com">Opera</a></p>
<p><a href="http://google.com/chrome">Download Chrome</a></p>
<p class="firefox">We are hoping that <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977864">multistream support</a> for Firefox would not be long so that we could all use this application with our favorite browser.</p>
</div>
<!-- wrap ends here -->
</div>
......
......@@ -10,7 +10,7 @@ body {
#wrap{
display: block;
position: absolute;
width:766px;
width:900px;
height: 262px;
overflow:hidden;
text-align: center;
......@@ -25,6 +25,10 @@ body {
height:262px;
float: left;
}
.firefox{
font-size: 11pt;
color: #c8c8c8;
}
#middle{
display:inline-block;
background-image:url(../images/chromepointer.png);
......@@ -35,8 +39,8 @@ body {
}
#text{
display:inline-block;
font-size: 20pt;
width: 400px;
font-size: 18pt;
width: 560px;
vertical-align:middle;
padding-top: 30px;
}
......
......@@ -35,6 +35,10 @@ html, body{
z-index: 0;
}
#etherpadButton {
display: none;
}
.videocontainer>span {
display: none; /* enable when you want nicks to be shown */
position: absolute;
......@@ -222,6 +226,11 @@ html, body{
visibility: hidden;
}
.toolbar_span {
display: inline-block;
position: relative;
}
.button {
display: inline-block;
position: relative;
......@@ -233,6 +242,30 @@ html, body{
font-size: 11pt;
text-align: center;
text-shadow: 0px 1px 0px rgba(255,255,255,.3), 0px -1px 0px rgba(0,0,0,.7);
z-index: 1;
}
.toolbar_span>span {
display: inline-block;
position: absolute;
font-size: 7pt;
color: #ffffff;
text-align:center;
cursor: pointer;
}
#chat {
font-size:1.65em;
-webkit-transition: all .5s ease-in-out;;
-moz-transition: all .5s ease-in-out;;
transition: all .5s ease-in-out;;
}
#chat.active {
-webkit-text-shadow: 0 0 10px #ffffff;
-moz-text-shadow: 0 0 10px #ffffff;
text-shadow: 0 0 10px #ffffff;
/* -webkit-transform: scale(1.1); */
}
a.button:hover {
......
......@@ -15,15 +15,16 @@ var Etherpad = (function (my) {
if (!name) {
// In case we're the focus we generate the name.
etherpadName = Math.random().toString(36).substring(7) + '_' + (new Date().getTime()).toString();
etherpadName = Math.random().toString(36).substring(7)
+ '_' + (new Date().getTime()).toString();
shareEtherpad();
}
else
etherpadName = name;
createEtherpadButton();
}
enableEtherpadButton();
}
};
/**
* Opens/hides the Etherpad.
......@@ -76,26 +77,9 @@ var Etherpad = (function (my) {
/**
* Creates the Etherpad button and adds it to the toolbar.
*/
function createEtherpadButton() {
//<div class="header_button_separator"></div>
//<a class="button" onclick='Etherpad.openEtherpad("teeest");'>
//<i title="Open shared document" class="fa fa-file-text fa-lg"></i></a>
var separator = document.createElement('div');
separator.className = 'header_button_separator';
var button = document.createElement('a');
button.className = 'button';
button.setAttribute('onclick', 'Etherpad.toggleEtherpad(0);');
var buttonImage = document.createElement('i');
buttonImage.setAttribute('title', 'Open shared document');
buttonImage.className = 'fa fa-file-text fa-lg';
button.appendChild(buttonImage);
var toolbar = document.getElementById('toolbar');
toolbar.insertBefore(button, toolbar.childNodes[toolbar.childNodes.length - 4]);
toolbar.insertBefore(separator, button);
function enableEtherpadButton() {
if (!$('#etherpadButton').is(":visible"))
$('#etherpadButton').css({display:'inline-block'});
}
/**
......
......@@ -5,14 +5,16 @@
<script src="libs/strophejingle.bundle.js?v=7"></script><!-- strophe.jingle bundle -->
<script src="libs/colibri.js?v=7"></script><!-- colibri focus implementation -->
<script src="//code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script src="muc.js?v=6"></script><!-- simple MUC library -->
<script src="muc.js?v=9"></script><!-- simple MUC library -->
<script src="estos_log.js?v=2"></script><!-- simple stanza logger -->
<script src="app.js?v=20"></script><!-- application logic -->
<script src="etherpad.js?v=2"></script><!-- etherpad plugin -->
<script src="app.js?v=23"></script><!-- application logic -->
<script src="chat.js?v=3"></script><!-- chat logic -->
<script src="util.js?v=2"></script><!-- utility functions -->
<script src="etherpad.js?v=5"></script><!-- etherpad plugin -->
<script src="smileys.js?v=1"></script><!-- smiley images -->
<script src="replacement.js?v=5"></script><!-- link and smiley replacement -->
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=17"/>
<link rel="stylesheet" type="text/css" media="screen" href="css/main.css?v=19"/>
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3">
<script src="libs/jquery-impromptu.js"></script>
......@@ -25,17 +27,26 @@
<a href="http://jitsi.org" target="_blank"><div id="leftlogo"></div></a>
<a href="http://www.estos.com/" target="_blank"><div id="rightlogo"></div></a>
<span id="toolbar">
<a class="button" onclick='buttonClick("#mute", "fa fa-microphone fa-lg fa fa-microphone-slash fa-lg");toggleAudio();'><i id="mute" title="Mute / unmute" class="fa fa-microphone fa-lg"></i></a>
<a class="button" onclick='buttonClick("#mute", "fa fa-microphone fa-lg fa fa-microphone-slash fa-lg");toggleAudio();'>
<i id="mute" title="Mute / unmute" class="fa fa-microphone fa-lg"></i></a>
<div class="header_button_separator"></div>
<a class="button" onclick='buttonClick("#video", "fa fa-video-camera fa-lg fa fa-video-camera no-fa-video-camera fa-lg");toggleVideo();'><i id="video" title="Start / stop camera" class="fa fa-video-camera fa-lg"></i></a>
<a class="button" onclick='buttonClick("#video", "fa fa-video-camera fa-lg fa fa-video-camera no-fa-video-camera fa-lg");toggleVideo();'>
<i id="video" title="Start / stop camera" class="fa fa-video-camera fa-lg"></i></a>
<div class="header_button_separator"></div>
<a class="button" onclick="openLockDialog();"><i id="lockIcon" title="Lock/unlock room" class="fa fa-unlock fa-lg"></i></a>
<div class="header_button_separator"></div>
<a class="button" onclick="openLinkDialog();"><i title="Invite others" class="fa fa-link fa-lg"></i></a>
<div class="header_button_separator"></div>
<a class="button" onclick='openChat();'><i id="chat" title="Open chat" class="fa fa-comments fa-lg"></i></a>
<span class="toolbar_span">
<a class="button" onclick='Chat.toggleChat();'><i id="chat" title="Open chat" class="fa fa-comments-o fa-lg"></i></a>
<span id="unreadMessages"></span>
</span>
<div class="header_button_separator"></div>
<a class="button" onclick='openPreziDialog();'><i title="Share prezi" class="fa fa-picture-o fa-lg"></i></a>
<span id="etherpadButton">
<div class="header_button_separator"></div>
<a class="button" onclick='openPreziDialog();'><i title="Share prezi" class="fa fa-desktop fa-lg"></i></a>
<a class="button" onclick='Etherpad.toggleEtherpad(0);'><i title="Open shared document" class="fa fa-file-text fa-lg"></i></a>
</span>
<div class="header_button_separator"></div>
<a class="button" onclick='toggleFullScreen();'><i title="Enter / Exit Full Screen" class="fa fa-arrows-alt fa-lg"></i></a>
</span>
......@@ -65,6 +76,8 @@
<video id="localVideo" autoplay oncontextmenu="return false;" muted></video>
<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>
</div>
</div>
<div id="chatspace">
......@@ -77,6 +90,7 @@
<!--div><i class="fa fa-comments">&nbsp;</i><span class='nick'></span>:&nbsp;<span class='chattext'></span></div-->
<div id="chatconversation"></div>
<audio id="chatNotification" src="sounds/incomingMessage.wav" preload="auto"></audio>
<textarea id="usermsg" placeholder='Enter text...' autofocus></textarea>
</div>
<a id="downloadlog" onclick='dump(event.target);'><i title="Download support information" class="fa fa-cloud-download"></i></a>
......
......@@ -55,6 +55,8 @@ function ColibriFocus(connection, bridgejid) {
this.addssrc = [];
// ssrc lines to be removed on next update
this.removessrc = [];
// pending mute/unmute video op that modify local description
this.pendingop = null;
// container for candidates from the focus
// gathered before confid is known
......@@ -118,11 +120,7 @@ ColibriFocus.prototype.makeConference = function (peers) {
console.log('end of candidates');
return;
}
if (self.confid === 0) {
self.drip_container.push(event.candidate);
} else {
self.sendIceCandidate(event.candidate);
}
};
this._makeConference();
/*
......@@ -712,12 +710,21 @@ ColibriFocus.prototype.addIceCandidate = function (session, elem) {
// send our own candidate to the bridge
ColibriFocus.prototype.sendIceCandidate = function (candidate) {
var self = this;
//console.log('candidate', candidate);
if (!candidate) {
console.log('end of candidates');
return;
}
this.sendIceCandidates([candidate]);
if (this.drip_container.length === 0) {
// start 20ms callout
window.setTimeout(function () {
if (self.drip_container.length === 0) return;
self.sendIceCandidates(self.drip_container);
self.drip_container = [];
}, 20);
}
this.drip_container.push(candidate);
};
// sort and send multiple candidates
......@@ -802,8 +809,8 @@ ColibriFocus.prototype.terminate = function (session, reason) {
ColibriFocus.prototype.modifySources = function () {
var self = this;
if (!(this.addssrc.length || this.removessrc.length)) return;
if (this.peerconnection.signalingState == 'closed') return;
if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null)) return;
// FIXME: this is a big hack
// https://code.google.com/p/webrtc/issues/detail?id=2688
......@@ -844,6 +851,25 @@ ColibriFocus.prototype.modifySources = function () {
self.peerconnection.createAnswer(
function (modifiedAnswer) {
console.log('modifiedAnswer created');
// change video direction, see https://github.com/jitsi/jitmeet/issues/41
if (self.pendingop !== null) {
var sdp = new SDP(modifiedAnswer.sdp);
if (sdp.media.length > 1) {
switch(self.pendingop) {
case 'mute':
sdp.media[1] = sdp.media[1].replace('a=sendrecv', 'a=recvonly');
break;
case 'unmute':
sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
break;
}
sdp.raw = sdp.session + sdp.media.join('');
modifiedAnswer.sdp = sdp.raw;
}
self.pendingop = null;
}
// FIXME: pushing down an answer while ice connection state
// is still checking is bad...
//console.log(self.peerconnection.iceConnectionState);
......@@ -900,6 +926,15 @@ ColibriFocus.prototype.modifySources = function () {
*/
};
ColibriFocus.prototype.hardMuteVideo = function (muted) {
this.pendingop = muted ? 'mute' : 'unmute';
this.modifySources();
this.connection.jingle.localStream.getVideoTracks().forEach(function (track) {
track.enabled = !muted;
});
};
// A colibri session is similar to a jingle session, it just implements some things differently
// FIXME: inherit jinglesession, see https://github.com/legastero/Jingle-RTCPeerConnection/blob/master/index.js
function ColibriSession(me, sid, connection) {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -139,11 +139,12 @@ Strophe.addConnectionPlugin('emuc', {
var txt = $(msg).find('>body').text();
// TODO: <subject/>
// FIXME: this is a hack. but jingle on muc makes nickchanges hard
var nick = $(msg).find('>nick[xmlns="http://jabber.org/protocol/nick"]').text() || Strophe.getResourceFromJid(msg.getAttribute('from'));
var from = msg.getAttribute('from');
var nick = $(msg).find('>nick[xmlns="http://jabber.org/protocol/nick"]').text() || Strophe.getResourceFromJid(from);
if (txt) {
console.log('chat', nick, txt);
updateChatConversation(nick, txt);
Chat.updateChatConversation(from, nick, txt);
}
return true;
},
......@@ -209,10 +210,12 @@ Strophe.addConnectionPlugin('emuc', {
}
});
if (sourceNumber > 0)
for (var i = 1; i <= sourceNumber/2; i ++) {
for (var i = 1; i <= sourceNumber/3; i ++) {
pres.c('source',
{type: this.presMap['source' + i + '_type'],
ssrc: this.presMap['source' + i + '_ssrc']}).up();
ssrc: this.presMap['source' + i + '_ssrc'],
direction: this.presMap['source'+ i + '_direction'] || 'sendrecv' }
).up();
}
}
pres.up();
......@@ -221,12 +224,13 @@ Strophe.addConnectionPlugin('emuc', {
addDisplayNameToPresence: function (displayName) {
this.presMap['displayName'] = displayName;
},
addMediaToPresence: function (sourceNumber, mtype, ssrcs) {
addMediaToPresence: function (sourceNumber, mtype, ssrcs, direction) {
if (!this.presMap['medians'])
this.presMap['medians'] = 'http://estos.de/ns/mjs';
this.presMap['source' + sourceNumber + '_type'] = mtype;
this.presMap['source' + sourceNumber + '_ssrc'] = ssrcs;
this.presMap['source' + sourceNumber + '_direction'] = direction;
},
addPreziToPresence: function (url, currentSlide) {
this.presMap['prezins'] = 'http://jitsi.org/jitmeet/prezi';
......
/**
* Utility functions.
*/
var Util = (function (my) {
/**
* Returns the text width for the given element.
*
* @param el the element
*/
my.getTextWidth = function(el) {
return (el.clientWidth + 1);
};
/**
* Returns the text height for the given element.
*
* @param el the element
*/
my.getTextHeight = function(el) {
return (el.clientHeight + 1);
};
/**
* Casts the given number to integer.
*
* @param number the number to cast
*/
my.toInteger = function(number) {
return Math.round(Number(number));
};
/**
* Plays the sound given by id.
*
* @param id the identifier of the audio element.
*/
my.playSoundNotification = function(id) {
document.getElementById(id).play();
};
/**
* Escapes the given text.
*/
my.escapeHtml = function(unsafeText) {
return $('<div/>').text(unsafeText).html();
};
/**
* Indicates if the given string is an alphanumeric string.
* Note that some special characters are also allowed (-, _ , /) for the
* purpose of checking URIs. (FIXME: This should maybe moved to another not
* so generic method in the future.)
*/
my.isAlphanumeric = function(unsafeText) {
var regex = /^[a-z0-9-_\/]+$/i;
return regex.test(unsafeText);
};
return my;
}(Util || {}));
\ No newline at end of file
......@@ -1069,11 +1069,15 @@ public class PluginImpl implements Plugin, PropertyEventListener
if (this.mediaStream != null)
{
mediaStream.removePropertyChangeListener(streamPropertyChangeListener);
if (recorder != null)
{
recorder.done();
recorder = null;
}
}
}
}
public class FocusAgent extends VirtualConnection
{
......@@ -1588,7 +1592,7 @@ public class PluginImpl implements Plugin, PropertyEventListener
String recordingPath = JiveGlobals.getHomeDirectory() + File.separator + "resources" + File.separator + "spank" + File.separator + "rayo" + File.separator + "video_recordings";
String fileName = "audio-" + focusName + "-" + System.currentTimeMillis() + ".au";
boolean pcmu = format.getEncoding() == AudioFormat.ULAW;
int sampleRate = (int) Math.round(format.getSampleRate());
int sampleRate = (int) format.getSampleRate();
int channels = format.getChannels();
recorder = new Recorder(recordingPath, fileName, "au", true, sampleRate, channels);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment