@ -0,0 +1,217 @@ |
||||
/** |
||||
* The audio Levels plugin. |
||||
*/ |
||||
var AudioLevels = (function(my) { |
||||
var CANVAS_EXTRA = 104; |
||||
var CANVAS_RADIUS = 7; |
||||
var SHADOW_COLOR = '#00ccff'; |
||||
var audioLevelCanvasCache = {}; |
||||
|
||||
my.LOCAL_LEVEL = 'local'; |
||||
|
||||
/** |
||||
* Updates the audio level canvas for the given peerJid. If the canvas |
||||
* didn't exist we create it. |
||||
*/ |
||||
my.updateAudioLevelCanvas = function (peerJid) { |
||||
var resourceJid = null; |
||||
var videoSpanId = null; |
||||
if (!peerJid) |
||||
videoSpanId = 'localVideoContainer'; |
||||
else { |
||||
resourceJid = Strophe.getResourceFromJid(peerJid); |
||||
|
||||
videoSpanId = 'participant_' + resourceJid; |
||||
} |
||||
|
||||
videoSpan = document.getElementById(videoSpanId); |
||||
|
||||
if (!videoSpan) { |
||||
if (resourceJid) |
||||
console.error("No video element for jid", resourceJid); |
||||
else |
||||
console.error("No video element for local video."); |
||||
|
||||
return; |
||||
} |
||||
|
||||
var audioLevelCanvas = $('#' + videoSpanId + '>canvas'); |
||||
|
||||
var videoSpaceWidth = $('#remoteVideos').width(); |
||||
var thumbnailSize |
||||
= VideoLayout.calculateThumbnailSize(videoSpaceWidth); |
||||
var thumbnailWidth = thumbnailSize[0]; |
||||
var thumbnailHeight = thumbnailSize[1]; |
||||
|
||||
if (!audioLevelCanvas || audioLevelCanvas.length === 0) { |
||||
|
||||
audioLevelCanvas = document.createElement('canvas'); |
||||
audioLevelCanvas.className = "audiolevel"; |
||||
audioLevelCanvas.style.bottom = "-" + CANVAS_EXTRA/2 + "px"; |
||||
audioLevelCanvas.style.left = "-" + CANVAS_EXTRA/2 + "px"; |
||||
resizeAudioLevelCanvas( audioLevelCanvas, |
||||
thumbnailWidth, |
||||
thumbnailHeight); |
||||
|
||||
videoSpan.appendChild(audioLevelCanvas); |
||||
} else { |
||||
audioLevelCanvas = audioLevelCanvas.get(0); |
||||
|
||||
resizeAudioLevelCanvas( audioLevelCanvas, |
||||
thumbnailWidth, |
||||
thumbnailHeight); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Updates the audio level UI for the given resourceJid. |
||||
* |
||||
* @param resourceJid the resource jid indicating the video element for |
||||
* which we draw the audio level |
||||
* @param audioLevel the newAudio level to render |
||||
*/ |
||||
my.updateAudioLevel = function (resourceJid, audioLevel) { |
||||
drawAudioLevelCanvas(resourceJid, audioLevel); |
||||
|
||||
var videoSpanId = getVideoSpanId(resourceJid); |
||||
|
||||
var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0); |
||||
|
||||
if (!audioLevelCanvas) |
||||
return; |
||||
|
||||
var drawContext = audioLevelCanvas.getContext('2d'); |
||||
|
||||
var canvasCache = audioLevelCanvasCache[resourceJid]; |
||||
|
||||
drawContext.clearRect (0, 0, |
||||
audioLevelCanvas.width, audioLevelCanvas.height); |
||||
drawContext.drawImage(canvasCache, 0, 0); |
||||
}; |
||||
|
||||
/** |
||||
* Resizes the given audio level canvas to match the given thumbnail size. |
||||
*/ |
||||
function resizeAudioLevelCanvas(audioLevelCanvas, |
||||
thumbnailWidth, |
||||
thumbnailHeight) { |
||||
audioLevelCanvas.width = thumbnailWidth + CANVAS_EXTRA; |
||||
audioLevelCanvas.height = thumbnailHeight + CANVAS_EXTRA; |
||||
}; |
||||
|
||||
/** |
||||
* Draws the audio level canvas into the cached canvas object. |
||||
* |
||||
* @param resourceJid the resource jid indicating the video element for |
||||
* which we draw the audio level |
||||
* @param audioLevel the newAudio level to render |
||||
*/ |
||||
function drawAudioLevelCanvas(resourceJid, audioLevel) { |
||||
if (!audioLevelCanvasCache[resourceJid]) { |
||||
|
||||
var videoSpanId = getVideoSpanId(resourceJid); |
||||
|
||||
var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0); |
||||
|
||||
/* |
||||
* FIXME Testing has shown that audioLevelCanvasOrig may not exist. |
||||
* In such a case, the method CanvasUtil.cloneCanvas may throw an |
||||
* error. Since audio levels are frequently updated, the errors have |
||||
* been observed to pile into the console, strain the CPU. |
||||
*/ |
||||
if (audioLevelCanvasOrig) |
||||
{ |
||||
audioLevelCanvasCache[resourceJid] |
||||
= CanvasUtil.cloneCanvas(audioLevelCanvasOrig); |
||||
} |
||||
} |
||||
|
||||
var canvas = audioLevelCanvasCache[resourceJid]; |
||||
|
||||
if (!canvas) |
||||
return; |
||||
|
||||
var drawContext = canvas.getContext('2d'); |
||||
|
||||
drawContext.clearRect(0, 0, canvas.width, canvas.height); |
||||
|
||||
var shadowLevel = getShadowLevel(audioLevel); |
||||
|
||||
if (shadowLevel > 0) |
||||
// drawContext, x, y, w, h, r, shadowColor, shadowLevel
|
||||
CanvasUtil.drawRoundRectGlow( drawContext, |
||||
CANVAS_EXTRA/2, CANVAS_EXTRA/2, |
||||
canvas.width - CANVAS_EXTRA, |
||||
canvas.height - CANVAS_EXTRA, |
||||
CANVAS_RADIUS, |
||||
SHADOW_COLOR, |
||||
shadowLevel); |
||||
}; |
||||
|
||||
/** |
||||
* Returns the shadow/glow level for the given audio level. |
||||
* |
||||
* @param audioLevel the audio level from which we determine the shadow |
||||
* level |
||||
*/ |
||||
function getShadowLevel (audioLevel) { |
||||
var shadowLevel = 0; |
||||
|
||||
if (audioLevel <= 0.3) { |
||||
shadowLevel = Math.round(CANVAS_EXTRA/2*(audioLevel/0.3)); |
||||
} |
||||
else if (audioLevel <= 0.6) { |
||||
shadowLevel = Math.round(CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3)); |
||||
} |
||||
else { |
||||
shadowLevel = Math.round(CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4)); |
||||
} |
||||
return shadowLevel; |
||||
}; |
||||
|
||||
/** |
||||
* Returns the video span id corresponding to the given resourceJid or local |
||||
* user. |
||||
*/ |
||||
function getVideoSpanId(resourceJid) { |
||||
var videoSpanId = null; |
||||
if (resourceJid === AudioLevels.LOCAL_LEVEL |
||||
|| (connection.emuc.myroomjid && resourceJid |
||||
=== Strophe.getResourceFromJid(connection.emuc.myroomjid))) |
||||
videoSpanId = 'localVideoContainer'; |
||||
else |
||||
videoSpanId = 'participant_' + resourceJid; |
||||
|
||||
return videoSpanId; |
||||
}; |
||||
|
||||
/** |
||||
* Indicates that the remote video has been resized. |
||||
*/ |
||||
$(document).bind('remotevideo.resized', function (event, width, height) { |
||||
var resized = false; |
||||
$('#remoteVideos>span>canvas').each(function() { |
||||
var canvas = $(this).get(0); |
||||
if (canvas.width !== width + CANVAS_EXTRA) { |
||||
canvas.width = width + CANVAS_EXTRA; |
||||
resized = true; |
||||
} |
||||
|
||||
if (canvas.heigh !== height + CANVAS_EXTRA) { |
||||
canvas.height = height + CANVAS_EXTRA; |
||||
resized = true; |
||||
} |
||||
}); |
||||
|
||||
if (resized) |
||||
Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) { |
||||
audioLevelCanvasCache[resourceJid].width |
||||
= width + CANVAS_EXTRA; |
||||
audioLevelCanvasCache[resourceJid].height |
||||
= height + CANVAS_EXTRA; |
||||
}); |
||||
}); |
||||
|
||||
return my; |
||||
|
||||
})(AudioLevels || {}); |
@ -0,0 +1,32 @@ |
||||
var BottomToolbar = (function (my) { |
||||
my.toggleChat = function() { |
||||
if (ContactList.isVisible()) { |
||||
buttonClick("#contactListButton", "active"); |
||||
ContactList.toggleContactList(); |
||||
} |
||||
|
||||
buttonClick("#chatBottomButton", "active"); |
||||
|
||||
Chat.toggleChat(); |
||||
}; |
||||
|
||||
my.toggleContactList = function() { |
||||
if (Chat.isVisible()) { |
||||
buttonClick("#chatBottomButton", "active"); |
||||
Chat.toggleChat(); |
||||
} |
||||
|
||||
buttonClick("#contactListButton", "active"); |
||||
|
||||
ContactList.toggleContactList(); |
||||
}; |
||||
|
||||
|
||||
$(document).bind("remotevideo.resized", function (event, width, height) { |
||||
var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18; |
||||
|
||||
$('#bottomToolbar').css({bottom: bottom + 'px'}); |
||||
}); |
||||
|
||||
return my; |
||||
}(BottomToolbar || {})); |
@ -0,0 +1,109 @@ |
||||
/** |
||||
* Utility class for drawing canvas shapes. |
||||
*/ |
||||
var CanvasUtil = (function(my) { |
||||
|
||||
/** |
||||
* Draws a round rectangle with a glow. The glowWidth indicates the depth |
||||
* of the glow. |
||||
* |
||||
* @param drawContext the context of the canvas to draw to |
||||
* @param x the x coordinate of the round rectangle |
||||
* @param y the y coordinate of the round rectangle |
||||
* @param w the width of the round rectangle |
||||
* @param h the height of the round rectangle |
||||
* @param glowColor the color of the glow |
||||
* @param glowWidth the width of the glow |
||||
*/ |
||||
my.drawRoundRectGlow |
||||
= function(drawContext, x, y, w, h, r, glowColor, glowWidth) { |
||||
|
||||
// Save the previous state of the context.
|
||||
drawContext.save(); |
||||
|
||||
if (w < 2 * r) r = w / 2; |
||||
if (h < 2 * r) r = h / 2; |
||||
|
||||
// Draw a round rectangle.
|
||||
drawContext.beginPath(); |
||||
drawContext.moveTo(x+r, y); |
||||
drawContext.arcTo(x+w, y, x+w, y+h, r); |
||||
drawContext.arcTo(x+w, y+h, x, y+h, r); |
||||
drawContext.arcTo(x, y+h, x, y, r); |
||||
drawContext.arcTo(x, y, x+w, y, r); |
||||
drawContext.closePath(); |
||||
|
||||
// Add a shadow around the rectangle
|
||||
drawContext.shadowColor = glowColor; |
||||
drawContext.shadowBlur = glowWidth; |
||||
drawContext.shadowOffsetX = 0; |
||||
drawContext.shadowOffsetY = 0; |
||||
|
||||
// Fill the shape.
|
||||
drawContext.fill(); |
||||
|
||||
drawContext.save(); |
||||
|
||||
drawContext.restore(); |
||||
|
||||
// 1) Uncomment this line to use Composite Operation, which is doing the
|
||||
// same as the clip function below and is also antialiasing the round
|
||||
// border, but is said to be less fast performance wise.
|
||||
|
||||
// drawContext.globalCompositeOperation='destination-out';
|
||||
|
||||
drawContext.beginPath(); |
||||
drawContext.moveTo(x+r, y); |
||||
drawContext.arcTo(x+w, y, x+w, y+h, r); |
||||
drawContext.arcTo(x+w, y+h, x, y+h, r); |
||||
drawContext.arcTo(x, y+h, x, y, r); |
||||
drawContext.arcTo(x, y, x+w, y, r); |
||||
drawContext.closePath(); |
||||
|
||||
// 2) Uncomment this line to use Composite Operation, which is doing the
|
||||
// same as the clip function below and is also antialiasing the round
|
||||
// border, but is said to be less fast performance wise.
|
||||
|
||||
// drawContext.fill();
|
||||
|
||||
// Comment these two lines if choosing to do the same with composite
|
||||
// operation above 1 and 2.
|
||||
drawContext.clip(); |
||||
drawContext.clearRect(0, 0, 277, 200); |
||||
|
||||
// Restore the previous context state.
|
||||
drawContext.restore(); |
||||
}; |
||||
|
||||
/** |
||||
* Clones the given canvas. |
||||
* |
||||
* @return the new cloned canvas. |
||||
*/ |
||||
my.cloneCanvas = function (oldCanvas) { |
||||
/* |
||||
* FIXME Testing has shown that oldCanvas may not exist. In such a case, |
||||
* the method CanvasUtil.cloneCanvas may throw an error. Since audio |
||||
* levels are frequently updated, the errors have been observed to pile |
||||
* into the console, strain the CPU. |
||||
*/ |
||||
if (!oldCanvas) |
||||
return oldCanvas; |
||||
|
||||
//create a new canvas
|
||||
var newCanvas = document.createElement('canvas'); |
||||
var context = newCanvas.getContext('2d'); |
||||
|
||||
//set dimensions
|
||||
newCanvas.width = oldCanvas.width; |
||||
newCanvas.height = oldCanvas.height; |
||||
|
||||
//apply the old canvas to the new one
|
||||
context.drawImage(oldCanvas, 0, 0); |
||||
|
||||
//return the new canvas
|
||||
return newCanvas; |
||||
}; |
||||
|
||||
return my; |
||||
})(CanvasUtil || {}); |
@ -1,17 +1,25 @@ |
||||
var config = { |
||||
hosts: { |
||||
domain: 'guest.jit.si', |
||||
muc: 'meet.jit.si', // FIXME: use XEP-0030
|
||||
bridge: 'jitsi-videobridge.lambada.jitsi.net' // FIXME: use XEP-0030
|
||||
domain: 'jitsi-meet.example.com', |
||||
//anonymousdomain: 'guest.example.com',
|
||||
muc: 'conference.jitsi-meet.example.com', // FIXME: use XEP-0030
|
||||
bridge: 'jitsi-videobridge.jitsi-meet.example.com', // FIXME: use XEP-0030
|
||||
//call_control: 'callcontrol.jitsi-meet.example.com'
|
||||
}, |
||||
// getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
|
||||
// useStunTurn: true, // use XEP-0215 to fetch STUN and TURN server
|
||||
// useIPv6: true, // ipv6 support. use at your own risk
|
||||
useNicks: false, |
||||
bosh: '//lambada.jitsi.net/http-bind', // FIXME: use xep-0156 for that
|
||||
bosh: '//jitsi-meet.example.com/http-bind', // FIXME: use xep-0156 for that
|
||||
desktopSharing: 'ext', // Desktop sharing method. Can be set to 'ext', 'webrtc' or false to disable.
|
||||
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
|
||||
}; |
||||
enableRtpStats: true, // Enables RTP stats processing
|
||||
openSctp: true, // Toggle to enable/disable SCTP channels
|
||||
channelLastN: -1, // The default value of the channel attribute last-n.
|
||||
// useRtcpMux: true,
|
||||
// useBundle: true,
|
||||
enableRecording: false, |
||||
enableWelcomePage: false, |
||||
isBrand: false |
||||
}; |
||||
|
@ -0,0 +1,235 @@ |
||||
/** |
||||
* Contact list. |
||||
*/ |
||||
var ContactList = (function (my) { |
||||
/** |
||||
* Indicates if the chat is currently visible. |
||||
* |
||||
* @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> - |
||||
* otherwise |
||||
*/ |
||||
my.isVisible = function () { |
||||
return $('#contactlist').is(":visible"); |
||||
}; |
||||
|
||||
/** |
||||
* Adds a contact for the given peerJid if such doesn't yet exist. |
||||
* |
||||
* @param peerJid the peerJid corresponding to the contact |
||||
*/ |
||||
my.ensureAddContact = function(peerJid) { |
||||
var resourceJid = Strophe.getResourceFromJid(peerJid); |
||||
|
||||
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]'); |
||||
|
||||
if (!contact || contact.length <= 0) |
||||
ContactList.addContact(peerJid); |
||||
}; |
||||
|
||||
/** |
||||
* Adds a contact for the given peer jid. |
||||
* |
||||
* @param peerJid the jid of the contact to add |
||||
*/ |
||||
my.addContact = function(peerJid) { |
||||
var resourceJid = Strophe.getResourceFromJid(peerJid); |
||||
|
||||
var contactlist = $('#contactlist>ul'); |
||||
|
||||
var newContact = document.createElement('li'); |
||||
newContact.id = resourceJid; |
||||
|
||||
newContact.appendChild(createAvatar()); |
||||
newContact.appendChild(createDisplayNameParagraph("Participant")); |
||||
|
||||
var clElement = contactlist.get(0); |
||||
|
||||
if (resourceJid === Strophe.getResourceFromJid(connection.emuc.myroomjid) |
||||
&& $('#contactlist>ul .title')[0].nextSibling.nextSibling) |
||||
{ |
||||
clElement.insertBefore(newContact, |
||||
$('#contactlist>ul .title')[0].nextSibling.nextSibling); |
||||
} |
||||
else { |
||||
clElement.appendChild(newContact); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Removes a contact for the given peer jid. |
||||
* |
||||
* @param peerJid the peerJid corresponding to the contact to remove |
||||
*/ |
||||
my.removeContact = function(peerJid) { |
||||
var resourceJid = Strophe.getResourceFromJid(peerJid); |
||||
|
||||
var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]'); |
||||
|
||||
if (contact && contact.length > 0) { |
||||
var contactlist = $('#contactlist>ul'); |
||||
|
||||
contactlist.get(0).removeChild(contact.get(0)); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Opens / closes the contact list area. |
||||
*/ |
||||
my.toggleContactList = function () { |
||||
var contactlist = $('#contactlist'); |
||||
var videospace = $('#videospace'); |
||||
|
||||
var chatSize = (ContactList.isVisible()) ? [0, 0] : Chat.getChatSize(); |
||||
var videospaceWidth = window.innerWidth - chatSize[0]; |
||||
var videospaceHeight = window.innerHeight; |
||||
var videoSize |
||||
= getVideoSize(null, null, videospaceWidth, videospaceHeight); |
||||
var videoWidth = videoSize[0]; |
||||
var videoHeight = videoSize[1]; |
||||
var videoPosition = getVideoPosition(videoWidth, |
||||
videoHeight, |
||||
videospaceWidth, |
||||
videospaceHeight); |
||||
var horizontalIndent = videoPosition[0]; |
||||
var verticalIndent = videoPosition[1]; |
||||
|
||||
var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth); |
||||
var thumbnailsWidth = thumbnailSize[0]; |
||||
var thumbnailsHeight = thumbnailSize[1]; |
||||
|
||||
if (ContactList.isVisible()) { |
||||
videospace.animate({right: chatSize[0], |
||||
width: videospaceWidth, |
||||
height: videospaceHeight}, |
||||
{queue: false, |
||||
duration: 500}); |
||||
|
||||
$('#remoteVideos').animate({height: thumbnailsHeight}, |
||||
{queue: false, |
||||
duration: 500}); |
||||
|
||||
$('#remoteVideos>span').animate({height: thumbnailsHeight, |
||||
width: thumbnailsWidth}, |
||||
{queue: false, |
||||
duration: 500, |
||||
complete: function() { |
||||
$(document).trigger( |
||||
"remotevideo.resized", |
||||
[thumbnailsWidth, |
||||
thumbnailsHeight]); |
||||
}}); |
||||
|
||||
$('#largeVideoContainer').animate({ width: videospaceWidth, |
||||
height: videospaceHeight}, |
||||
{queue: false, |
||||
duration: 500 |
||||
}); |
||||
|
||||
$('#largeVideo').animate({ width: videoWidth, |
||||
height: videoHeight, |
||||
top: verticalIndent, |
||||
bottom: verticalIndent, |
||||
left: horizontalIndent, |
||||
right: horizontalIndent}, |
||||
{ queue: false, |
||||
duration: 500 |
||||
}); |
||||
|
||||
$('#contactlist').hide("slide", { direction: "right", |
||||
queue: false, |
||||
duration: 500}); |
||||
} |
||||
else { |
||||
// Undock the toolbar when the chat is shown and if we're in a
|
||||
// video mode.
|
||||
if (VideoLayout.isLargeVideoVisible()) |
||||
Toolbar.dockToolbar(false); |
||||
|
||||
videospace.animate({right: chatSize[0], |
||||
width: videospaceWidth, |
||||
height: videospaceHeight}, |
||||
{queue: false, |
||||
duration: 500, |
||||
complete: function () { |
||||
contactlist.trigger('shown'); |
||||
} |
||||
}); |
||||
|
||||
$('#remoteVideos').animate({height: thumbnailsHeight}, |
||||
{queue: false, |
||||
duration: 500}); |
||||
|
||||
$('#remoteVideos>span').animate({height: thumbnailsHeight, |
||||
width: thumbnailsWidth}, |
||||
{queue: false, |
||||
duration: 500, |
||||
complete: function() { |
||||
$(document).trigger( |
||||
"remotevideo.resized", |
||||
[thumbnailsWidth, thumbnailsHeight]); |
||||
}}); |
||||
|
||||
$('#largeVideoContainer').animate({ width: videospaceWidth, |
||||
height: videospaceHeight}, |
||||
{queue: false, |
||||
duration: 500 |
||||
}); |
||||
|
||||
$('#largeVideo').animate({ width: videoWidth, |
||||
height: videoHeight, |
||||
top: verticalIndent, |
||||
bottom: verticalIndent, |
||||
left: horizontalIndent, |
||||
right: horizontalIndent}, |
||||
{queue: false, |
||||
duration: 500 |
||||
}); |
||||
|
||||
$('#contactlist').show("slide", { direction: "right", |
||||
queue: false, |
||||
duration: 500}); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Creates the avatar element. |
||||
*
|
||||
* @return the newly created avatar element |
||||
*/ |
||||
function createAvatar() { |
||||
var avatar = document.createElement('i'); |
||||
avatar.className = "icon-avatar avatar"; |
||||
|
||||
return avatar; |
||||
}; |
||||
|
||||
/** |
||||
* Creates the display name paragraph. |
||||
* |
||||
* @param displayName the display name to set |
||||
*/ |
||||
function createDisplayNameParagraph(displayName) { |
||||
var p = document.createElement('p'); |
||||
p.innerHTML = displayName; |
||||
|
||||
return p; |
||||
}; |
||||
|
||||
/** |
||||
* Indicates that the display name has changed. |
||||
*/ |
||||
$(document).bind( 'displaynamechanged', |
||||
function (event, peerJid, displayName) { |
||||
if (peerJid === 'localVideoContainer') |
||||
peerJid = connection.emuc.myroomjid; |
||||
|
||||
var resourceJid = Strophe.getResourceFromJid(peerJid); |
||||
|
||||
var contactName = $('#contactlist #' + resourceJid + '>p'); |
||||
|
||||
if (contactName && displayName && displayName.length > 0) |
||||
contactName.html(displayName); |
||||
}); |
||||
|
||||
return my; |
||||
}(ContactList || {})); |
@ -0,0 +1,35 @@ |
||||
#contactlist { |
||||
background-color:rgba(0,0,0,.65); |
||||
} |
||||
|
||||
#contactlist>ul { |
||||
margin: 0px; |
||||
padding: 0px; |
||||
} |
||||
|
||||
#contactlist>ul>li { |
||||
list-style-type: none; |
||||
text-align: left; |
||||
color: #FFF; |
||||
font-size: 10pt; |
||||
padding: 8px 10px; |
||||
} |
||||
|
||||
#contactlist>ul>li>p { |
||||
display: inline-block; |
||||
vertical-align: middle; |
||||
margin: 0px; |
||||
} |
||||
|
||||
#contactlist>ul>li.title { |
||||
color: #00ccff; |
||||
font-size: 11pt; |
||||
border-bottom: 1px solid #676767; |
||||
} |
||||
|
||||
.avatar { |
||||
padding: 0px; |
||||
margin-right: 10px; |
||||
vertical-align: middle; |
||||
font-size: 22pt; |
||||
} |
@ -0,0 +1,6 @@ |
||||
jitsi-meet (1.0.1-1) unstable; urgency=low |
||||
|
||||
* Initial release |
||||
* Jitsi Meet github snapshot from 2014-07-01 |
||||
|
||||
-- Yasen Pramatarov <yasen@bluejimp.com> Tue, 01 Jul 2014 16:31:41 +0300 |
@ -0,0 +1 @@ |
||||
8 |
@ -0,0 +1,33 @@ |
||||
Source: jitsi-meet |
||||
Section: net |
||||
Priority: extra |
||||
Maintainer: Jitsi Team <dev@jitsi.org> |
||||
Uploaders: Emil Ivov <emcho@jitsi.org>, Damian Minkov <damencho@jitsi.org> |
||||
Build-Depends: debhelper (>= 8.0.0) |
||||
Standards-Version: 3.9.3 |
||||
Homepage: https://jitsi.org/meet |
||||
|
||||
Package: jitsi-meet |
||||
Architecture: all |
||||
Pre-Depends: adduser, openssl, jitsi-videobridge |
||||
Depends: ${misc:Depends}, nginx, jitsi-meet-prosody |
||||
Description: WebRTC JavaScript video conferences |
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi |
||||
Videobridge to provide high quality, scalable video conferences. |
||||
. |
||||
It is a web interface to Jitsi Videobridge for audio and video |
||||
forwarding and relaying, configured to work with nginx |
||||
|
||||
Package: jitsi-meet-prosody |
||||
Architecture: all |
||||
Pre-Depends: adduser, openssl, prosody-trunk, jitsi-videobridge |
||||
Depends: ${misc:Depends}, nginx, prosody-modules-otalk, lua-sec |
||||
Description: Prosody configuration for Jitsi Meet |
||||
Jitsi Meet is a WebRTC JavaScript application that uses Jitsi |
||||
Videobridge to provide high quality, scalable video conferences. |
||||
. |
||||
It is a web interface to Jitsi Videobridge for audio and video |
||||
forwarding and relaying, configured to work with nginx |
||||
. |
||||
This package contains configuration for Prosody to be used with |
||||
Jitsi Meet. |
@ -0,0 +1,7 @@ |
||||
Prosody configuration for Jitsi Meet for Debian |
||||
---------------------------- |
||||
|
||||
Jitsi Meet is a WebRTC video conferencing application. This package contains |
||||
configuration of prosody which are needed for Jitsi Meet to work. |
||||
|
||||
-- Yasen Pramatarov <yasen@bluejimp.com> Mon, 30 Jun 2014 23:05:18 +0100 |
@ -0,0 +1,31 @@ |
||||
Format: http://dep.debian.net/deps/dep5 |
||||
Upstream-Name: Jitsi Meet |
||||
Upstream-Contact: Emil Ivov <emcho@jitsi.org> |
||||
Source: https://github.com/jitsi/jitsi-meet |
||||
|
||||
Files: * |
||||
Copyright: 2013-2014 Jitsi |
||||
License: MIT |
||||
|
||||
License: MIT |
||||
The MIT License (MIT) |
||||
. |
||||
Copyright (c) 2013 ESTOS GmbH |
||||
Copyright (c) 2013 BlueJimp SARL |
||||
. |
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||
the Software, and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
. |
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
. |
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1 @@ |
||||
debian/usr/share/doc/jitsi-meet-prosody/prosody.cfg.lua-jvb.example.gz |
@ -0,0 +1 @@ |
||||
debian/usr/share/* usr/share/ |
@ -0,0 +1,59 @@ |
||||
#!/bin/sh |
||||
# postinst script for jitsi-meet-prosody |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <postinst> `configure' <most-recently-configured-version> |
||||
# * <old-postinst> `abort-upgrade' <new version> |
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package> |
||||
# <new-version> |
||||
# * <postinst> `abort-remove' |
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' |
||||
# <failed-install-package> <version> `removing' |
||||
# <conflicting-package> <version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
configure) |
||||
|
||||
. /etc/default/jitsi-videobridge |
||||
|
||||
if [ -x /etc/prosody/prosody.cfg.lua ]; then |
||||
mv /etc/prosody/prosody.cfg.lua /etc/prosody/prosody.cfg.lua.orig |
||||
fi |
||||
gunzip -c /usr/share/doc/jitsi-meet-prosody/prosody.cfg.lua-jvb.example.gz > /etc/prosody/prosody.cfg.lua |
||||
sed -i "s/jitmeet.example.com/$JVB_HOSTNAME/g" /etc/prosody/prosody.cfg.lua |
||||
sed -i "s/jitmeetSecret/$JVB_SECRET/g" /etc/prosody/prosody.cfg.lua |
||||
if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then |
||||
HOST="$( (hostname -s; echo localhost) | head -n 1)" |
||||
DOMAIN="$( (hostname -d; echo localdomain) | head -n 1)" |
||||
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj \ |
||||
"/O=$DOMAIN/OU=$HOST/CN=$JVB_HOSTNAME/emailAddress=webmaster@$HOST.$DOMAIN" \ |
||||
-keyout /var/lib/prosody/$JVB_HOSTNAME.key \ |
||||
-out /var/lib/prosody/$JVB_HOSTNAME.crt |
||||
fi |
||||
ln -sf /var/lib/prosody/$JVB_HOSTNAME.key /etc/prosody/certs/$JVB_HOSTNAME.key |
||||
ln -sf /var/lib/prosody/$JVB_HOSTNAME.crt /etc/prosody/certs/$JVB_HOSTNAME.crt |
||||
invoke-rc.d prosody restart |
||||
;; |
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure) |
||||
;; |
||||
|
||||
*) |
||||
echo "postinst called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
exit 0 |
@ -0,0 +1,48 @@ |
||||
#!/bin/sh |
||||
# postrm script for jitsi-meet-prosody |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <postrm> `remove' |
||||
# * <postrm> `purge' |
||||
# * <old-postrm> `upgrade' <new-version> |
||||
# * <new-postrm> `failed-upgrade' <old-version> |
||||
# * <new-postrm> `abort-install' |
||||
# * <new-postrm> `abort-install' <old-version> |
||||
# * <new-postrm> `abort-upgrade' <old-version> |
||||
# * <disappearer's-postrm> `disappear' <overwriter> |
||||
# <overwriter-version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
# Load debconf |
||||
. /usr/share/debconf/confmodule |
||||
|
||||
|
||||
case "$1" in |
||||
purge|remove) |
||||
if [ -x "/etc/init.d/prosody" ]; then |
||||
invoke-rc.d nginx reload |
||||
fi |
||||
;; |
||||
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) |
||||
;; |
||||
|
||||
*) |
||||
echo "postrm called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
db_stop |
||||
|
||||
exit 0 |
@ -0,0 +1,35 @@ |
||||
#!/bin/sh |
||||
# preinst script for jitsi-meet-prosody |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <new-preinst> `install' |
||||
# * <new-preinst> `install' <old-version> |
||||
# * <new-preinst> `upgrade' <old-version> |
||||
# * <old-preinst> `abort-upgrade' <new-version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
install|upgrade) |
||||
;; |
||||
|
||||
abort-upgrade) |
||||
;; |
||||
|
||||
*) |
||||
echo "preinst called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
exit 0 |
@ -0,0 +1,36 @@ |
||||
#!/bin/sh |
||||
# prerm script for jitsi-meet-prosody |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <prerm> `remove' |
||||
# * <old-prerm> `upgrade' <new-version> |
||||
# * <new-prerm> `failed-upgrade' <old-version> |
||||
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version> |
||||
# * <deconfigured's-prerm> `deconfigure' `in-favour' |
||||
# <package-being-installed> <version> `removing' |
||||
# <conflicting-package> <version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
remove|purge) |
||||
;; |
||||
|
||||
upgrade|deconfigure) |
||||
;; |
||||
|
||||
failed-upgrade) |
||||
;; |
||||
|
||||
*) |
||||
echo "prerm called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
exit 0 |
@ -0,0 +1 @@ |
||||
misc:Depends= |
@ -0,0 +1,8 @@ |
||||
Jitsi Meet for Debian |
||||
---------------------------- |
||||
|
||||
This is a WebRTC frontend of the video conferencing tool Jitsi Meet. It depends on the |
||||
jitsi-videobridge package, which is a SFU (Selective Forwarding Unit) and both packages |
||||
are designed to work together. |
||||
|
||||
-- Yasen Pramatarov <yasen@bluejimp.com> Mon, 30 Jun 2014 23:05:18 +0100 |
@ -0,0 +1,6 @@ |
||||
jitsi-meet for Debian |
||||
--------------------- |
||||
|
||||
The jitsi-meet package is built from the sources of Jitsi Meet. |
||||
|
||||
Jitsi Meet is downloaded from https://github.com/jitsi/jitsi-meet and the git files are removed. you can recreate the source with 'git clone https://github.com/jitsi/jitsi-meet.git'. |
@ -0,0 +1,31 @@ |
||||
Format: http://dep.debian.net/deps/dep5 |
||||
Upstream-Name: Jitsi Meet |
||||
Upstream-Contact: Emil Ivov <emcho@jitsi.org> |
||||
Source: https://github.com/jitsi/jitsi-meet |
||||
|
||||
Files: * |
||||
Copyright: 2013-2014 Jitsi |
||||
License: MIT |
||||
|
||||
License: MIT |
||||
The MIT License (MIT) |
||||
. |
||||
Copyright (c) 2013 ESTOS GmbH |
||||
Copyright (c) 2013 BlueJimp SARL |
||||
. |
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||
the Software, and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
. |
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
. |
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,3 @@ |
||||
README.md |
||||
debian/usr/share/doc/jitsi-meet/README |
||||
debian/usr/share/doc/jitsi-meet/jitsi-meet.example |
@ -0,0 +1,2 @@ |
||||
* usr/share/jitsi-meet/ |
||||
debian/usr/share/* usr/share/ |
@ -0,0 +1,64 @@ |
||||
#!/bin/sh |
||||
# postinst script for jitsi-meet |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <postinst> `configure' <most-recently-configured-version> |
||||
# * <old-postinst> `abort-upgrade' <new version> |
||||
# * <conflictor's-postinst> `abort-remove' `in-favour' <package> |
||||
# <new-version> |
||||
# * <postinst> `abort-remove' |
||||
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' |
||||
# <failed-install-package> <version> `removing' |
||||
# <conflicting-package> <version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
configure) |
||||
|
||||
# nginx conf |
||||
. /etc/default/jitsi-videobridge |
||||
cp /usr/share/doc/jitsi-meet/jitsi-meet.example /etc/nginx/sites-available/$JVB_HOSTNAME.conf |
||||
if [ ! -f /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf ]; then |
||||
ln -s /etc/nginx/sites-available/$JVB_HOSTNAME.conf /etc/nginx/sites-enabled/$JVB_HOSTNAME.conf |
||||
fi |
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" /etc/nginx/sites-available/$JVB_HOSTNAME.conf |
||||
# FIXME do we need the default? |
||||
if [ ! -f /etc/nginx/sites-enabled/default ]; then |
||||
ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default |
||||
fi |
||||
if grep "# server_names_hash_bucket_size 64" /etc/nginx/nginx.conf > /dev/null; then |
||||
sed -i "s/#\ server_names_hash_bucket_size\ 64/\ server_names_hash_bucket_size\ 64/" /etc/nginx/nginx.conf |
||||
fi |
||||
|
||||
# jitsi meet |
||||
chown -R www-data:www-data /usr/share/jitsi-meet/ |
||||
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" /usr/share/jitsi-meet/config.js |
||||
# enable turn |
||||
if grep "// useStunTurn: true," /usr/share/jitsi-meet/config.js > /dev/null; then |
||||
sed -i "s/\/\/\ \ useStunTurn:\ true,/\ \ \ \ useStunTurn:\ true,/" /usr/share/jitsi-meet/config.js |
||||
fi |
||||
invoke-rc.d nginx restart |
||||
|
||||
;; |
||||
|
||||
abort-upgrade|abort-remove|abort-deconfigure) |
||||
;; |
||||
|
||||
*) |
||||
echo "postinst called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
exit 0 |
@ -0,0 +1,48 @@ |
||||
#!/bin/sh |
||||
# postrm script for jitsi-meet |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <postrm> `remove' |
||||
# * <postrm> `purge' |
||||
# * <old-postrm> `upgrade' <new-version> |
||||
# * <new-postrm> `failed-upgrade' <old-version> |
||||
# * <new-postrm> `abort-install' |
||||
# * <new-postrm> `abort-install' <old-version> |
||||
# * <new-postrm> `abort-upgrade' <old-version> |
||||
# * <disappearer's-postrm> `disappear' <overwriter> |
||||
# <overwriter-version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
# Load debconf |
||||
. /usr/share/debconf/confmodule |
||||
|
||||
|
||||
case "$1" in |
||||
purge|remove) |
||||
if [ -x "/etc/init.d/nginx" ]; then |
||||
invoke-rc.d nginx reload |
||||
fi |
||||
;; |
||||
|
||||
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) |
||||
;; |
||||
|
||||
*) |
||||
echo "postrm called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
db_stop |
||||
|
||||
exit 0 |
@ -0,0 +1,35 @@ |
||||
#!/bin/sh |
||||
# preinst script for jitsi-meet |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <new-preinst> `install' |
||||
# * <new-preinst> `install' <old-version> |
||||
# * <new-preinst> `upgrade' <old-version> |
||||
# * <old-preinst> `abort-upgrade' <new-version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
install|upgrade) |
||||
;; |
||||
|
||||
abort-upgrade) |
||||
;; |
||||
|
||||
*) |
||||
echo "preinst called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
# dh_installdeb will replace this with shell code automatically |
||||
# generated by other debhelper scripts. |
||||
|
||||
#DEBHELPER# |
||||
|
||||
exit 0 |
@ -0,0 +1,36 @@ |
||||
#!/bin/sh |
||||
# prerm script for jitsi-meet |
||||
# |
||||
# see: dh_installdeb(1) |
||||
|
||||
set -e |
||||
|
||||
# summary of how this script can be called: |
||||
# * <prerm> `remove' |
||||
# * <old-prerm> `upgrade' <new-version> |
||||
# * <new-prerm> `failed-upgrade' <old-version> |
||||
# * <conflictor's-prerm> `remove' `in-favour' <package> <new-version> |
||||
# * <deconfigured's-prerm> `deconfigure' `in-favour' |
||||
# <package-being-installed> <version> `removing' |
||||
# <conflicting-package> <version> |
||||
# for details, see http://www.debian.org/doc/debian-policy/ or |
||||
# the debian-policy package |
||||
|
||||
|
||||
case "$1" in |
||||
remove|purge) |
||||
;; |
||||
|
||||
upgrade|deconfigure) |
||||
;; |
||||
|
||||
failed-upgrade) |
||||
;; |
||||
|
||||
*) |
||||
echo "prerm called with unknown argument \`$1'" >&2 |
||||
exit 1 |
||||
;; |
||||
esac |
||||
|
||||
exit 0 |
@ -0,0 +1,16 @@ |
||||
#!/usr/bin/make -f |
||||
# -*- makefile -*- |
||||
# Sample debian/rules that uses debhelper. |
||||
# This file was originally written by Joey Hess and Craig Small. |
||||
# As a special exception, when this file is copied by dh-make into a |
||||
# dh-make output file, you may use that output file without restriction. |
||||
# This special exception was added by Craig Small in version 0.37 of dh-make. |
||||
|
||||
# Uncomment this to turn on verbose mode. |
||||
#export DH_VERBOSE=1 |
||||
|
||||
%: |
||||
dh $@ |
||||
|
||||
override_dh_install-indep: |
||||
dh_install -Xdebian -Xdoc -XINSTALL.md -XLICENSE -XREADME.md usr/share/jitsi-meet/ |
@ -0,0 +1 @@ |
||||
3.0 (quilt) |
@ -0,0 +1,19 @@ |
||||
debian/usr/share/jitsi-meet/favicon.ico |
||||
debian/usr/share/jitsi-meet/fonts/jitsi.eot |
||||
debian/usr/share/jitsi-meet/fonts/jitsi.woff |
||||
debian/usr/share/jitsi-meet/fonts/jitsi.ttf |
||||
debian/usr/share/jitsi-meet/sounds/left.wav |
||||
debian/usr/share/jitsi-meet/sounds/incomingMessage.wav |
||||
debian/usr/share/jitsi-meet/sounds/joined.wav |
||||
debian/usr/share/jitsi-meet/images/estoslogo.png |
||||
debian/usr/share/jitsi-meet/images/chromelogo.png |
||||
debian/usr/share/jitsi-meet/images/jitsilogo.png |
||||
debian/usr/share/jitsi-meet/images/watermark.png |
||||
debian/usr/share/jitsi-meet/images/avatarprezi.png |
||||
debian/usr/share/jitsi-meet/images/chromepointer.png |
||||
debian/usr/share/jitsi-meet/images/avatar1.png |
||||
debian/usr/share/jitsi-meet/images/popupPointer.png |
||||
debian/usr/share/jitsi-meet/images/favicon.ico |
||||
debian/usr/share/doc/jitsi-meet/changelog.Debian.gz |
||||
debian/usr/share/doc/jitsi-meet-prosody/changelog.Debian.gz |
||||
debian/usr/share/doc/jitsi-meet-prosody/prosody.cfg.lua-jvb.example.gz |
@ -0,0 +1 @@ |
||||
Prosody configuration for Jitsi Meet |
@ -0,0 +1,31 @@ |
||||
Format: http://dep.debian.net/deps/dep5 |
||||
Upstream-Name: Jitsi Meet |
||||
Upstream-Contact: Emil Ivov <emcho@jitsi.org> |
||||
Source: https://github.com/jitsi/jitsi-meet |
||||
|
||||
Files: * |
||||
Copyright: 2013-2014 Jitsi |
||||
License: MIT |
||||
|
||||
License: MIT |
||||
The MIT License (MIT) |
||||
. |
||||
Copyright (c) 2013 ESTOS GmbH |
||||
Copyright (c) 2013 BlueJimp SARL |
||||
. |
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||
the Software, and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
. |
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
. |
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,13 @@ |
||||
Jitsi Meet |
||||
|
||||
==== |
||||
|
||||
A WebRTC-powered multi-user videochat. For a live demo, check out either |
||||
https://meet.estos.de/ or https://meet.jit.si/. |
||||
|
||||
Built using colibri.js[0] and strophe.jingle[1], powered by the jitsi-videobridge[2] |
||||
|
||||
|
||||
[0] https://github.com/ESTOS/colibri.js |
||||
[1] https://github.com/ESTOS/strophe.jingle |
||||
[3] https://github.com/jitsi/jitsi-videobridge |
@ -0,0 +1,31 @@ |
||||
Format: http://dep.debian.net/deps/dep5 |
||||
Upstream-Name: Jitsi Meet |
||||
Upstream-Contact: Emil Ivov <emcho@jitsi.org> |
||||
Source: https://github.com/jitsi/jitsi-meet |
||||
|
||||
Files: * |
||||
Copyright: 2013-2014 Jitsi |
||||
License: MIT |
||||
|
||||
License: MIT |
||||
The MIT License (MIT) |
||||
. |
||||
Copyright (c) 2013 ESTOS GmbH |
||||
Copyright (c) 2013 BlueJimp SARL |
||||
. |
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
||||
the Software, and to permit persons to whom the Software is furnished to do so, |
||||
subject to the following conditions: |
||||
. |
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
. |
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,36 @@ |
||||
server { |
||||
listen 80; |
||||
server_name jitsi-meet.example.com; |
||||
return 301 https://$host$request_uri; |
||||
} |
||||
server { |
||||
listen 443 ssl; |
||||
server_name jitsi-meet.example.com; |
||||
|
||||
ssl_certificate /var/lib/prosody/jitsi-meet.example.com.crt; |
||||
ssl_certificate_key /var/lib/prosody/jitsi-meet.example.com.key; |
||||
|
||||
root /usr/share/jitsi-meet; |
||||
index index.html index.htm; |
||||
|
||||
location ~ ^/([a-zA-Z0-9]+)$ { |
||||
rewrite ^/(.*)$ / break; |
||||
} |
||||
|
||||
# BOSH |
||||
location /http-bind { |
||||
proxy_pass http://localhost:5280/http-bind; |
||||
proxy_set_header X-Forwarded-For $remote_addr; |
||||
proxy_set_header Host $http_host; |
||||
} |
||||
|
||||
# xmpp websockets |
||||
location /xmpp-websocket { |
||||
proxy_pass http://localhost:5280; |
||||
proxy_http_version 1.1; |
||||
proxy_set_header Upgrade $http_upgrade; |
||||
proxy_set_header Connection "upgrade"; |
||||
proxy_set_header Host $host; |
||||
tcp_nodelay on; |
||||
} |
||||
} |
@ -0,0 +1,103 @@ |
||||
# Jitsi Meet quick install |
||||
|
||||
This documents decribes the needed steps for quick Jitsi Meet installation on a Debian based GNU/Linux system. |
||||
|
||||
N.B.: All commands are supposed to be run by root. If you are logged in as a regular user with sudo rights, please prepend ___sudo___ to each of the commands. |
||||
|
||||
## Basic Jitsi Meet install |
||||
|
||||
### Add the repository |
||||
|
||||
```sh |
||||
add-apt-repository 'deb http://download.jitsi.org/nightly/deb unstable/' |
||||
wget -qO - https://download.jitsi.org/nightly/deb/unstable/archive.key | apt-key add - |
||||
``` |
||||
|
||||
add-apt-repository is in the default Ubuntu install and is available for both Ubuntu and Debian, but if it's not present, either install it with |
||||
|
||||
```sh |
||||
apt-get -y install software-properties-common |
||||
add-apt-repository 'deb http://download.jitsi.org/nightly/deb unstable/' |
||||
wget -qO - https://download.jitsi.org/nightly/deb/unstable/archive.key | apt-key add - |
||||
``` |
||||
|
||||
or add the repository by hand with |
||||
|
||||
```sh |
||||
echo 'deb http://download.jitsi.org/nightly/deb unstable/' >> /etc/apt/sources.list |
||||
wget -qO - https://download.jitsi.org/nightly/deb/unstable/archive.key | apt-key add - |
||||
``` |
||||
|
||||
### Update the package lists |
||||
|
||||
```sh |
||||
apt-get update |
||||
``` |
||||
|
||||
### Install Jitsi Meet |
||||
|
||||
```sh |
||||
apt-get -y install jitsi-meet |
||||
``` |
||||
|
||||
During the installation you'll be asked to enter the hostname of the Jitsi Meet instance. If you have a FQDN hostname for the instance already set ip in DNS, enter it there. If you don't have a resolvable hostname, you can enter the IP address of the machine (if it is static or doesn't change). |
||||
|
||||
This hostname (or IP address) will be used for virtualhost configuration inside the Jitsi Meet and also you and your correspondents will be using it to access the web conferences. |
||||
|
||||
### Open a conference |
||||
|
||||
Launch a web broswer (Chrome, Chromium or latest Opera) and enter in the URL bar the hostname (or IP address) you used in the previous step. |
||||
|
||||
Confirm that you trust the self-signed certificate of the newly installed Jitsi Meet. |
||||
|
||||
Enjoy! |
||||
|
||||
## Adding sip-gateway to Jitsi Meet |
||||
|
||||
### Install Jigasi |
||||
|
||||
```sh |
||||
apt-get -o Dpkg::Options::="--force-overwrite" -y install jigasi |
||||
``` |
||||
|
||||
or |
||||
|
||||
```sh |
||||
wget https://download.jitsi.org/jigasi_1.0-1_amd64.deb |
||||
dpkg -i --force-overwrite jigasi_1.0-1_amd64.deb |
||||
``` |
||||
|
||||
You need to pass "--force-overwrite" option to dpkg, because the jigasi package patches some of the files in the jitsi-meet package in order to enable the SIP support in Jitsi Meet. |
||||
|
||||
During the installation you'll be asked to enter your SIP account and password. This account will be used to invite the other SIP participants. |
||||
|
||||
### Reload Jitsi Meet |
||||
|
||||
Launch again a browser with the Jitsi Meet URL and you'll see a telephone icon on the right end of the toolbar. Use it to invite SIP accounts to join the current conference. |
||||
|
||||
Enjoy! |
||||
|
||||
## Troubleshoot |
||||
|
||||
If the SIP gateway doesn't work on first try, restart it. |
||||
|
||||
```sh |
||||
/etc/init.d/jigasi restart |
||||
``` |
||||
|
||||
## Deinstall |
||||
|
||||
```sh |
||||
apt-get purge jigasi jitsi-meet jitsi-videobridge |
||||
``` |
||||
|
||||
Somethimes the following packages will fail to uninstall properly: |
||||
|
||||
- jigasi |
||||
- jitsi-videobridge |
||||
|
||||
When this happens, just run the deinstall command a second time and it should be ok. |
||||
|
||||
The reason for failure is that not allways the daemons are stopped right away, there is a timeout before the actual stop. And if the unistall script goes on before the services' stop, there is an error. |
||||
|
||||
The second run of the deinstall command fixes this, as by then the jigasi or jvb daemons are already stopped. |
After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 7.8 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 9.8 KiB |
@ -0,0 +1,94 @@ |
||||
/* jshint -W117 */ |
||||
Strophe.addConnectionPlugin('rayo', |
||||
{ |
||||
RAYO_XMLNS: 'urn:xmpp:rayo:1', |
||||
connection: null, |
||||
init: function (conn) |
||||
{ |
||||
this.connection = conn; |
||||
if (this.connection.disco) |
||||
{ |
||||
this.connection.disco.addFeature('urn:xmpp:rayo:client:1'); |
||||
} |
||||
|
||||
this.connection.addHandler( |
||||
this.onRayo.bind(this), this.RAYO_XMLNS, 'iq', 'set', null, null); |
||||
}, |
||||
onRayo: function (iq) |
||||
{ |
||||
console.info("Rayo IQ", iq); |
||||
}, |
||||
dial: function (to, from, roomName) |
||||
{ |
||||
var self = this; |
||||
var req = $iq( |
||||
{ |
||||
type: 'set', |
||||
to: config.hosts.call_control |
||||
} |
||||
); |
||||
req.c('dial', |
||||
{ |
||||
xmlns: this.RAYO_XMLNS, |
||||
to: to, |
||||
from: from |
||||
}); |
||||
req.c('header', |
||||
{ |
||||
name: 'JvbRoomName', |
||||
value: roomName |
||||
}); |
||||
|
||||
this.connection.sendIQ( |
||||
req, |
||||
function (result) |
||||
{ |
||||
console.info('Dial result ', result); |
||||
|
||||
var resource = $(result).find('ref').attr('uri'); |
||||
this.call_resource = resource.substr('xmpp:'.length); |
||||
console.info( |
||||
"Received call resource: " + this.call_resource); |
||||
}, |
||||
function (error) |
||||
{ |
||||
console.info('Dial error ', error); |
||||
} |
||||
); |
||||
}, |
||||
hang_up: function () |
||||
{ |
||||
if (!this.call_resource) |
||||
{ |
||||
console.warn("No call in progress"); |
||||
return; |
||||
} |
||||
|
||||
var self = this; |
||||
var req = $iq( |
||||
{ |
||||
type: 'set', |
||||
to: this.call_resource |
||||
} |
||||
); |
||||
req.c('hangup', |
||||
{ |
||||
xmlns: this.RAYO_XMLNS |
||||
}); |
||||
|
||||
this.connection.sendIQ( |
||||
req, |
||||
function (result) |
||||
{ |
||||
console.info('Hangup result ', result); |
||||
self.call_resource = null; |
||||
}, |
||||
function (error) |
||||
{ |
||||
console.info('Hangup error ', error); |
||||
self.call_resource = null; |
||||
} |
||||
); |
||||
} |
||||
} |
||||
); |
@ -0,0 +1,131 @@ |
||||
/** |
||||
* Provides statistics for the local stream. |
||||
*/ |
||||
var LocalStatsCollector = (function() { |
||||
/** |
||||
* Size of the webaudio analizer buffer. |
||||
* @type {number} |
||||
*/ |
||||
var WEBAUDIO_ANALIZER_FFT_SIZE = 2048; |
||||
|
||||
/** |
||||
* Value of the webaudio analizer smoothing time parameter. |
||||
* @type {number} |
||||
*/ |
||||
var WEBAUDIO_ANALIZER_SMOOTING_TIME = 0.8; |
||||
|
||||
/** |
||||
* <tt>LocalStatsCollector</tt> calculates statistics for the local stream. |
||||
* |
||||
* @param stream the local stream |
||||
* @param interval stats refresh interval given in ms. |
||||
* @param {function(LocalStatsCollector)} updateCallback the callback called on stats |
||||
* update. |
||||
* @constructor |
||||
*/ |
||||
function LocalStatsCollectorProto(stream, interval, updateCallback) { |
||||
window.AudioContext = window.AudioContext || window.webkitAudioContext; |
||||
this.stream = stream; |
||||
this.intervalId = null; |
||||
this.intervalMilis = interval; |
||||
this.updateCallback = updateCallback; |
||||
this.audioLevel = 0; |
||||
} |
||||
|
||||
/** |
||||
* Starts the collecting the statistics. |
||||
*/ |
||||
LocalStatsCollectorProto.prototype.start = function () { |
||||
if (!window.AudioContext) |
||||
return; |
||||
|
||||
var context = new AudioContext(); |
||||
var analyser = context.createAnalyser(); |
||||
analyser.smoothingTimeConstant = WEBAUDIO_ANALIZER_SMOOTING_TIME; |
||||
analyser.fftSize = WEBAUDIO_ANALIZER_FFT_SIZE; |
||||
|
||||
|
||||
var source = context.createMediaStreamSource(this.stream); |
||||
source.connect(analyser); |
||||
|
||||
|
||||
var self = this; |
||||
|
||||
this.intervalId = setInterval( |
||||
function () { |
||||
var array = new Uint8Array(analyser.frequencyBinCount); |
||||
analyser.getByteTimeDomainData(array); |
||||
var audioLevel = TimeDomainDataToAudioLevel(array); |
||||
if(audioLevel != self.audioLevel) { |
||||
self.audioLevel = animateLevel(audioLevel, self.audioLevel); |
||||
self.updateCallback(LocalStatsCollectorProto.LOCAL_JID, self.audioLevel); |
||||
} |
||||
}, |
||||
this.intervalMilis |
||||
); |
||||
|
||||
}; |
||||
|
||||
/** |
||||
* Stops collecting the statistics. |
||||
*/ |
||||
LocalStatsCollectorProto.prototype.stop = function () { |
||||
if (this.intervalId) { |
||||
clearInterval(this.intervalId); |
||||
this.intervalId = null; |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Converts time domain data array to audio level. |
||||
* @param array the time domain data array. |
||||
* @returns {number} the audio level |
||||
*/ |
||||
var TimeDomainDataToAudioLevel = function (samples) { |
||||
|
||||
var maxVolume = 0; |
||||
|
||||
var length = samples.length; |
||||
|
||||
for (var i = 0; i < length; i++) { |
||||
if (maxVolume < samples[i]) |
||||
maxVolume = samples[i]; |
||||
} |
||||
|
||||
return parseFloat(((maxVolume - 127) / 128).toFixed(3)); |
||||
}; |
||||
|
||||
/** |
||||
* Animates audio level change |
||||
* @param newLevel the new audio level |
||||
* @param lastLevel the last audio level |
||||
* @returns {Number} the audio level to be set |
||||
*/ |
||||
function animateLevel(newLevel, lastLevel) |
||||
{ |
||||
var value = 0; |
||||
var diff = lastLevel - newLevel; |
||||
if(diff > 0.2) |
||||
{ |
||||
value = lastLevel - 0.2; |
||||
} |
||||
else if(diff < -0.4) |
||||
{ |
||||
value = lastLevel + 0.4; |
||||
} |
||||
else |
||||
{ |
||||
value = newLevel; |
||||
} |
||||
|
||||
return parseFloat(value.toFixed(3)); |
||||
} |
||||
|
||||
/** |
||||
* Indicates that this audio level is for local jid. |
||||
* @type {string} |
||||
*/ |
||||
LocalStatsCollectorProto.LOCAL_JID = 'local'; |
||||
|
||||
return LocalStatsCollectorProto; |
||||
})(); |
@ -0,0 +1,30 @@ |
||||
/** |
||||
* Provides a wrapper class for the MediaStream. |
||||
*
|
||||
* TODO : Add here the src from the video element and other related properties |
||||
* and get rid of some of the mappings that we use throughout the UI. |
||||
*/ |
||||
var MediaStream = (function() { |
||||
/** |
||||
* Creates a MediaStream object for the given data, session id and ssrc. |
||||
* |
||||
* @param data the data object from which we obtain the stream, |
||||
* the peerjid, etc. |
||||
* @param sid the session id |
||||
* @param ssrc the ssrc corresponding to this MediaStream |
||||
* |
||||
* @constructor |
||||
*/ |
||||
function MediaStreamProto(data, sid, ssrc) { |
||||
this.VIDEO_TYPE = "Video"; |
||||
this.AUDIO_TYPE = "Audio"; |
||||
this.stream = data.stream; |
||||
this.peerjid = data.peerjid; |
||||
this.ssrc = ssrc; |
||||
this.session = connection.jingle.sessions[sid]; |
||||
this.type = (this.stream.getVideoTracks().length > 0) |
||||
? this.VIDEO_TYPE : this.AUDIO_TYPE; |
||||
} |
||||
|
||||
return MediaStreamProto; |
||||
})(); |