Compare commits

...

100 Commits
353 ... 428

Author SHA1 Message Date
hristo
15f4f03ba3 Commit from translate.jitsi.org by user hristo.: 11 of 149 strings translated (0 fuzzy). 2015-03-11 17:50:42 +00:00
hristoterezov
4f9b6f7180 Changes the format of email text in the language resource files. 2015-03-11 18:54:43 +02:00
hristoterezov
b36ec5fd01 Moves supported browser list from the email message to the JS 2015-03-11 10:53:39 +02:00
ibauersachs
ac95ea03fe Commit from translate.jitsi.org by user ibauersachs.: 148 of 148 strings translated (0 fuzzy). 2015-03-11 08:51:16 +00:00
hristoterezov
ae535fcb7d Replaces %0D%0A with \n in the email template text. 2015-03-11 10:29:21 +02:00
hristoterezov
957cc6afc1 Merge branch 'master' of github.com:jitsi/jitsi-meet 2015-03-10 17:25:44 +02:00
hristoterezov
16fdd59617 Adds turkish language. 2015-03-10 17:24:27 +02:00
George Politis
fabf8f42c6 Updates .gitignore. 2015-03-10 15:50:26 +01:00
ibauersachs
c98a56dc37 Commit from translate.jitsi.org by user ibauersachs.: 135 of 135 strings translated (0 fuzzy). 2015-03-10 10:10:08 +00:00
hristoterezov
deb68dd420 Fixes translation issues 2015-03-10 11:38:09 +02:00
Boris Grozev
0fd1a7fa08 Removes embedded html as per Ingo's suggestion. 2015-03-09 19:14:11 +01:00
Boris Grozev
c6ff8aa5dd Tries to improve readibility... 2015-03-09 18:44:42 +01:00
Boris Grozev
06f025e92a Fix formatting. 2015-03-09 18:29:47 +01:00
Boris Grozev
f14329f2cd Adds instructions to enable logging. 2015-03-09 18:27:56 +01:00
Boris Grozev
53e525597a Add .swp files to .gitignore. 2015-03-09 18:27:55 +01:00
George Politis
54b3cbcf94 Reverts config.js 2015-03-09 17:58:11 +01:00
George Politis
2852740e71 Updates the Makefile. It calls npm update before building the project. 2015-03-09 17:41:17 +01:00
George Politis
5322ba086b Reverts previous change of the Makefile. 2015-03-09 17:39:16 +01:00
hristoterezov
d2f95f3c81 Fixes some translation issues. 2015-03-09 17:50:13 +02:00
George Politis
3747251821 Adds dependency to specific commit for sdp-interop. 2015-03-09 16:21:53 +01:00
George Politis
159ba82167 Updates app.bundle.js with latest sdp-interop module that offers support for ssrc-groups. 2015-03-09 15:25:47 +01:00
George Politis
e34a8e6b60 Updates app.bundle.js with latest sdp-interop module. 2015-03-09 11:11:25 +01:00
jitsi-pootle
17a6e360a2 New files added from translate.jitsi.org based on templates 2015-03-09 08:16:17 +00:00
George Politis
b690f5d4a1 Updates app.bundle.js. 2015-03-05 20:25:50 +01:00
Damian Minkov
30f3168bf7 Adds watch file for the deb. 2015-03-05 19:23:55 +02:00
Damian Minkov
115f2e4663 Updates the patch for debian src package. 2015-03-05 19:23:29 +02:00
Damian Minkov
fa15a75928 Updates missing-source location. 2015-03-05 18:01:27 +02:00
Damian Minkov
4db75446f3 Do not edit /etc/nginx/nginx.conf file directly. 2015-03-05 17:52:05 +02:00
George Politis
d9f7b8b6cc Adds a comment about how FF handles the video.src attribute. 2015-03-05 11:26:44 +01:00
George Politis
05bbfda5bb Adds support for FF/multistream. 2015-03-04 21:33:06 +01:00
paweldomas
e465b3ed90 Removes unnecessary error dialog when desktop sharing is started before the conference. 2015-03-04 13:58:07 +01:00
hristoterezov
1825f47ef2 Adds translation support for placeholder attributes. 2015-03-04 12:59:52 +02:00
ibauersachs
169d613ac4 Commit from translate.jitsi.org by user ibauersachs.: 135 of 135 strings translated (0 fuzzy). 2015-03-04 09:37:19 +00:00
Ingo Bauersachs
3dac5eeff5 Fix punctuation spacing 2015-03-04 10:27:44 +01:00
hristoterezov
f79651f806 Merge branch 'translation' 2015-03-04 11:06:02 +02:00
hristoterezov
6048d0a325 Fixes the html attributes for translation options. 2015-02-27 20:05:32 +02:00
hristoterezov
6f12446c99 Fixes translation of plurals. 2015-02-27 19:58:05 +02:00
hristoterezov
af682f8727 Changes the configuration of translation module to retrieve the resources synchronous. Removes the default values. 2015-02-26 17:35:35 +02:00
paweldomas
9123923818 Displays reservation system error if one is returned by the focus. 2015-02-26 14:59:01 +01:00
Boris Grozev
aee7a8e1bd Fix a bug with stats accumulating. Fix a typo. 2015-02-26 10:12:06 +01:00
paweldomas
5b44edb3cc Handles graceful-shutdown focus error response. 2015-02-25 16:55:22 +01:00
Boris Grozev
806d4ea443 Filters some statistics from the logs. Increases the interval for logged statistics. 2015-02-25 11:38:04 +01:00
hristoterezov
1e35ca5e4d Removes the firefox issue link. 2015-02-25 12:06:32 +02:00
hristoterezov
d4f00d76ab Removes webrtcrequired.html. 2015-02-25 11:07:33 +02:00
hristoterezov
37282e63b3 Fixes the references with chromeonly page. 2015-02-24 18:24:39 +02:00
hristoterezov
4b218499ae Redesigns the supported browsers page. 2015-02-24 18:08:24 +02:00
hristoterezov
f16a1cdf44 Changes the implementation to store the language in local storage. Adds new languages. 2015-02-24 12:49:46 +02:00
hristoterezov
702f02568d Fixes issue with the buttons in the message handler. 2015-02-24 10:57:41 +02:00
paweldomas
b6808d87bc Updates app.bundle.js. 2015-02-23 16:15:42 +01:00
paweldomas
8042bd2aa6 Handles MUC destroyed event. 2015-02-23 16:13:38 +01:00
paweldomas
053b2d5af2 Fixes logout confirmation dialog. 2015-02-23 16:13:26 +01:00
Ingo Bauersachs
222164333b Fix some typos and punctuation spacing. 2015-02-23 13:35:16 +01:00
ibauersachs
db50810e4b Commit from translate.jitsi.org by user ibauersachs.: 130 of 130 strings translated (0 fuzzy). 2015-02-23 12:33:29 +00:00
hristo
720851dcb9 Commit from translate.jitsi.org by user hristo.: 3 of 130 strings translated (0 fuzzy). 2015-02-23 11:44:51 +00:00
jitsi-pootle
d7203b8b1a New files added from translate.jitsi.org based on templates 2015-02-23 11:42:53 +00:00
jitsi-pootle
204ca29ed7 New files added from translate.jitsi.org based on templates 2015-02-23 11:42:33 +00:00
hristoterezov
fdada53a4a Fixes issue with the recording. 2015-02-23 12:06:42 +02:00
hristoterezov
81eb3754a0 Fixes "focus not available" notifications. 2015-02-23 11:20:35 +02:00
hristoterezov
d260f1db61 Removes unused package.son files. 2015-02-20 18:21:58 +02:00
hristoterezov
74f078f166 Adds multi language support for message handlers. 2015-02-20 18:17:46 +02:00
paweldomas
e16cee4187 Delete old session ID and retry on 'session-invalid' response. Updates app.bundle.js. 2015-02-19 13:56:04 +01:00
paweldomas
a904e35c67 Adds auto-sign in feature and login/logout toolbar menu. 2015-02-19 13:49:51 +01:00
paweldomas
b87cd9f842 Moves Settings module out from the UI. 2015-02-19 13:49:41 +01:00
paweldomas
fed34e7671 Fixes PreziPlayer crash when invalid message is received. 2015-02-19 13:49:41 +01:00
George Politis
ed57f72117 Adds extra logging. 2015-02-19 13:27:44 +01:00
hristoterezov
4d39d4ccc3 Fixes issue with selected user resource jid variable. 2015-02-19 11:23:55 +02:00
hristoterezov
79cdd94833 Adds multi language support for notifications. 2015-02-13 18:28:35 +02:00
hristoterezov
e0645b41d3 Moves some function calls in UI service 2015-02-13 11:31:25 +02:00
hristoterezov
aa7f0c8a0b Merge branch 'master' of github.com:jitsi/jitsi-meet 2015-02-12 16:44:24 +02:00
hristoterezov
2362770cce Changes getUserMedia implementation to try lower resolution if the configured one is not supported. 2015-02-12 16:42:08 +02:00
Damian Minkov
8334036cf4 Moves admins definition as it seems on some distributions after latest lua updates, causes trouble for prosody. 2015-02-12 15:39:56 +02:00
Damian Minkov
eec513e9e3 Adds admins line after muc component. 2015-02-12 13:50:21 +02:00
hristoterezov
f2a7a43ba7 Fixes audio level performance issue on avatar. 2015-02-11 18:29:20 +02:00
hristoterezov
61bbbaf6eb Adds gitattributes file that marks the generated files as binary files. 2015-02-09 15:50:49 +02:00
hristoterezov
3519a6ec7b Fixes the generated file. 2015-02-09 15:03:23 +02:00
hristoterezov
d21f994eee Removes rtp stats option and adds options for disabling/enabling stats and audio levels. 2015-02-09 14:51:25 +02:00
hristoterezov
b32acf0dfb Fixes the multi language support for the debian package. 2015-02-09 12:24:11 +02:00
hristoterezov
71a56e13d9 Fixes some issues with the tests 2015-02-09 12:21:23 +02:00
hristoterezov
0f6d0a0439 Adds methods required by torture 2015-02-09 10:12:55 +02:00
hristoterezov
3032ea7684 Implements basic multi language support. 2015-02-06 17:46:50 +02:00
hristoterezov
04cfbafc33 Fixes issue with recording. 2015-02-06 15:43:40 +02:00
hristoterezov
57fcee676a Fixes issues with accessing modules not from APP object. 2015-02-06 14:54:19 +02:00
hristoterezov
2f5d090ca5 Merge pull request #227 from odotom/odotom-patch-1
Fixes typos.
2015-02-03 15:42:30 +02:00
bgrozev
8d796f328b Update README.md
Clarify that the detailed instructions are for a 'manual' installation.
2015-02-03 12:45:01 +02:00
hristoterezov
ffb1d6ea17 Generates app bundle file 2015-02-02 20:00:45 +02:00
hristoterezov
4447e5dac6 Merge pull request #229 from schleussinger/master
Corrected Scope - fixes runtime JS error and  Chrome Ext desktop sharing for me
2015-02-02 19:47:59 +02:00
schleussinger
dbed14db5e Fix correct Scope - this fixes JS error and Chrome Ext desktop sharing for me 2015-02-01 13:14:18 +01:00
Thomas Odorfer
254103e21f Update UI.js
fix typo UI.getCredentials
2015-01-31 22:14:53 +01:00
Thomas Odorfer
d0b39e1c97 Update app.js
app.js: fix getCredentials - return object instead of function reference
2015-01-31 22:11:02 +01:00
hristoterezov
4bb555e4b2 Fixes authentication issues. 2015-01-29 11:43:40 +02:00
hristoterezov
8d0ee3ded9 Updates generated file. 2015-01-29 11:27:02 +02:00
hristoterezov
98d1ca8505 Fixes authentication issues. 2015-01-29 11:09:09 +02:00
hristoterezov
e766bad4ce Merge branch 'master' of https://github.com/Zalmoxisus/jitsi-meet
Conflicts:
	libs/modules/RTC.bundle.js
	libs/modules/simulcast.bundle.js
2015-01-28 18:06:09 +02:00
hristoterezov
9eb2873cfa Removes the bundles for every module and add bundle for the whole application. 2015-01-28 16:35:22 +02:00
hristoterezov
c7e2331284 Removes document bind events between modules. 2015-01-27 14:03:26 +02:00
hristoterezov
02ca5e5732 Merge branch 'master' of github.com:jitsi/jitsi-meet 2015-01-27 11:56:43 +02:00
hristoterezov
bc2d72638b Add events for data chanel. 2015-01-27 11:56:22 +02:00
Zalmoxisus
40de181959 Fixes audio-only (when GUM fails) 2015-01-26 19:54:26 +02:00
bgrozev
70bc071cb8 Merge pull request #220 from Zalmoxisus/master
Fixes some typos that cause errors
2015-01-26 09:29:59 -06:00
Zalmoxisus
567ac23c2c Fixes some typos that cause errors 2015-01-26 16:24:26 +02:00
113 changed files with 29959 additions and 25456 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.bundle.js -text -diff

3
.gitignore vendored
View File

@@ -1 +1,4 @@
node_modules
*.swp
.idea/
*.iml

View File

@@ -1,23 +1,21 @@
NPM = npm
BROWSERIFY = browserify
GLOBAL_FLAGS = -e
MODULE_DIR = modules
MODULE_SUBDIRS = $(wildcard $(MODULE_DIR)/*/)
MODULES = $(MODULE_SUBDIRS:$(MODULE_DIR)/%/=%)
GLOBAL_FLAGS = -x jquery -e
OUTPUT_DIR = .
DEPLOY_DIR = libs/modules
DEPLOY_DIR = libs
all: compile deploy clean
compile:FLAGS = $(GLOBAL_FLAGS)
compile:$(MODULES)
compile: app
debug: compile-debug deploy clean
compile-debug:FLAGS = -d $(GLOBAL_FLAGS)
compile-debug:$(MODULES)
compile-debug: app
$(MODULES): *.js
$(BROWSERIFY) $(FLAGS) $(MODULE_DIR)/$@/$@.js -s $@ -o $(OUTPUT_DIR)/$@.bundle.js
app:
$(NPM) update && $(BROWSERIFY) $(FLAGS) app.js -s APP -o $(OUTPUT_DIR)/app.bundle.js
clean:
@rm -f $(OUTPUT_DIR)/*.bundle.js

View File

@@ -10,7 +10,7 @@ Jitsi Meet allows for very efficient collaboration. It allows users to stream th
Installing Jitsi Meet is quite a simple experience. For Debian-based systems, we recommend following the [quick-install](https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md) document, which uses the package system.
For other systems, or if you wish to install all components manually, see the [detailed installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
For other systems, or if you wish to install all components manually, see the [detailed manual installation instructions](https://github.com/jitsi/jitsi-meet/blob/master/doc/manual-install.md).
## Building the sources

50
app.js
View File

@@ -1,30 +1,54 @@
/* jshint -W117 */
/* application specific logic */
var APP =
{
init: function () {
this.UI = require("./modules/UI/UI");
this.API = require("./modules/API/API");
this.connectionquality = require("./modules/connectionquality/connectionquality");
this.statistics = require("./modules/statistics/statistics");
this.RTC = require("./modules/RTC/RTC");
this.simulcast = require("./modules/simulcast/simulcast");
this.desktopsharing = require("./modules/desktopsharing/desktopsharing");
this.xmpp = require("./modules/xmpp/xmpp");
this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut");
this.translation = require("./modules/translation/translation");
this.settings = require("./modules/settings/Settings");
}
};
function init() {
RTC.start();
xmpp.start(UI.getCreadentials);
APP.RTC.start();
APP.xmpp.start(APP.UI.getCredentials());
APP.statistics.start();
APP.connectionquality.init();
// Set default desktop sharing method
APP.desktopsharing.init();
APP.keyboardshortcut.init();
}
$(document).ready(function () {
if(API.isEnabled())
API.init();
APP.init();
UI.start();
statistics.start();
connectionquality.init();
// Set default desktop sharing method
desktopsharing.init();
APP.translation.init();
if(APP.API.isEnabled())
APP.API.init();
APP.UI.start(init);
keyboardshortcut.init();
});
$(window).bind('beforeunload', function () {
if(API.isEnabled())
API.dispose();
if(APP.API.isEnabled())
APP.API.dispose();
});
module.exports = APP;

View File

@@ -1,20 +0,0 @@
<html>
<head>
<title>Jitsi Meet: Unsupported Browser</title>
<link rel="stylesheet" type="text/css" media="screen" href="css/chromeonly.css" />
</head>
<body>
<!-- wrap starts here -->
<div id="wrap">
<a href="http://google.com/chrome"><div id="left"></div></a>
<div id="middle"></div>
<div id="text">
<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>
</body>
</html>

View File

@@ -20,8 +20,9 @@ var config = {
chromeExtensionId: 'diibjkoicjeejcmhdnailmkgecihlobk', // Id of desktop streamer Chrome extension
desktopSharingSources: ['screen', 'window'],
minChromeExtVersion: '0.1', // Required version of Chrome extension
enableRtpStats: true, // Enables RTP stats processing
openSctp: true, // Toggle to enable/disable SCTP channels
disableStats: false,
disableAudioLevels: false,
channelLastN: -1, // The default value of the channel attribute last-n.
adaptiveLastN: false,
adaptiveSimulcast: false,

View File

@@ -1,54 +0,0 @@
body {
width:100%;
height:100%;
background-color: white;
color: #424242;
font-family:'YanoneKaffeesatzLight',Verdana,Tahoma,Arial;
margin:0;
padding:0;
}
#wrap{
display: block;
position: absolute;
width:900px;
height: 262px;
overflow:hidden;
text-align: center;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
#left{
display:inline-block;
background-image:url(../images/chromelogo.png);
background-repeat:no-repeat;
width:246px;
height:262px;
float: left;
}
.firefox{
font-size: 11pt;
color: #c8c8c8;
}
#middle{
display:inline-block;
background-image:url(../images/chromepointer.png);
background-repeat:no-repeat;
width:53px;
height:262px;
float: left;
}
#text{
display:inline-block;
font-size: 18pt;
width: 560px;
vertical-align:middle;
padding-top: 30px;
}
a {
color: #087dba;
text-decoration:none;
}

View File

@@ -99,5 +99,7 @@
width: 90px;
height: 16px;
padding-top: 4px;
padding-left: 10px;
padding-right: 10px;
margin: 15px auto 0px auto;
}

61
css/login_menu.css Normal file
View File

@@ -0,0 +1,61 @@
/*Initialize*/
ul.loginmenu {
display:none;
position: absolute;
margin: 0;
padding: 5px;
padding-bottom: 7px;
top: 45px;
left: -5px;
background-color: rgba(0,0,0,0.9);
border: 1px solid rgba(256, 256, 256, 0.2);
border-radius:8px;
}
ul.loginmenu li {
list-style-type: none;
padding: 7px;
}
ul.loginmenu li.identity {
color: #fff;
font-size: 11pt;
cursor: default;
}
ul.loginmenu:after {
content: url('../images/dropdownPointer.png');
display: block;
position: absolute;
top: -7px;
left: 18px;
}
li a.authButton{
background-color: #06a5df;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 29px;
padding-right: 29px;
border-radius: 4px;
color: #fff;
font-size: 11pt;
cursor: pointer;
}
span.authentication:hover ul.loginmenu, ul.loginmenu:hover {
display:block !important;
}
a.disabled {
color: gray !important;
pointer-events: none;
}
.loginmenuPadding {
width: 50px;
height: 30px;
position: absolute;
top: -30px;
left: 0px;
}

View File

@@ -3,7 +3,7 @@
color: #00ccff;
}
#settingsmenu input {
#settingsmenu input, select {
margin-top: 10px;
margin-left: 10%;
width: 80%;
@@ -27,8 +27,8 @@
}
#settingsmenu button {
width: 36%;
left: 32%;
width: 45%;
left: 26%;
padding: 0;
margin-top: 10px;
}
@@ -43,3 +43,7 @@
#settingsmenu .icon-settings {
padding: 34px;
}
#languages_selectbox{
height: 40px;
}

111
css/unsupported_browser.css Normal file
View File

@@ -0,0 +1,111 @@
body {
width:100%;
height:100%;
background-color: white;
color: #424242;
font-family:Helvetica,'YanoneKaffeesatzLight',Verdana,Tahoma,Arial;
font-size: 28px;
margin:0;
padding:0;
}
#wrap{
display: block;
position: absolute;
width:900px;
height: 365px;
overflow:hidden;
text-align: center;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
.firefox{
font-size: 11pt;
color: #c8c8c8;
width: 468px;
text-align: center;
margin: 30px auto 0px auto;
padding-left: 15px;
}
#text{
display:inline-block;
font-size: 28px;
width: 568px;
vertical-align:middle;
padding-top: 25px;
}
a {
color: #087dba;
text-decoration:none;
}
.browser {
width: 138px;
height: 163px;
margin-top: 5px;
background-color: #e8e8e8;
border: 1px solid #cfcfcf;
border-radius: 10px;
}
.browser_wrapper
{
width: 138px;
height: 188px;
vertical-align: middle;
color: #929391;
font-size: 20px;
float: left;
margin-left: 15px;
}
.supported_browsers
{
margin: 0px auto 0px auto;
width: 460px;
}
.clear
{
clear: both;
}
.button
{
background-color: #62c82a;
border: 1px solid #3c8117;
border-radius: 10px;
color: #FFFFFF;
font-size: 12px;
text-align: center;
width: 115px;
height: 26px;
padding-top: 13px;
margin: 15px auto 0px auto;
}
.logo
{
margin: 20px auto 0px auto;
}
#chrome_logo
{
width: 78px;
height: 78px;
background-image: url('/images/chrome.png');
}
#chromium_logo
{
width: 77px;
height: 79px;
background-image: url('/images/chromium.png');
}
#opera_logo
{
width: 73px;
height: 78px;
background-image: url('/images/opera.png');
}

View File

@@ -62,7 +62,7 @@ case "$1" in
if [ -f $PROSODY_HOST_CONFIG ] && ! grep -q "VirtualHost \"auth.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG; then
echo -e "\nVirtualHost \"auth.$JVB_HOSTNAME\"" >> $PROSODY_HOST_CONFIG
echo -e " authentication = \"internal_plain\"\n" >> $PROSODY_HOST_CONFIG
echo -e "admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\" }\n" >> $PROSODY_HOST_CONFIG
sed -i "s/Component \"conference.$JVB_HOSTNAME\" \"muc\"/Component \"conference.$JVB_HOSTNAME\" \"muc\"\nadmins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\" }\n/g" $PROSODY_HOST_CONFIG
echo -e "Component \"focus.$JVB_HOSTNAME\"" >> $PROSODY_HOST_CONFIG
echo -e " component_secret=\"$JICOFO_SECRET\"\n" >> $PROSODY_HOST_CONFIG
PROSODY_CREATE_JICOFO_USER="true"

View File

@@ -7,4 +7,5 @@ service /usr/share/jitsi-meet/
css /usr/share/jitsi-meet/
sounds /usr/share/jitsi-meet/
fonts /usr/share/jitsi-meet/
images /usr/share/jitsi-meet/
images /usr/share/jitsi-meet/
lang /usr/share/jitsi-meet/

View File

@@ -37,10 +37,6 @@ case "$1" in
sed -i "s/jitsi-meet.example.com/$JVB_HOSTNAME/g" /etc/nginx/sites-available/$JVB_HOSTNAME.conf
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
# SSL for nginx
db_get jitsi-meet/cert-choice
CERT_CHOICE="$RET"

View File

@@ -2,21 +2,18 @@ Index: jitsi-meet/index.html
===================================================================
--- jitsi-meet.orig/index.html
+++ jitsi-meet/index.html
@@ -9,7 +9,7 @@
@@ -9,12 +9,12 @@
<meta itemprop="name" content="Jitsi Meet"/>
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
<meta itemprop="image" content="/images/jitsilogo.png"/>
- <script src="libs/jquery-2.1.1.min.js"></script>
+ <script src="libs/jquery.min.js"></script>
<script src="config.js?v=5"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="simulcast.js?v=5"></script><!-- simulcast handling -->
<script src="libs/strophe/strophe.jingle.adapter.js?v=2"></script><!-- strophe.jingle bundles -->
@@ -24,7 +24,7 @@
<script src="libs/strophe/strophe.util.js"></script>
<script src="libs/colibri/colibri.focus.js?v=10"></script><!-- colibri focus implementation -->
<script src="libs/colibri/colibri.session.js?v=1"></script>
<script src="config.js?v=6"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="libs/strophe/strophe.min.js?v=1"></script>
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
- <script src="libs/jquery-ui.js"></script>
+ <script src="libs/jquery-ui.min.js"></script>
<script src="libs/rayo.js?v=1"></script>
<script src="libs/tooltip.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->

12
debian/rules vendored
View File

@@ -1,10 +1,4 @@
#!/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
@@ -19,7 +13,7 @@ override_dh_install:
dh_installdirs
dh_install -X/config.js
yui-compressor -o debian/jitsi-meet/usr/share/jitsi-meet/libs/strophe/strophe.caps.jsonly.min.js \
debian/patches/missing-source/libs/strophe/strophe.caps.jsonly.js
debian/missing-source/libs/strophe/strophe.caps.jsonly.js
yui-compressor -o debian/jitsi-meet/usr/share/jitsi-meet/libs/strophe/strophe.disco.min.js \
debian/patches/missing-source/libs/strophe/sha1.js \
debian/patches/missing-source/libs/strophe/strophe.disco.js
debian/missing-source/libs/strophe/sha1.js \
debian/missing-source/libs/strophe/strophe.disco.js

2
debian/watch vendored Normal file
View File

@@ -0,0 +1,2 @@
version=3
https://github.com/jitsi/jitsi-meet/releases/ /jitsi/jitsi-meet/archive/(\S+)\.tar\.gz

View File

@@ -16,6 +16,7 @@ VirtualHost "jitmeet.example.com"
}
Component "conference.jitmeet.example.com" "muc"
admins = { "focusUser@auth.jitmeet.example.com" }
Component "jitsi-videobridge.jitmeet.example.com"
component_secret = "jitmeetSecret"
@@ -23,7 +24,5 @@ Component "jitsi-videobridge.jitmeet.example.com"
VirtualHost "auth.jitmeet.example.com"
authentication = "internal_plain"
admins = { "focusUser@auth.jitmeet.example.com" }
Component "focus.jitmeet.example.com"
component_secret = "focusSecret"

View File

@@ -1,3 +1,5 @@
server_names_hash_bucket_size 64;
server {
listen 80;
server_name jitsi-meet.example.com;

26
doc/influxdb.md Normal file
View File

@@ -0,0 +1,26 @@
# Overview
Jitsi Meet supports logging to an [InfluxDB](http://influxdb.com/) database.
# Configuration
The following needs to be done to enable this functionality.
## Install InfluxDB
The details are outside the scope of the document, see http://influxdb.com/download/ .
## Enable logging for Jitsi Videobridge
Add the following properties to <code>/usr/share/jitsi-videobridge/.sip-communicator/sip-communicator.properties</code>.
- org.jitsi.videobridge.log.INFLUX_DB_ENABLED=true
- org.jitsi.videobridge.log.INFLUX_URL_BASE=http://influxdb.example.com:8086
- org.jitsi.videobridge.log.INFLUX_DATABASE=jitsi_database
- org.jitsi.videobridge.log.INFLUX_USER=user
- org.jitsi.videobridge.log.INFLUX_PASS=pass
## Enable logging for Jicofo
Add the same properties as above to <code>/usr/share/jitsi-videobridge/.sip-communicator/sip-communicator.properties</code>.
## Enable logging for Jitsi Meet itself
Change "logStats" to "true" in <code>/etc/jitsi/meet/you-domain.config.js</code> or the <code>config.js</code> file used in your installation.
# User interface
You can explore the database using the [Jiloin](https://github.com/jitsi/jiloin) web interface.

BIN
images/chrome.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/chromium.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
images/dropdownPointer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

BIN
images/firefox.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
images/opera.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -10,7 +10,7 @@
<meta itemprop="description" content="Join a WebRTC video conference powered by the Jitsi Videobridge"/>
<meta itemprop="image" content="/images/jitsilogo.png"/>
<script src="libs/jquery-2.1.1.min.js"></script>
<script src="config.js?v=5"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="config.js?v=6"></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script src="libs/strophe/strophe.min.js?v=1"></script>
<script src="libs/strophe/strophe.disco.min.js?v=1"></script>
<script src="libs/strophe/strophe.caps.jsonly.min.js?v=1"></script>
@@ -19,24 +19,7 @@
<script src="libs/popover.js?v=1"></script><!-- bootstrap tooltip lib -->
<script src="libs/toastr.js?v=1"></script><!-- notifications lib -->
<script src="interface_config.js?v=5"></script>
<script src="service/RTC/RTCBrowserType.js?v=1"></script>
<script src="service/RTC/StreamEventTypes.js?v=2"></script>
<script src="service/RTC/MediaStreamTypes.js?v=1"></script>
<script src="service/xmpp/XMPPEvents.js?v=1"></script>
<script src="service/connectionquality/CQEvents.js?v=1"></script>
<script src="service/UI/UIEvents.js?v=1"></script>
<script src="service/desktopsharing/DesktopSharingEventTypes.js?v=1"></script>
<script src="libs/modules/simulcast.bundle.js?v=5"></script>
<script src="libs/modules/connectionquality.bundle.js?v=3"></script>
<script src="libs/modules/UI.bundle.js?v=12"></script>
<script src="libs/modules/statistics.bundle.js?v=5"></script>
<script src="libs/modules/RTC.bundle.js?v=7"></script>
<script src="libs/modules/desktopsharing.bundle.js?v=3"></script><!-- desktop sharing -->
<script src="libs/modules/xmpp.bundle.js?v=7"></script>
<script src="libs/modules/keyboardshortcut.bundle.js?v=2"></script>
<script src="app.js?v=30"></script><!-- application logic -->
<script src="libs/modules/API.bundle.js?v=2"></script>
<script src="libs/app.bundle.js?v=34"></script>
<script src="analytics.js?v=1"></script><!-- google analytics plugin -->
<link rel="stylesheet" href="css/font.css?v=6"/>
<link rel="stylesheet" href="css/toastr.css?v=1">
@@ -46,6 +29,7 @@
<link rel="stylesheet" href="css/jquery-impromptu.css?v=4">
<link rel="stylesheet" href="css/modaldialog.css?v=3">
<link rel="stylesheet" href="css/popup_menu.css?v=4">
<link rel="stylesheet" href="css/login_menu.css?v=1">
<link rel="stylesheet" href="css/popover.css?v=2">
<link rel="stylesheet" href="css/jitsi_popover.css?v=2">
<link rel="stylesheet" href="css/contact_list.css?v=4">
@@ -68,76 +52,66 @@
<a target="_new">
<div class="watermark rightwatermark"></div>
</a>
<a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a>
<a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
<div id="enter_room_container">
<div id="enter_room_form" >
<div id="domain_name"></div>
<div id="enter_room">
<input id="enter_room_field" type="text" autofocus placeholder="Enter room name" />
<input id="enter_room_field" type="text" autofocus data-i18n="[placeholder]welcomepage.roomname" placeholder="Enter room name" />
<div class="icon-reload" id="reload_roomname"></div>
<input id="enter_room_button" type="button" value="GO" />
<input id="enter_room_button" type="button" data-i18n="[value]welcomepage.go" value="GO" />
</div>
</div>
</div>
<div id="brand_header"></div>
<input type='checkbox' name='checkbox' id="disable_welcome"/>
<label for="disable_welcome" class="disable_welcome_position">Don't show this page next time I enter</label>
<label for="disable_welcome" class="disable_welcome_position" data-i18n="welcomepage.disable"></label>
<div id="header_text"></div>
</div>
<div id="welcome_page_main">
<div id="features">
<div class="feature_row">
<div class="feature_holder">
<div class="feature_icon">Simple to use</div>
<div class="feature_description">
No downloads required. <span name="appName"></span> works directly within your browser. Simply share your conference URL with others to get started.
<div class="feature_icon" data-i18n="welcomepage.feature1.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature1.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
</div>
</div>
<div class="feature_holder">
<div class="feature_icon">Low bandwidth</div>
<div class="feature_description">
Multi-party video conferences work with as little as 128Kbps. Screen-sharing and audio-only conferences are possible with far less.
<div class="feature_icon" data-i18n="welcomepage.feature2.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature2.content">
</div>
</div>
<div class="feature_holder">
<div class="feature_icon">Open source</div>
<div class="feature_description">
<span name="appName"></span> is licensed under MIT. You are free to download, use, modify, and share them as per these licenses.
<div class="feature_icon" data-i18n="welcomepage.feature3.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature3.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
</div>
</div>
<div class="feature_holder">
<div class="feature_icon">Unlimited users</div>
<div class="feature_description">
There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors.
<div class="feature_icon" data-i18n="welcomepage.feature4.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature4.content">
</div>
</div>
</div>
<div class="feature_row">
<div class="feature_holder">
<div class="feature_icon">Screen sharing</div>
<div class="feature_description">
It's easy to share your screen with others. <span name="appName"></span> is ideal for on-line presentations, lectures, and tech support sessions.
</div>
<div class="feature_icon" data-i18n="welcomepage.feature5.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature5.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
</div>
</div>
<div class="feature_holder">
<div class="feature_icon">Secure rooms</div>
<div class="feature_description">
Need some privacy? <span name="appName"></span> conference rooms can be secured with a password in order to exclude unwanted guests and prevent interruptions.
</div>
<div class="feature_icon" data-i18n="welcomepage.feature6.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature6.content" data-i18n-options='{ "postProcess": "resolveAppName" }'>
</div>
</div>
<div class="feature_holder">
<div class="feature_icon">Shared notes</div>
<div class="feature_description">
<span name="appName"></span> features Etherpad, a real-time collaborative text editor that's great for meeting minutes, writing articles, and more.
</div>
<div class="feature_icon" data-i18n="welcomepage.feature7.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature7.content" data-i18n-options='{ "postProcess": "resolveAppName" }'></div>
</div>
<div class="feature_holder">
<div class="feature_icon">Usage statistics</div>
<div class="feature_description">
Learn about your users through easy integration with Piwik, Google Analytics, and other usage monitoring and statistics systems.
</div>
<div class="feature_icon" data-i18n="welcomepage.feature8.title" ></div>
<div class="feature_description" data-i18n="welcomepage.feature8.content"></div>
</div>
</div>
</div>
@@ -147,36 +121,46 @@
<div style="position: relative;" id="header_container">
<div id="header">
<span id="toolbar">
<a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" content="Mute / Unmute">
<span id="authentication" class="authentication" style="display: none">
<a class="button" id="toolbar_button_authentication" >
<i id="authButton" class="icon-avatar"></i>
</a>
<ul class="loginmenu">
<span class="loginmenuPadding"></span>
<li id="toolbar_auth_identity" class="identity"></li>
<li id="toolbar_button_login">
<a class="authButton" data-i18n="toolbar.login"></a>
</li>
<li id="toolbar_button_logout">
<a class="authButton" data-i18n="toolbar.logout"></a>
</li>
</ul>
<div class="header_button_separator"></div>
</span>
<a class="button" id="toolbar_button_mute" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="mutePopover" data-i18n="[content]toolbar.mute" content="Mute / Unmute">
<i id="mute" class="icon-microphone"></i>
</a>
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" content="Start / stop camera">
<a class="button" id="toolbar_button_camera" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" data-i18n="[content]toolbar.videomute" content="Start / stop camera">
<i id="video" class="icon-camera"></i>
</a>
<span id="authentication" style="display: none">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_authentication" data-container="body" data-toggle="popover" data-placement="bottom" content="Authenticate">
<i id="authButton" class="icon-avatar"></i>
</a>
</span>
<span id="recording" style="display: none">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" content="Record">
<a class="button" id="toolbar_button_record" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.record" content="Record">
<i id="recordButton" class="icon-recEnable"></i>
</a>
</span>
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_security" data-container="body" data-toggle="popover" data-placement="bottom" content="Lock / unlock room">
<a class="button" id="toolbar_button_security" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.lock" content="Lock / unlock room">
<i id="lockIcon" class="icon-security"></i>
</a>
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="bottom" content="Invite others">
<a class="button" id="toolbar_button_link" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.invite" content="Invite others">
<i class="icon-link"></i>
</a>
<div class="header_button_separator"></div>
<span class="toolbar_span">
<a class="button" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" content="Open / close chat">
<a class="button" id="toolbar_button_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="bottom" data-i18n="[content]toolbar.chat" content="Open / close chat">
<i id="chatButton" class="icon-chat">
<span id="unreadMessages"></span>
</i>
@@ -184,38 +168,38 @@
</span>
<span id="prezi_button">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_prezi" data-container="body" data-toggle="popover" data-placement="bottom" content="Share Prezi">
<a class="button" id="toolbar_button_prezi" data-container="body" data-toggle="popover" data-placement="bottom" data-i18n="[content]toolbar.prezi" content="Share Prezi">
<i class="icon-prezi"></i>
</a>
</span>
<span id="etherpadButton">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_etherpad" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document">
<a class="button" id="toolbar_button_etherpad" data-container="body" data-toggle="popover" data-placement="bottom" content="Shared document" data-i18n="[content]toolbar.etherpad">
<i class="icon-share-doc"></i>
</a>
</span>
<div class="header_button_separator"></div>
<span id="desktopsharing" style="display: none">
<a class="button" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen">
<a class="button" id="toolbar_button_desktopsharing" data-container="body" data-toggle="popover" data-placement="bottom" content="Share screen" data-i18n="[content]toolbar.sharescreen">
<i class="icon-share-desktop"></i>
</a>
</span>
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen">
<a class="button" id="toolbar_button_fullScreen" data-container="body" data-toggle="popover" data-placement="bottom" content="Enter / Exit Full Screen" data-i18n="[content]toolbar.fullscreen">
<i id="fullScreen" class="icon-full-screen"></i>
</a>
<span id="sipCallButton" style="display: none">
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number">
<a class="button" id="toolbar_button_sip" data-container="body" data-toggle="popover" data-placement="bottom" content="Call SIP number" data-i18n="[content]toolbar.sip">
<i class="icon-telephone"></i></a>
</span>
<div class="header_button_separator"></div>
<a class="button" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" >
<a class="button" id="toolbar_button_settings" data-container="body" data-toggle="popover" data-placement="bottom" content="Settings" data-i18n="[content]toolbar.Settings">
<i id="settingsButton" class="icon-settings"></i>
</a>
<div class="header_button_separator"></div>
<span id="hangup">
<a class="button" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up">
<a class="button" id="toolbar_button_hangup" data-container="body" data-toggle="popover" data-placement="bottom" content="Hang Up" data-i18n="[content]toolbar.hangup">
<i class="icon-hangup" style="color:#ff0000;font-size: 1.4em;"></i>
</a>
</span>
@@ -224,7 +208,7 @@
<div id="subject"></div>
</div>
<div id="settings">
<h1>Connection Settings</h1>
<h1 data-i18n="connectionsettings"></h1>
<form id="loginInfo">
<label>JID: <input id="jid" type="text" name="jid" placeholder="me@example.com"/></label>
<label>Password: <input id="password" type="password" name="password" placeholder="secret"/></label>
@@ -239,7 +223,7 @@
<div id="etherpad"></div>
<a target="_new"><div class="watermark leftwatermark"></div></a>
<a target="_new"><div class="watermark rightwatermark"></div></a>
<a class="poweredby" href="http://jitsi.org" target="_new" >powered by jitsi.org</a>
<a class="poweredby" href="http://jitsi.org" target="_new" ><span data-i18n="poweredby"></span> jitsi.org</a>
<div id="activeSpeaker">
<img id="activeSpeakerAvatar" src=""/>
<canvas id="activeSpeakerAudioLevel"></canvas>
@@ -254,18 +238,13 @@
</span>
<audio id="localAudio" autoplay oncontextmenu="return false;" muted></audio>
<span class="focusindicator"></span>
<!--<div class="connectionindicator">
<span class="connection connection_empty"><i class="icon-connection"></i></span>
<span class="connection connection_full"><i class="icon-connection"></i></span>
</div>-->
</span>
<audio id="userJoined" src="sounds/joined.wav" preload="auto"></audio>
<audio id="userLeft" src="sounds/left.wav" preload="auto"></audio>
</div>
<span id="bottomToolbar">
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" id="bottom_toolbar_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" content="Open / close chat">
<a class="bottomToolbarButton" id="bottom_toolbar_chat" data-container="body" data-toggle="popover" shortcut="toggleChatPopover" data-placement="top" data-i18n="[content]bottomtoolbar.chat" content="Open / close chat">
<i id="chatBottomButton" class="icon-chat-simple">
<span id="bottomUnreadMessages"></span>
</i>
@@ -273,7 +252,7 @@
</span>
<div class="bottom_button_separator"></div>
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" id="bottom_toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover" content="Open / close contact list">
<a class="bottomToolbarButton" id="bottom_toolbar_contact_list" data-container="body" data-toggle="popover" data-placement="top" id="contactlistpopover" data-i18n="[content]bottomtoolbar.contactlist" content="Open / close contact list">
<i id="contactListButton" class="icon-contactList">
<span id="numberOfParticipants"></span>
</i>
@@ -281,7 +260,7 @@
</span>
<div class="bottom_button_separator"></div>
<span class="bottomToolbar_span">
<a class="bottomToolbarButton" id="bottom_toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" content="Show / hide film strip">
<a class="bottomToolbarButton" id="bottom_toolbar_film_strip" data-container="body" data-toggle="popover" shortcut="filmstripPopover" data-placement="top" data-i18n="[content]bottomtoolbar.filmstrip" content="Show / hide film strip">
<i id="filmStripButton" class="icon-filmstrip"></i>
</a>
</span>
@@ -289,16 +268,16 @@
</div>
<div id="chatspace" class="right-panel">
<div id="nickname">
Enter a nickname in the box below
<span data-i18n="chat.nickname.title"></span>
<form>
<input type='text' id="nickinput" placeholder='Choose a nickname' autofocus>
<input type='text' id="nickinput" data-i18n="[placeholder]chat.nickname.popover" autofocus>
</form>
</div>
<!--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>
<textarea id="usermsg" data-i18n="[placeholder]chat.messagebox" autofocus></textarea>
<div id="smileysarea">
<div id="smileys" id="toggle_smileys">
<img src="images/smile.svg"/>
@@ -307,18 +286,18 @@
</div>
<div id="contactlist" class="right-panel">
<ul>
<li class="title"><i class="icon-contact-list"></i> CONTACT LIST</li>
<li class="title"><i class="icon-contact-list"></i><span data-i18n="contactlist"></span></li>
</ul>
</div>
<div id="settingsmenu" class="right-panel">
<div class="icon-settings"> SETTINGS</div>
<div class="icon-settings" data-i18n="settings.title"></div>
<img id="avatar" src="https://www.gravatar.com/avatar/87291c37c25be69a072a4514931b1749?d=wavatar&size=30"/>
<div class="arrow-up"></div>
<input type="text" id="setDisplayName" placeholder="Name">
<input type="text" id="setDisplayName" data-i18n="[placeholder]settings.name" placeholder="Name">
<input type="text" id="setEmail" placeholder="E-Mail">
<button id="updateSettings">Update</button>
<button id="updateSettings" data-i18n="settings.update"></button>
</div>
<a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-content="Download logs" ><i class="fa fa-cloud-download"></i></a>
<a id="downloadlog" onclick='dump(event.target);' data-container="body" data-toggle="popover" data-placement="right" data-i18n="[data-content]downloadlogs" ><i class="fa fa-cloud-download"></i></a>
</div>
</body>
</html>

View File

@@ -5,7 +5,7 @@ var interfaceConfig = {
INITIAL_TOOLBAR_TIMEOUT: 20000,
TOOLBAR_TIMEOUT: 4000,
DEFAULT_REMOTE_DISPLAY_NAME: "Fellow Jitster",
DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME: "Speaker",
DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME: "speaker",
DEFAULT_LOCAL_DISPLAY_NAME: "me",
SHOW_JITSI_WATERMARK: true,
JITSI_WATERMARK_LINK: "http://jitsi.org",

6
lang/languages-bg.json Normal file
View File

@@ -0,0 +1,6 @@
{
"en": "Английски",
"bg": "Български",
"de": "Немски",
"tr": "Турски"
}

6
lang/languages-de.json Normal file
View File

@@ -0,0 +1,6 @@
{
"en": "Englisch",
"bg": "Bulgarisch",
"de": "Deutsch",
"tr": "Türkisch"
}

5
lang/languages-tr.json Normal file
View File

@@ -0,0 +1,5 @@
{
"en": "İngilizce",
"bg": "Bulgarca",
"de": "Almanca"
}

6
lang/languages.json Normal file
View File

@@ -0,0 +1,6 @@
{
"en": "English",
"bg": "Bulgarian",
"de": "German",
"tr": "Turkish"
}

204
lang/main-bg.json Normal file
View File

@@ -0,0 +1,204 @@
{
"contactlist": "СПИСЪК С КОНТАКТИ",
"connectionsettings": "Настройки на връзката",
"poweredby": "",
"downloadlogs": "",
"roomUrlDefaultMsg": "",
"participant": "Участник",
"me": "аз",
"speaker": "",
"defaultNickname": "",
"defaultPreziLink": "",
"welcomepage": {
"go": "",
"roomname": "Въведете име на стаята",
"disable": "",
"feature1": {
"title": "",
"content": ""
},
"feature2": {
"title": "",
"content": ""
},
"feature3": {
"title": "",
"content": ""
},
"feature4": {
"title": "",
"content": ""
},
"feature5": {
"title": "",
"content": ""
},
"feature6": {
"title": "",
"content": ""
},
"feature7": {
"title": "",
"content": ""
},
"feature8": {
"title": "",
"content": ""
}
},
"toolbar": {
"mute": "",
"videomute": "",
"authenticate": "",
"record": "",
"lock": "",
"invite": "",
"chat": "",
"prezi": "",
"etherpad": "",
"sharescreen": "",
"fullscreen": "",
"sip": "",
"Settings": "",
"hangup": "",
"login": "",
"logout": ""
},
"bottomtoolbar": {
"chat": "",
"filmstrip": "",
"contactlist": ""
},
"chat": {
"nickname": {
"title": "",
"popover": ""
},
"messagebox": ""
},
"settings": {
"title": "НАСТРОЙКИ",
"update": "",
"name": ""
},
"videothumbnail": {
"editnickname": "",
"moderator": "",
"videomute": "",
"mute": "",
"kick": "",
"muted": "",
"domute": ""
},
"connectionindicator": {
"bitrate": "",
"packetloss": "",
"resolution": "",
"less": "",
"more": "",
"address": "",
"remoteport": "",
"remoteport_plural": "",
"localport": "",
"localport_plural": "",
"localaddress": "",
"localaddress_plural": "",
"remoteaddress": "",
"remoteaddress_plural": "",
"transport": "",
"bandwidth": "",
"na": ""
},
"notify": {
"disconnected": "",
"moderator": "",
"connected": "",
"somebody": "",
"me": "",
"focus": "",
"focusFail": "",
"grantedTo": "",
"grantedToUnknown": ""
},
"dialog": {
"kickMessage": "",
"popupError": "",
"passwordError": "",
"passwordError2": "",
"joinError": "",
"connectError": "",
"error": "",
"detectext": "",
"failtoinstall": "",
"failedpermissions": "",
"bridgeUnavailable": "",
"lockTitle": "",
"lockMessage": "",
"warning": "",
"passwordNotSupported": "",
"sorry": "",
"internalError": "",
"unableToSwitch": "",
"SLDFailure": "",
"SRDFailure": "",
"oops": "",
"defaultError": "",
"passwordRequired": "",
"Ok": "",
"removePreziTitle": "",
"removePreziMsg": "",
"sharePreziTitle": "",
"sharePreziMsg": "",
"Remove": "",
"Stop": "",
"AuthMsg": "",
"Authenticate": "",
"Cancel": "",
"logoutTitle": "",
"logoutQuestion": "",
"sessTerminated": "",
"hungUp": "",
"joinAgain": "",
"Share": "",
"preziLinkError": "",
"Save": "",
"recordingToken": "",
"Dial": "",
"sipMsg": "",
"passwordCheck": "",
"passwordMsg": "",
"Invite": "",
"shareLink": "",
"settings1": "",
"settings2": "",
"settings3": "",
"yourPassword": "",
"Back": "",
"serviceUnavailable": "",
"gracefulShutdown": "",
"Yes": "",
"reservationError": "",
"reservationErrorMsg": "",
"password": "",
"userPassword": "",
"token": ""
},
"email": {
"sharedKeyThis conference is password protected. Please use the following pin when joining:\n\n\n__sharedKey__\n\n": "",
"subject": "",
"bodyHey there, I%27d like to invite you to a __appName__ conference I%27ve just set up.\n\n\nPlease click on the following link in order to join the conference.\n\n\n__roomUrl__\n\n\n__sharedKeyText__\n Note that __appName__ is currently only supported by __supportedBrowsers__, so you need to be using one of these browsers.\n\n\nTalk to you in a sec!": [
"Здравей, Бих искал да те поканя в една __appName__ конференция, която създадох.",
"",
"",
"Кликни на следния линк за да се присъединиш в конференцията.",
"",
"",
"__sharedKeyText__",
"__appName__ поддържа __supportedBrowsers__, така че трябва да използваш един от тези браузъри.",
"",
"",
"Ще се видим след секунда!"
],
"and": ""
}
}

207
lang/main-de.json Normal file
View File

@@ -0,0 +1,207 @@
{
"contactlist": "Kontaktliste",
"connectionsettings": "Verbindungseinstellungen",
"poweredby": "Betrieben von",
"downloadlogs": "Log herunterladen",
"roomUrlDefaultMsg": "Die Konferenz wird erstellt...",
"participant": "Teilnehmer",
"me": "ich",
"speaker": "Sprecher",
"defaultNickname": "Bsp.: __name__",
"defaultPreziLink": "Bsp.: __url__",
"welcomepage": {
"go": "Los",
"roomname": "Raumnamen eingeben",
"disable": "Diese Seite beim nächsten Betreten nicht mehr anzeigen",
"feature1": {
"title": "Einfach zu benutzen",
"content": "Kein Download nötig. __app__ läuft direkt im Browser. Einfach die Konferenzadresse teilen und los geht's."
},
"feature2": {
"title": "Niedrige Bandbreite",
"content": "Videokonferenzen mit mehreren Teilnehmen mit weniger als 128Kpbs. Bildschirmfreigaben und Telefonkonferenzen kommen sogar mit noch weniger Bandbreite aus."
},
"feature3": {
"title": "Open Source",
"content": "__app__ steht unter der MIT Lizenz. __app__ kann gemäss der Lizenz heruntergeladen, verwendet, verändert und weitergegeben werden."
},
"feature4": {
"title": "Unbegrenzte Anzahl Benutzer",
"content": "Es gibt keine künstliche Beschränkung der Anzahl der Benutzer oder Konferenzteilnehmer. Die Leistung des Servers und die Bandbreite sind die einzigen limitierenden Faktoren."
},
"feature5": {
"title": "Bildschirmfreigabe",
"content": "Es ist ganz einfach den Bildschirm zu teilen. __app__ ist ideal für Online-Präsentationen, Vorlesungen und Fernwartungsanfragen."
},
"feature6": {
"title": "Sichere Konferenzen",
"content": "Privatsphäre gewünscht? __app__ Konferenzen können mit einem Passwort geschützt werden um ungebetene Gäste fernzuhalten und Unterbrechungen zu vermeiden."
},
"feature7": {
"title": "Freigegebene Notizen",
"content": "__app__ verwendent Etherpad, ein Editor zur kollaborativen Bearbeitung von Texten."
},
"feature8": {
"title": "Benutzungsstatistiken",
"content": "Die Verwendung kann durch die Integration mit Piwik, Google Analytics und anderen Überwachungs- und Statistikprogrammen protokolliert werden."
}
},
"toolbar": {
"mute": "Stummschaltung aktivieren / deaktivieren",
"videomute": "Kamera starten / stoppen",
"authenticate": "Anmelden",
"record": "Aufnehmen",
"lock": "Raum schützen / Schutz aufheben",
"invite": "Andere einladen",
"chat": "Chat öffnen / schliessen",
"prezi": "Prezi freigeben",
"etherpad": "Geteiltes Dokument",
"sharescreen": "Bildschirm freigeben",
"fullscreen": "Vollbildmodus aktivieren / deaktivieren",
"sip": "SIP Nummer anrufen",
"Settings": "Einstellungen",
"hangup": "Auflegen",
"login": "Anmelden",
"logout": "Abmelden"
},
"bottomtoolbar": {
"chat": "Chat öffnen / schliessen",
"filmstrip": "Videovorschauen anzeigen / verstecken",
"contactlist": "Kontaktliste öffnen / schliessen"
},
"chat": {
"nickname": {
"title": "Nickname im Eingabefeld eingeben",
"popover": "Einen Namen auswählen"
},
"messagebox": "Text eingeben..."
},
"settings": {
"title": "Einstellungen",
"update": "Aktualisieren",
"name": "Name"
},
"videothumbnail": {
"editnickname": "Klicken um den Anzeigenamen zu bearbeiten",
"moderator": "Besitzer dieser Konferenz",
"videomute": "Teilnehmer hat die Kamera pausiert.",
"mute": "Teilnehmer ist stumm geschaltet",
"kick": "Hinauswerfen",
"muted": "Stummgeschaltet",
"domute": "Stummschalten"
},
"connectionindicator": {
"bitrate": "Bitrate:",
"packetloss": "Paketverlust:",
"resolution": "Auflösung:",
"less": "Weniger anzeigen",
"more": "Mehr anzeigen",
"address": "Adresse:",
"remoteport": "Entfernter Port:",
"remoteport_plural": "Entfernte Ports:",
"localport": "Lokaler Port:",
"localport_plural": "Lokale Ports:",
"localaddress": "Lokale Adresse:",
"localaddress_plural": "Lokale Adressen:",
"remoteaddress": "Entfernte Adresse:",
"remoteaddress_plural": "Entfernte Adressen:",
"transport": "Protokoll:",
"bandwidth": "Geschätzte Bandbreite:",
"na": "Verbindungsdaten erneut anzeigen wenn die Konferenz begonnen hat"
},
"notify": {
"disconnected": "getrennt",
"moderator": "Moderatorenrechte vergeben",
"connected": "verbunden",
"somebody": "Jemand",
"me": "Ich",
"focus": "Konferenz-Organisator",
"focusFail": "__component__ ist im Moment nicht verfügbar - wiederholen in __ms__ Sekunden",
"grantedTo": "Moderatorenrechte an __to__ vergeben.",
"grantedToUnknown": "Moderatorenrechte an $t(somebody) vergeben."
},
"dialog": {
"kickMessage": "Oh! Sie wurden aus der Konferenz ausgeschlossen.",
"popupError": "Ihr Browser blockiert Popups von dieser Webseite. Bitte erlauben Sie Popups in den Sicherheitseinstellungen und versuchen Sie es erneut.",
"passwordError": "Diese Konferenz ist mit einem Paswort geschützt. Nur der Besitzer der Konferenz kann ein Passwort vergeben.",
"passwordError2": "Diese Konferenzt ist nicht mit einem Passwort geschützt. Nur der Besitzer der Konferenz kann ein Passwort vergeben.",
"joinError": "Oh! Der Konferenz konnte nicht beigetreten werden. Diese könnte ein Problem mit den Sicherheitseinstellungen sein. Bitte kontaktieren Sie den Administrator des Dienstes.",
"connectError": "Oh! Es hat etwas nicht geklappt und der Konferenz konnte nicht beigetreten werden.",
"error": "Fehler",
"detectext": "Fehler bei der Erkennung der Bildschirmfreigabeerweiterung.",
"failtoinstall": "Die Bildschirmfreigabeerweiterung konnte nicht installiert werden.",
"failedpermissions": "Die Zugriffsberechtigungen auf das Mikrofon und/oder die Kamera konnte nicht eingeholt werden.",
"bridgeUnavailable": "Die Jitsi Videobridge ist momentan nicht erreichbar. Bitte versuchen Sie es später noch einmal.",
"lockTitle": "Sperren fehlgeschlagen",
"lockMessage": "Die Konferenz konnte nicht gesperrt werden.",
"warning": "Warnung",
"passwordNotSupported": "Passwörter für Räume werden nicht unterstützt.",
"sorry": "Entschuldigung",
"internalError": "Interner Anwendungsfehler [setRemoteDescription]",
"unableToSwitch": "Der Videodatenstrom kann nicht gewechselt werden.",
"SLDFailure": "Oh! Die Stummschaltung konnte nicht aktiviert werden. (SLD Fehler)",
"SRDFailure": "Oh! Das Video konnte nicht gestoppt werden. (SRD Fehler)",
"oops": "Oh!",
"defaultError": "Es ist ein Fehler aufgetreten",
"passwordRequired": "Passwort erforderlich",
"Ok": "OK",
"removePreziTitle": "Prezi entfernen",
"removePreziMsg": "Sind Sie sich sicher dass sie Prezi entfernen möchten?",
"sharePreziTitle": "Ein Prezi teilen",
"sharePreziMsg": "Ein anderer Teilnehmer teilt bereits ein Prezi. Diese Konferenz kann nur eine Prezi auf einmal anzeigen.",
"Remove": "Entfernen",
"Stop": "Stopp",
"AuthMsg": "Für die Erstellung des Raums ist eine Authentifizierung erforderlich. <br/><b>__room__</b><br/>Sie können sich entweder anmelden oder warten bis jemand anderes die Authentifizierung vornimmt.",
"Authenticate": "Anmelden",
"Cancel": "Abbrechen",
"logoutTitle": "Abmelden",
"logoutQuestion": "Sind Sie sicher dass Sie sich abmelden und die Konferenz verlassen möchten?",
"sessTerminated": "Sitzung beendet",
"hungUp": "Anruf beendet",
"joinAgain": "Erneut beitreten",
"Share": "Teilen",
"preziLinkError": "Bitte einen gültigen Prezi-Link angeben.",
"Save": "Speichern",
"recordingToken": "Aufnahme-Token eingeben",
"Dial": "Wählen",
"sipMsg": "Geben Sie eine SIP Nummer ein",
"passwordCheck": "Sind Sie sicher dass Sie das Passwort entfernen möchten?",
"passwordMsg": "Passwort setzen um den Raum zu schützen",
"Invite": "Einladen",
"shareLink": "Teilen Sie diesen Link mit jedem den Sie einladen möchten",
"settings1": "Konferenz einrichten",
"settings2": "Teilnehmer treten stummgeschaltet bei",
"settings3": "Nickname erforderlich<br/><br/>Setzen Sie ein Passwort um den Raum zu schützen:",
"yourPassword": "Ihr Passwort",
"Back": "Zurück",
"serviceUnavailable": "Dienst nicht verfügbar",
"gracefulShutdown": "Der Dienst steht momentan wegen Wartungsarbeiten nicht zur Verfügung. Bitte versuchen Sie es später noch einmal.",
"Yes": "Ja",
"reservationError": "Fehler im Reservationssystem",
"reservationErrorMsg": "Fehler, Nummer: __code__, Nachricht: __msg__",
"password": "Passwort",
"userPassword": "Benutzerpasswort",
"token": "Token"
},
"email": {
"sharedKeyThis conference is password protected. Please use the following pin when joining:\n\n __sharedKey__ \n\n": [
"Diese Konferenz ist Passwortgeschützt. Bitte verwenden Sie diesen PIN zum Beitreten:",
"",
" __sharedKey__",
"",
"",
""
],
"subject": "Einladung zu einer __appName__ (__conferenceName__)",
"bodyHey there, I%27d like to invite you to a __appName__ conference I%27ve just set up.\n\nPlease click on the following link in order to join the conference.\n\n __roomUrl__\n\n__sharedKeyText__ Note that __appName__ is currently only supported by Chromium, Google Chrome and Opera, so you need to be using one of these browsers.\n\nTalk to you in a sec!": [
"Hallo!",
"Ich möchte dich zu einer eben erstellten __appName__-Konferenz einladen.",
"",
"Bitte klicke auf den folgenden Link um der Konferenz ebenfalls beizutreten:\\",
" __roomUrl__",
"__sharedKeyText__ Bitte beachte, dass __appName__ momentan nur mit einem der Browser Chromium, Google und Opera verwendet werden kann.",
"",
"Bis gleich!"
]
}
}

173
lang/main-tr.json Normal file
View File

@@ -0,0 +1,173 @@
{
"contactlist": "KİŞİ LİSTESİ",
"connectionsettings": "Bağlantı Ayarları",
"poweredby": "Gücünün kaynağı",
"downloadlogs": "Günlükleri indir",
"welcomepage": {
"go": "GİT",
"roomname": "Oda adı girin",
"disable": "Sonraki girişimde bu sayfayı gösterme",
"feature1": {
"title": "Kullanımı kolay",
"content": "İndirmeye gerek yok. __app__ tarayıcınızda doğrudan çalışır. Başlamak için görüşme bağlantısını URL diğerleri ile paylaşın."
},
"feature2": {
"title": "Düşük bant genişliği ihtiyacı",
"content": "Ekran paylaşımı ve sadece ses ile çok katılımcılı video görüşmeleri, 128Kbps bağlantı ile mümkündür."
},
"feature3": {
"title": "Açık kaynak kodlu",
"content": "__app__ MIT ile lisanslanmıştır. Bu lisansa uygun olarak indirmek, kullanmak, değiştirmek ve paylaşmakta özgürsün."
},
"feature4": {
"title": "Sınırsız sayıda kullanıcı",
"content": "Kullanıcılar veya konferans katılımcılarının sayısında hiçbir yapay kısıtlama yoktur. Sadece sunucun güç ve bant genişliği, sınırlayıcı unsurdur."
},
"feature5": {
"title": "Ekran paylaşımı",
"content": "Diğerlerinle ekranınızı kolayca paylaşın. __app__ çevrimiçi sunumlar, dersler ve teknik destek oturumları için idealdir."
},
"feature6": {
"title": "Güvenli odalar",
"content": "Biraz gizliliğe ihtiyacınız var? __app__ görüşme odaları, istemeyen misafirleri uzak tutmak ve kesinleri önlemek için bir parola ile güvence altına alınabilir."
},
"feature7": {
"title": "Paylaşımlı notlar",
"content": "__app__ Etherpad içerir, gerçek zamanlı bir ortak çalışma metin düzenleyicisidir. Görüşme tutanakları, makale yazımı ve daha fazlası için biçilmiş kaftandır."
},
"feature8": {
"title": "Kullanım istatistikleri",
"content": "Piwik, Google Analytics ve diğer kullanım izleme ve istatistik sistemleri ile kolay tümleştirmeyle kullanıcılar hakkında bilgi edinin."
}
},
"toolbar": {
"mute": "Sessiz / Sesli",
"videomute": "Kamera başlat / durdur",
"authenticate": "",
"record": "Kaydet",
"lock": "Odayı kilitle / kilit aç",
"invite": "Arkadaşlarını davet et",
"chat": "",
"prezi": "Prezi paylaş",
"etherpad": "Paylaşımlı belge",
"sharescreen": "Ekran paylaş",
"fullscreen": "Tam Ekrana Gir / Çık",
"sip": "SIP numara ara",
"Settings": "Ayarlar",
"hangup": "Kapat",
"login": "Oturum aç",
"logout": ""
},
"bottomtoolbar": {
"chat": "Sohbeti aç / kapa",
"filmstrip": "Kişi listesi aç / kapa",
"contactlist": "Film şeridini göster / gizle"
},
"chat": {
"nickname": {
"title": "Aşağıdaki kutuya bir takma ad girin",
"popover": "Bir takma ad seçin"
},
"messagebox": "Metin girin..."
},
"settings": {
"title": "AYARLAR",
"update": "Güncelle",
"name": "Ad"
},
"videothumbnail": {
"editnickname": "Görünür adınızı değiştirmek<br/>için tıkla",
"moderator": "Bu görüşmenin<br/>sahibi",
"videomute": "Katılımcı<br/>kamera durdurdu.",
"mute": "Katılımcı sessiz",
"kick": "Kovuldu",
"muted": "Sessiz",
"domute": "Sustur"
},
"connectionindicator": {
"bitrate": "Bit hızı:",
"packetloss": "Paket kaybı:",
"resolution": "Çözünürlük:",
"less": "Daha az göster",
"more": "Daha fazla göster",
"address": "Adres:",
"remoteport": "Uzak port:Uzak portlar:",
"localport": "Yerel port:Yerel portlar:",
"localaddress": "Yerel adres:Yerel adresler:",
"remoteaddress": "Uzak adres:Uzak adresler:",
"transport": "Transport:",
"bandwidth": "Tahmini bant genişliği:",
"na": "Görüşme başladıktan sonra bağlantı bilgileri için buraya gel"
},
"notify": {
"disconnected": "bağlantı kesildi",
"moderator": "Görüşme yöneticisi hakları verildi!",
"connected": "bağlandı",
"somebody": "Birisi",
"me": "Bana",
"focus": "Görüşme odağı",
"focusFail": "__component__ uygun değil - __ms__ saniye içinde tekrar deneyin",
"grantedTo": "__to__, görüşme yöneticisi hakları verildi!",
"grantedToUnknown": "$t(somebody), görüşme yöneticisi hakları verildi!"
},
"dialog": {
"kickMessage": "Ahhh! Görüşmeden, kavuldun!",
"popupError": "Tarayıcınız bu siteden açılır pencereleri engelliyor. Lütfen, tarayıcınızın güvenlik ayarlarında pop-up etkinleştirin ve tekrar deneyin.",
"passwordError": "Bu görüşme şu anda bir parola ile korunmaktadır. Sadece görüşmenin sahibi bir parola ayarlayabilir.",
"passwordError2": "Bu görüşme şu anda bir parola ile korunmamaktadır. Sadece görüşmenin sahibi bir parola ayarlayabilir.",
"joinError": "Amanin boo! Görüşmeye katılamadık. Güvenlik yapılandırması ile ilgili bir sorun olabilir. Hizmet yöneticisi ile bağlantı kurun.",
"connectError": "Amanin boo! Birşeyler ters gitti ve görüşmeye bağlanamadık.",
"error": "Hata",
"detectext": "Ekran paylaşımı eklentisi tespit edilirken hata.",
"failtoinstall": "Masaüstü paylaşım eklentisi yüklenemedi",
"failedpermissions": "Yerel mikrofon ve/veya kamerayı kullanmak için izinler alınamadı.",
"bridgeUnavailable": "Jitsi Videobridge şu anda kullanılamıyor. Daha sonra tekrar deneyiniz!",
"lockTitle": "Kilitlenemedi",
"lockMessage": "Görüşme kilitlenemedi.",
"warning": "Uyarı",
"passwordNotSupported": "Oda parolaları şu anda desteklenmemekte.",
"sorry": "Üzgünüz",
"internalError": "İç uygulama hatası [setRemoteDescription]",
"unableToSwitch": "Video akışıılamıyor.",
"SLDFailure": "Amanin boo! Birşeyler ters gitti ve sessize alamadık! (SLD Başarısız)",
"SRDFailure": "Amanin boo! Birşeyler ters gitti ve videoyu durduramadık! (SRD Başarısız)",
"oops": "Amanin boo!",
"defaultError": "Bir tür hata var",
"passwordRequired": "Parola gerekli",
"Ok": "Tamam",
"removePreziTitle": "Prezi kaldır",
"removePreziMsg": "Prezi kaldırmak istediğinizden emin misiniz?",
"sharePreziTitle": "Bir Prezi paylaşın",
"sharePreziMsg": "Diğer katılımcı hala bir Prezi paylaşıyor.Bu görüşme aynı zamanda sadece bir Prezi izin verir.",
"Remove": "Kaldır",
"Stop": "Durdur",
"AuthMsg": "Oda oluşturmak için kimlik doğrulama gerekli:<br/><b>__room__ </b></br> Oda oluşturmak için ya kimlik doğrulamalı ya da bunu yapması için bir başkasını beklemelisiniz.",
"Authenticate": "Kimlik doğrula",
"Cancel": "İptal",
"logoutTitle": "Oturum kapat",
"logoutQuestion": "Oturumu ve görüşmeyi sonlandırmak istediğinizden emin misiniz?",
"sessTerminated": "Oturum sonlandırıldı",
"hungUp": "Görüşmeyi bitirdiniz",
"joinAgain": "Yeniden katıl",
"Share": "Paylaş",
"preziLinkError": "Lütfen doğru prezi bağlantısı verin.",
"Save": "Kaydet",
"recordingToken": "Kayıt jetonu girin",
"Dial": "Ara",
"sipMsg": "SIP numarası gir",
"passwordCheck": "Parolanızı kaldırmak istediğinizden emin misiniz?",
"passwordMsg": "Odanızı kilitlemek için bir parola koyun",
"Invite": "Davet et",
"shareLink": "Davet etmek istediğiniz herkesle bu bağlantıyı paylaşın",
"settings1": "Görüşmenizi yapılandır",
"settings2": "Katılımcılar sessiz katılsın",
"settings3": "Takma adlar gerekli<br/><br/>Odanızı kitlemek için bir parola ayarlayın:",
"yourPassword": "parolanız",
"Back": "Geri",
"serviceUnavailable": "Hizmet kullanım dışı",
"gracefulShutdown": "Hizmetimiz bakıp için durduruldu. Daha sonra tekrar deneyiniz.",
"Yes": "Evet",
"reservationError": "Rezervasyon sistemi hatası",
"reservationErrorMsg": "Hata kodu: __code__, mesaj: __msg__"
}
}

220
lang/main.json Normal file
View File

@@ -0,0 +1,220 @@
{
"contactlist": "CONTACT LIST",
"connectionsettings": "Connection Settings",
"poweredby": "powered by",
"downloadlogs": "Download logs",
"roomUrlDefaultMsg": "Your conference is currently being created...",
"participant": "Participant",
"me": "me",
"speaker": "Speaker",
"defaultNickname": "ex. __name__",
"defaultPreziLink": "e.g. __url__",
"welcomepage":{
"go": "GO",
"roomname": "Enter room name",
"disable": "Don't show this page next time I enter",
"feature1": {
"title": "Simple to use",
"content": "No downloads required. __app__ works directly within your browser. Simply share your conference URL with others to get started."
},
"feature2": {
"title": "Low bandwidth",
"content": "Multi-party video conferences work with as little as 128Kbps. Screen-sharing and audio-only conferences are possible with far less."
},
"feature3": {
"title": "Open source",
"content": "__app__ is licensed under MIT. You are free to download, use, modify, and share them as per these licenses."
},
"feature4": {
"title": "Unlimited users",
"content": "There are no artificial restrictions on the number of users or conference participants. Server power and bandwidth are the only limiting factors."
},
"feature5": {
"title": "Screen sharing",
"content": "It's easy to share your screen with others. __app__ is ideal for on-line presentations, lectures, and tech support sessions."
},
"feature6": {
"title": "Secure rooms",
"content": "Need some privacy? __app__ conference rooms can be secured with a password in order to exclude unwanted guests and prevent interruptions."
},
"feature7": {
"title": "Shared notes",
"content": "__app__ features Etherpad, a real-time collaborative text editor that's great for meeting minutes, writing articles, and more."
},
"feature8": {
"title": "Usage statistics",
"content": "Learn about your users through easy integration with Piwik, Google Analytics, and other usage monitoring and statistics systems."
}
},
"toolbar": {
"mute": "Mute / Unmute",
"videomute": "Start / stop camera",
"authenticate": "Authenticate",
"record": "Record",
"lock": "Lock / unlock room",
"invite": "Invite others",
"chat": "Open / close chat",
"prezi": "Share Prezi",
"etherpad": "Shared document",
"sharescreen": "Share screen",
"fullscreen": "Enter / Exit Full Screen",
"sip": "Call SIP number",
"Settings": "Settings",
"hangup": "Hang Up",
"login": "Login",
"logout": "Logout"
},
"bottomtoolbar": {
"chat": "Open / close chat",
"filmstrip": "Show / hide film strip",
"contactlist": "Open / close contact list"
},
"chat":{
"nickname": {
"title": "Enter a nickname in the box below",
"popover": "Choose a nickname"
},
"messagebox": "Enter text..."
},
"settings":
{
"title": "SETTINGS",
"update": "Update",
"name": "Name"
},
"videothumbnail":
{
"editnickname": "Click to edit your<br/>display name",
"moderator": "The owner of<br/>this conference",
"videomute": "Participant has<br/>stopped the camera.",
"mute": "Participant is muted",
"kick": "Kick out",
"muted": "Muted",
"domute": "Mute"
},
"connectionindicator":
{
"bitrate": "Bitrate:",
"packetloss": "Packet loss:",
"resolution": "Resolution:",
"less": "Show less",
"more": "Show more",
"address": "Address:",
"remoteport_plural": "Remote ports:",
"localport_plural": "Local ports:",
"remoteport": "Remote port:",
"localport": "Local port:",
"localaddress": "Local address:",
"localaddress_plural": "Local addresses:",
"remoteaddress": "Remote address:",
"remoteaddress_plural": "Remote addresses:",
"transport": "Transport:",
"bandwidth": "Estimated bandwidth:",
"na": "Come back here for connection information once the conference starts"
},
"notify": {
"disconnected": "disconnected",
"moderator": "Moderator rights granted!",
"connected": "connected",
"somebody": "Somebody",
"me": "Me",
"focus": "Conference focus",
"focusFail": "__component__ not available - retry in __ms__ sec",
"grantedTo": "Moderator rights granted to __to__!",
"grantedToUnknown": "Moderator rights granted to $t(somebody)!"
},
"dialog": {
"kickMessage": "Ouch! You have been kicked out of the meet!",
"popupError": "Your browser is blocking popup windows from this site. Please enable popups in your browser security settings and try again.",
"passwordError": "This conversation is currently protected by a password. Only the owner of the conference could set a password.",
"passwordError2": "This conversation isn't currently protected by a password. Only the owner of the conference could set a password.",
"joinError": "Oops! We couldn't join the conference. There might be some problem with security configuration. Please contact service administrator.",
"connectError": "Oops! Something went wrong and we couldn't connect to the conference.",
"error": "Error",
"detectext": "Error when trying to detect desktopsharing extension.",
"failtoinstall": "Failed to install desktop sharing extension",
"failedpermissions": "Failed to obtain permissions to use the local microphone and/or camera.",
"bridgeUnavailable": "Jitsi Videobridge is currently unavailable. Please try again later!",
"lockTitle": "Lock failed",
"lockMessage": "Failed to lock conference.",
"warning": "Warning",
"passwordNotSupported": "Room passwords are currently not supported.",
"sorry": "Sorry",
"internalError": "Internal application error [setRemoteDescription]",
"unableToSwitch": "Unable to switch video stream.",
"SLDFailure": "Oops! Something went wrong and we failed to mute! (SLD Failure)",
"SRDFailure": "Oops! Something went wrong and we failed to stop video! (SRD Failure)",
"oops": "Oops!",
"defaultError": "There was some kind of error",
"passwordRequired": "Password required",
"Ok": "Ok",
"removePreziTitle": "Remove Prezi",
"removePreziMsg": "Are you sure you would like to remove your Prezi?",
"sharePreziTitle": "Share a Prezi",
"sharePreziMsg": "Another participant is already sharing a Prezi.This conference allows only one Prezi at a time.",
"Remove": "Remove",
"Stop": "Stop",
"AuthMsg": "Authentication is required to create room:<br/><b>__room__ </b></br> You can either authenticate to create the room or just wait for someone else to do so.",
"Authenticate": "Authenticate",
"Cancel": "Cancel",
"logoutTitle" : "Logout",
"logoutQuestion" : "Are you sure you want to logout and stop the conference?",
"sessTerminated": "Session Terminated",
"hungUp": "You hung up the call",
"joinAgain": "Join again",
"Share": "Share",
"preziLinkError": "Please provide a correct prezi link.",
"Save": "Save",
"recordingToken": "Enter recording token",
"Dial": "Dial",
"sipMsg": "Enter SIP number",
"passwordCheck": "Are you sure you would like to remove your password?",
"Remove": "Remove",
"passwordMsg": "Set a password to lock your room",
"Invite": "Invite",
"shareLink": "Share this link with everyone you want to invite",
"settings1": "Configure your conference",
"settings2": "Participants join muted",
"settings3": "Require nicknames<br/><br/>Set a password to lock your room:",
"yourPassword": "your password",
"Back": "Back",
"serviceUnavailable": "Service unavailable",
"gracefulShutdown": "Our service is currently down for maintenance. Please try again later.",
"Yes": "Yes",
"reservationError": "Reservation system error",
"reservationErrorMsg": "Error code: __code__, message: __msg__",
"password": "password",
"userPassword": "user password",
"token": "token"
},
"email":
{
"sharedKey": [
"This conference is password protected. Please use the following pin when joining:",
"",
"",
"__sharedKey__",
"",
""],
"subject": "Invitation to a __appName__ (__conferenceName__)",
"body": [
"Hey there, I%27d like to invite you to a __appName__ conference I%27ve just set up.",
"",
"",
"Please click on the following link in order to join the conference.",
"",
"",
"__roomUrl__",
"",
"",
"__sharedKeyText__",
" Note that __appName__ is currently only supported by __supportedBrowsers__, so you need to be using one of these browsers.",
"",
"",
"Talk to you in a sec!"
],
"and": "and"
}
}

26842
libs/app.bundle.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,234 +0,0 @@
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.API=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* Implements API class that communicates with external api class
* and provides interface to access Jitsi Meet features by external
* applications that embed Jitsi Meet
*/
/**
* List of the available commands.
* @type {{
* displayName: inputDisplayNameHandler,
* muteAudio: toggleAudio,
* muteVideo: toggleVideo,
* filmStrip: toggleFilmStrip
* }}
*/
var commands =
{
displayName: UI.inputDisplayNameHandler,
muteAudio: UI.toggleAudio,
muteVideo: UI.toggleVideo,
toggleFilmStrip: UI.toggleFilmStrip,
toggleChat: UI.toggleChat,
toggleContactList: UI.toggleContactList
};
/**
* Maps the supported events and their status
* (true it the event is enabled and false if it is disabled)
* @type {{
* incomingMessage: boolean,
* outgoingMessage: boolean,
* displayNameChange: boolean,
* participantJoined: boolean,
* participantLeft: boolean
* }}
*/
var events =
{
incomingMessage: false,
outgoingMessage:false,
displayNameChange: false,
participantJoined: false,
participantLeft: false
};
var displayName = {};
/**
* Processes commands from external applicaiton.
* @param message the object with the command
*/
function processCommand(message)
{
if(message.action != "execute")
{
console.error("Unknown action of the message");
return;
}
for(var key in message)
{
if(commands[key])
commands[key].apply(null, message[key]);
}
}
/**
* Processes events objects from external applications
* @param event the event
*/
function processEvent(event) {
if(!event.action)
{
console.error("Event with no action is received.");
return;
}
var i = 0;
switch(event.action)
{
case "add":
for(; i < event.events.length; i++)
{
events[event.events[i]] = true;
}
break;
case "remove":
for(; i < event.events.length; i++)
{
events[event.events[i]] = false;
}
break;
default:
console.error("Unknown action for event.");
}
}
/**
* Sends message to the external application.
* @param object
*/
function sendMessage(object) {
window.parent.postMessage(JSON.stringify(object), "*");
}
/**
* Processes a message event from the external application
* @param event the message event
*/
function processMessage(event)
{
var message;
try {
message = JSON.parse(event.data);
} catch (e) {}
if(!message.type)
return;
switch (message.type)
{
case "command":
processCommand(message);
break;
case "event":
processEvent(message);
break;
default:
console.error("Unknown type of the message");
return;
}
}
function setupListeners() {
xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) {
API.triggerEvent("participantJoined", {jid: from});
});
xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) {
if (from != myjid)
API.triggerEvent("incomingMessage",
{"from": from, "nick": nick, "message": txt});
});
xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) {
API.triggerEvent("participantLeft", {jid: jid});
});
xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) {
name = displayName[jid];
if(!name || name != newDisplayName) {
API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName});
displayName[jid] = newDisplayName;
}
});
xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) {
API.triggerEvent("outgoingMessage", {"message": body});
});
}
var API = {
/**
* Check whether the API should be enabled or not.
* @returns {boolean}
*/
isEnabled: function () {
var hash = location.hash;
if(hash && hash.indexOf("external") > -1 && window.postMessage)
return true;
return false;
},
/**
* Initializes the APIConnector. Setups message event listeners that will
* receive information from external applications that embed Jitsi Meet.
* It also sends a message to the external application that APIConnector
* is initialized.
*/
init: function () {
if (window.addEventListener)
{
window.addEventListener('message',
processMessage, false);
}
else
{
window.attachEvent('onmessage', processMessage);
}
sendMessage({type: "system", loaded: true});
setupListeners();
},
/**
* Checks whether the event is enabled ot not.
* @param name the name of the event.
* @returns {*}
*/
isEventEnabled: function (name) {
return events[name];
},
/**
* Sends event object to the external application that has been subscribed
* for that event.
* @param name the name event
* @param object data associated with the event
*/
triggerEvent: function (name, object) {
if(this.isEnabled() && this.isEventEnabled(name))
sendMessage({
type: "event", action: "result", event: name, result: object});
},
/**
* Removes the listeners.
*/
dispose: function () {
if(window.removeEventListener)
{
window.removeEventListener("message",
processMessage, false);
}
else
{
window.detachEvent('onmessage', processMessage);
}
}
};
module.exports = API;
},{}]},{},[1])(1)
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,438 +0,0 @@
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self),n.connectionquality=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
/**
* local stats
* @type {{}}
*/
var stats = {};
/**
* remote stats
* @type {{}}
*/
var remoteStats = {};
/**
* Interval for sending statistics to other participants
* @type {null}
*/
var sendIntervalId = null;
/**
* Start statistics sending.
*/
function startSendingStats() {
sendStats();
sendIntervalId = setInterval(sendStats, 10000);
}
/**
* Sends statistics to other participants
*/
function sendStats() {
xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
}
/**
* Converts statistics to format for sending through XMPP
* @param stats the statistics
* @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}}
*/
function convertToMUCStats(stats) {
return {
"bitrate_download": stats.bitrate.download,
"bitrate_upload": stats.bitrate.upload,
"packetLoss_total": stats.packetLoss.total,
"packetLoss_download": stats.packetLoss.download,
"packetLoss_upload": stats.packetLoss.upload
};
}
/**
* Converts statitistics to format used by VideoLayout
* @param stats
* @returns {{bitrate: {download: *, upload: *}, packetLoss: {total: *, download: *, upload: *}}}
*/
function parseMUCStats(stats) {
return {
bitrate: {
download: stats.bitrate_download,
upload: stats.bitrate_upload
},
packetLoss: {
total: stats.packetLoss_total,
download: stats.packetLoss_download,
upload: stats.packetLoss_upload
}
};
}
var ConnectionQuality = {
init: function () {
xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
statistics.addConnectionStatsListener(this.updateLocalStats);
statistics.addRemoteStatsStopListener(this.stopSendingStats);
},
/**
* Updates the local statistics
* @param data new statistics
*/
updateLocalStats: function (data) {
stats = data;
eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, 100 - stats.packetLoss.total, stats);
if (sendIntervalId == null) {
startSendingStats();
}
},
/**
* Updates remote statistics
* @param jid the jid associated with the statistics
* @param data the statistics
*/
updateRemoteStats: function (jid, data) {
if (data == null || data.packetLoss_total == null) {
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, jid, null, null);
return;
}
remoteStats[jid] = parseMUCStats(data);
eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED,
jid, 100 - data.packetLoss_total, remoteStats[jid]);
},
/**
* Stops statistics sending.
*/
stopSendingStats: function () {
clearInterval(sendIntervalId);
sendIntervalId = null;
//notify UI about stopping statistics gathering
eventEmitter.emit(CQEvents.STOP);
},
/**
* Returns the local statistics.
*/
getStats: function () {
return stats;
},
addListener: function (type, listener) {
eventEmitter.on(type, listener);
}
};
module.exports = ConnectionQuality;
},{"events":2}],2:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}]},{},[1])(1)
});

View File

@@ -1,628 +0,0 @@
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.desktopsharing=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/* global $, alert, changeLocalVideo, chrome, config, getConferenceHandler, getUserMediaWithConstraints */
/**
* Indicates that desktop stream is currently in use(for toggle purpose).
* @type {boolean}
*/
var isUsingScreenStream = false;
/**
* Indicates that switch stream operation is in progress and prevent from triggering new events.
* @type {boolean}
*/
var switchInProgress = false;
/**
* Method used to get screen sharing stream.
*
* @type {function (stream_callback, failure_callback}
*/
var obtainDesktopStream = null;
/**
* Flag used to cache desktop sharing enabled state. Do not use directly as it can be <tt>null</tt>.
* @type {null|boolean}
*/
var _desktopSharingEnabled = null;
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
/**
* Method obtains desktop stream from WebRTC 'screen' source.
* Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
*/
function obtainWebRTCScreen(streamCallback, failCallback) {
RTC.getUserMediaWithConstraints(
['screen'],
streamCallback,
failCallback
);
}
/**
* Constructs inline install URL for Chrome desktop streaming extension.
* The 'chromeExtensionId' must be defined in config.js.
* @returns {string}
*/
function getWebStoreInstallUrl()
{
return "https://chrome.google.com/webstore/detail/" + config.chromeExtensionId;
}
/**
* Checks whether extension update is required.
* @param minVersion minimal required version
* @param extVersion current extension version
* @returns {boolean}
*/
function isUpdateRequired(minVersion, extVersion)
{
try
{
var s1 = minVersion.split('.');
var s2 = extVersion.split('.');
var len = Math.max(s1.length, s2.length);
for (var i = 0; i < len; i++)
{
var n1 = 0,
n2 = 0;
if (i < s1.length)
n1 = parseInt(s1[i]);
if (i < s2.length)
n2 = parseInt(s2[i]);
if (isNaN(n1) || isNaN(n2))
{
return true;
}
else if (n1 !== n2)
{
return n1 > n2;
}
}
// will happen if boths version has identical numbers in
// their components (even if one of them is longer, has more components)
return false;
}
catch (e)
{
console.error("Failed to parse extension version", e);
UI.messageHandler.showError('Error',
'Error when trying to detect desktopsharing extension.');
return true;
}
}
function checkExtInstalled(isInstalledCallback) {
if (!chrome.runtime) {
// No API, so no extension for sure
isInstalledCallback(false);
return;
}
chrome.runtime.sendMessage(
config.chromeExtensionId,
{ getVersion: true },
function (response) {
if (!response || !response.version) {
// Communication failure - assume that no endpoint exists
console.warn("Extension not installed?: " + chrome.runtime.lastError);
isInstalledCallback(false);
} else {
// Check installed extension version
var extVersion = response.version;
console.log('Extension version is: ' + extVersion);
var updateRequired = isUpdateRequired(config.minChromeExtVersion, extVersion);
if (updateRequired) {
alert(
'Jitsi Desktop Streamer requires update. ' +
'Changes will take effect after next Chrome restart.');
}
isInstalledCallback(!updateRequired);
}
}
);
}
function doGetStreamFromExtension(streamCallback, failCallback) {
// Sends 'getStream' msg to the extension. Extension id must be defined in the config.
chrome.runtime.sendMessage(
config.chromeExtensionId,
{ getStream: true, sources: config.desktopSharingSources },
function (response) {
if (!response) {
failCallback(chrome.runtime.lastError);
return;
}
console.log("Response from extension: " + response);
if (response.streamId) {
RTC.getUserMediaWithConstraints(
['desktop'],
function (stream) {
streamCallback(stream);
},
failCallback,
null, null, null,
response.streamId);
} else {
failCallback("Extension failed to get the stream");
}
}
);
}
/**
* Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop' stream for returned stream token.
*/
function obtainScreenFromExtension(streamCallback, failCallback) {
checkExtInstalled(
function (isInstalled) {
if (isInstalled) {
doGetStreamFromExtension(streamCallback, failCallback);
} else {
chrome.webstore.install(
getWebStoreInstallUrl(),
function (arg) {
console.log("Extension installed successfully", arg);
// We need to reload the page in order to get the access to chrome.runtime
window.location.reload(false);
},
function (arg) {
console.log("Failed to install the extension", arg);
failCallback(arg);
UI.messageHandler.showError('Error',
'Failed to install desktop sharing extension');
}
);
}
}
);
}
/**
* Call this method to toggle desktop sharing feature.
* @param method pass "ext" to use chrome extension for desktop capture(chrome extension required),
* pass "webrtc" to use WebRTC "screen" desktop source('chrome://flags/#enable-usermedia-screen-capture'
* must be enabled), pass any other string or nothing in order to disable this feature completely.
*/
function setDesktopSharing(method) {
// Check if we are running chrome
if (!navigator.webkitGetUserMedia) {
obtainDesktopStream = null;
console.info("Desktop sharing disabled");
} else if (method == "ext") {
obtainDesktopStream = obtainScreenFromExtension;
console.info("Using Chrome extension for desktop sharing");
} else if (method == "webrtc") {
obtainDesktopStream = obtainWebRTCScreen;
console.info("Using Chrome WebRTC for desktop sharing");
}
// Reset enabled cache
_desktopSharingEnabled = null;
}
/**
* Initializes <link rel=chrome-webstore-item /> with extension id set in config.js to support inline installs.
* Host site must be selected as main website of published extension.
*/
function initInlineInstalls()
{
$("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
}
function getSwitchStreamFailed(error) {
console.error("Failed to obtain the stream to switch to", error);
switchInProgress = false;
}
function streamSwitchDone() {
switchInProgress = false;
eventEmitter.emit(
DesktopSharingEventTypes.SWITCHING_DONE,
isUsingScreenStream);
}
function newStreamCreated(stream)
{
eventEmitter.emit(DesktopSharingEventTypes.NEW_STREAM_CREATED,
stream, isUsingScreenStream, streamSwitchDone);
}
module.exports = {
isUsingScreenStream: function () {
return isUsingScreenStream;
},
/**
* @returns {boolean} <tt>true</tt> if desktop sharing feature is available and enabled.
*/
isDesktopSharingEnabled: function () {
if (_desktopSharingEnabled === null) {
if (obtainDesktopStream === obtainScreenFromExtension) {
// Parse chrome version
var userAgent = navigator.userAgent.toLowerCase();
// We can assume that user agent is chrome, because it's enforced when 'ext' streaming method is set
var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10);
console.log("Chrome version" + userAgent, ver);
_desktopSharingEnabled = ver >= 34;
} else {
_desktopSharingEnabled = obtainDesktopStream === obtainWebRTCScreen;
}
}
return _desktopSharingEnabled;
},
init: function () {
setDesktopSharing(config.desktopSharing);
// Initialize Chrome extension inline installs
if (config.chromeExtensionId) {
initInlineInstalls();
}
eventEmitter.emit(DesktopSharingEventTypes.INIT);
},
addListener: function(listener, type)
{
eventEmitter.on(type, listener);
},
removeListener: function (listener,type) {
eventEmitter.removeListener(type, listener);
},
/*
* Toggles screen sharing.
*/
toggleScreenSharing: function () {
if (switchInProgress || !obtainDesktopStream) {
console.warn("Switch in progress or no method defined");
return;
}
switchInProgress = true;
if (!isUsingScreenStream)
{
// Switch to desktop stream
obtainDesktopStream(
function (stream) {
// We now use screen stream
isUsingScreenStream = true;
// Hook 'ended' event to restore camera when screen stream stops
stream.addEventListener('ended',
function (e) {
if (!switchInProgress && isUsingScreenStream) {
toggleScreenSharing();
}
}
);
newStreamCreated(stream);
},
getSwitchStreamFailed);
} else {
// Disable screen stream
RTC.getUserMediaWithConstraints(
['video'],
function (stream) {
// We are now using camera stream
isUsingScreenStream = false;
newStreamCreated(stream);
},
getSwitchStreamFailed, config.resolution || '360'
);
}
}
};
},{"events":2}],2:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
function EventEmitter() {
this._events = this._events || {};
this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;
// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
if (!isNumber(n) || n < 0 || isNaN(n))
throw TypeError('n must be a positive number');
this._maxListeners = n;
return this;
};
EventEmitter.prototype.emit = function(type) {
var er, handler, len, args, i, listeners;
if (!this._events)
this._events = {};
// If there is no 'error' event listener then throw.
if (type === 'error') {
if (!this._events.error ||
(isObject(this._events.error) && !this._events.error.length)) {
er = arguments[1];
if (er instanceof Error) {
throw er; // Unhandled 'error' event
}
throw TypeError('Uncaught, unspecified "error" event.');
}
}
handler = this._events[type];
if (isUndefined(handler))
return false;
if (isFunction(handler)) {
switch (arguments.length) {
// fast cases
case 1:
handler.call(this);
break;
case 2:
handler.call(this, arguments[1]);
break;
case 3:
handler.call(this, arguments[1], arguments[2]);
break;
// slower
default:
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
handler.apply(this, args);
}
} else if (isObject(handler)) {
len = arguments.length;
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
listeners = handler.slice();
len = listeners.length;
for (i = 0; i < len; i++)
listeners[i].apply(this, args);
}
return true;
};
EventEmitter.prototype.addListener = function(type, listener) {
var m;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events)
this._events = {};
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (this._events.newListener)
this.emit('newListener', type,
isFunction(listener.listener) ?
listener.listener : listener);
if (!this._events[type])
// Optimize the case of one listener. Don't need the extra array object.
this._events[type] = listener;
else if (isObject(this._events[type]))
// If we've already got an array, just append.
this._events[type].push(listener);
else
// Adding the second element, need to change to array.
this._events[type] = [this._events[type], listener];
// Check for listener leak
if (isObject(this._events[type]) && !this._events[type].warned) {
var m;
if (!isUndefined(this._maxListeners)) {
m = this._maxListeners;
} else {
m = EventEmitter.defaultMaxListeners;
}
if (m && m > 0 && this._events[type].length > m) {
this._events[type].warned = true;
console.error('(node) warning: possible EventEmitter memory ' +
'leak detected. %d listeners added. ' +
'Use emitter.setMaxListeners() to increase limit.',
this._events[type].length);
if (typeof console.trace === 'function') {
// not supported in IE 10
console.trace();
}
}
}
return this;
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.once = function(type, listener) {
if (!isFunction(listener))
throw TypeError('listener must be a function');
var fired = false;
function g() {
this.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
g.listener = listener;
this.on(type, g);
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
var list, position, length, i;
if (!isFunction(listener))
throw TypeError('listener must be a function');
if (!this._events || !this._events[type])
return this;
list = this._events[type];
length = list.length;
position = -1;
if (list === listener ||
(isFunction(list.listener) && list.listener === listener)) {
delete this._events[type];
if (this._events.removeListener)
this.emit('removeListener', type, listener);
} else if (isObject(list)) {
for (i = length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list.length = 0;
delete this._events[type];
} else {
list.splice(position, 1);
}
if (this._events.removeListener)
this.emit('removeListener', type, listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners = function(type) {
var key, listeners;
if (!this._events)
return this;
// not listening for removeListener, no need to emit
if (!this._events.removeListener) {
if (arguments.length === 0)
this._events = {};
else if (this._events[type])
delete this._events[type];
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
for (key in this._events) {
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = {};
return this;
}
listeners = this._events[type];
if (isFunction(listeners)) {
this.removeListener(type, listeners);
} else {
// LIFO order
while (listeners.length)
this.removeListener(type, listeners[listeners.length - 1]);
}
delete this._events[type];
return this;
};
EventEmitter.prototype.listeners = function(type) {
var ret;
if (!this._events || !this._events[type])
ret = [];
else if (isFunction(this._events[type]))
ret = [this._events[type]];
else
ret = this._events[type].slice();
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
var ret;
if (!emitter._events || !emitter._events[type])
ret = 0;
else if (isFunction(emitter._events[type]))
ret = 1;
else
ret = emitter._events[type].length;
return ret;
};
function isFunction(arg) {
return typeof arg === 'function';
}
function isNumber(arg) {
return typeof arg === 'number';
}
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
function isUndefined(arg) {
return arg === void 0;
}
},{}]},{},[1])(1)
});

View File

@@ -1,95 +0,0 @@
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var o;"undefined"!=typeof window?o=window:"undefined"!=typeof global?o=global:"undefined"!=typeof self&&(o=self),o.keyboardshortcut=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
//maps keycode to character, id of popover for given function and function
var shortcuts = {
67: {
character: "C",
id: "toggleChatPopover",
function: UI.toggleChat
},
70: {
character: "F",
id: "filmstripPopover",
function: UI.toggleFilmStrip
},
77: {
character: "M",
id: "mutePopover",
function: UI.toggleAudio
},
84: {
character: "T",
function: function() {
if(!RTC.localAudio.isMuted()) {
UI.toggleAudio();
}
}
},
86: {
character: "V",
id: "toggleVideoPopover",
function: UI.toggleVideo
}
};
var KeyboardShortcut = {
init: function () {
window.onkeyup = function(e) {
var keycode = e.which;
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if (typeof shortcuts[keycode] === "object") {
shortcuts[keycode].function();
}
else if (keycode >= "0".charCodeAt(0) &&
keycode <= "9".charCodeAt(0)) {
UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1);
}
//esc while the smileys are visible hides them
} else if (keycode === 27 && $('#smileysContainer').is(':visible')) {
UI.toggleSmileys();
}
};
window.onkeydown = function(e) {
if(!($(":focus").is("input[type=text]") ||
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if(e.which === "T".charCodeAt(0)) {
if(RTC.localAudio.isMuted()) {
UI.toggleAudio();
}
}
}
};
var self = this;
$('body').popover({ selector: '[data-toggle=popover]',
trigger: 'click hover',
content: function() {
return this.getAttribute("content") +
self.getShortcut(this.getAttribute("shortcut"));
}
});
},
/**
*
* @param id indicates the popover associated with the shortcut
* @returns {string} the keyboard shortcut used for the id given
*/
getShortcut: function (id) {
for (var keycode in shortcuts) {
if (shortcuts.hasOwnProperty(keycode)) {
if (shortcuts[keycode].id === id) {
return " (" + shortcuts[keycode].character + ")";
}
}
}
return "";
}
};
module.exports = KeyboardShortcut;
},{}]},{},[1])(1)
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
* applications that embed Jitsi Meet
*/
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
/**
* List of the available commands.
@@ -17,12 +17,12 @@
*/
var commands =
{
displayName: UI.inputDisplayNameHandler,
muteAudio: UI.toggleAudio,
muteVideo: UI.toggleVideo,
toggleFilmStrip: UI.toggleFilmStrip,
toggleChat: UI.toggleChat,
toggleContactList: UI.toggleContactList
displayName: APP.UI.inputDisplayNameHandler,
muteAudio: APP.UI.toggleAudio,
muteVideo: APP.UI.toggleVideo,
toggleFilmStrip: APP.UI.toggleFilmStrip,
toggleChat: APP.UI.toggleChat,
toggleContactList: APP.UI.toggleContactList
};
@@ -135,26 +135,26 @@ function processMessage(event)
}
function setupListeners() {
xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) {
APP.xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) {
API.triggerEvent("participantJoined", {jid: from});
});
xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) {
APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) {
if (from != myjid)
API.triggerEvent("incomingMessage",
{"from": from, "nick": nick, "message": txt});
});
xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) {
APP.xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) {
API.triggerEvent("participantLeft", {jid: jid});
});
xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) {
APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) {
name = displayName[jid];
if(!name || name != newDisplayName) {
API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName});
displayName[jid] = newDisplayName;
}
});
xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) {
API.triggerEvent("outgoingMessage", {"message": body});
APP.xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) {
APP.API.triggerEvent("outgoingMessage", {"message": body});
});
}

View File

@@ -2,7 +2,11 @@
// cache datachannels to avoid garbage collection
// https://code.google.com/p/chromium/issues/detail?id=405545
var RTCEvents = require("../../service/RTC/RTCEvents");
var _dataChannels = [];
var eventEmitter = null;
@@ -32,7 +36,7 @@ var DataChannels =
// selections so that it can do adaptive simulcast,
// we want the notification to trigger even if userJid is undefined,
// or null.
var userJid = UI.getLargeVideoState().userJid;
var userJid = APP.UI.getLargeVideoState().userResourceJid;
// we want the notification to trigger even if userJid is undefined,
// or null.
onSelectedEndpointChanged(userJid);
@@ -66,9 +70,7 @@ var DataChannels =
console.info(
"Data channel new dominant speaker event: ",
dominantSpeakerEndpoint);
$(document).trigger(
'dominantspeakerchanged',
[dominantSpeakerEndpoint]);
eventEmitter.emit(RTCEvents.DOMINANTSPEAKER_CHANGED, dominantSpeakerEndpoint);
}
else if ("InLastNChangeEvent" === colibriClass)
{
@@ -91,7 +93,8 @@ var DataChannels =
newValue = new Boolean(newValue).valueOf();
}
}
UI.onLastNChanged(oldValue, newValue);
eventEmitter.emit(RTCEvents.LASTN_CHANGED, oldValue, newValue);
}
else if ("LastNEndpointsChangeEvent" === colibriClass)
{
@@ -106,29 +109,26 @@ var DataChannels =
console.log(
"Data channel new last-n event: ",
lastNEndpoints, endpointsEnteringLastN, obj);
$(document).trigger(
'lastnchanged',
[lastNEndpoints, endpointsEnteringLastN, stream]);
eventEmitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED,
lastNEndpoints, endpointsEnteringLastN, obj);
}
else if ("SimulcastLayersChangedEvent" === colibriClass)
{
$(document).trigger(
'simulcastlayerschanged',
[obj.endpointSimulcastLayers]);
eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGED,
obj.endpointSimulcastLayers);
}
else if ("SimulcastLayersChangingEvent" === colibriClass)
{
$(document).trigger(
'simulcastlayerschanging',
[obj.endpointSimulcastLayers]);
eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGING,
obj.endpointSimulcastLayers);
}
else if ("StartSimulcastLayerEvent" === colibriClass)
{
$(document).trigger('startsimulcastlayer', obj.simulcastLayer);
eventEmitter.emit(RTCEvents.SIMULCAST_START, obj.simulcastLayer);
}
else if ("StopSimulcastLayerEvent" === colibriClass)
{
$(document).trigger('stopsimulcastlayer', obj.simulcastLayer);
eventEmitter.emit(RTCEvents.SIMULCAST_STOP, obj.simulcastLayer);
}
else
{
@@ -151,11 +151,12 @@ var DataChannels =
* Binds "ondatachannel" event listener to given PeerConnection instance.
* @param peerConnection WebRTC peer connection instance.
*/
bindDataChannelListener: function (peerConnection) {
init: function (peerConnection, emitter) {
if(!config.openSctp)
retrun;
return;
peerConnection.ondatachannel = this.onDataChannel;
eventEmitter = emitter;
// Sample code for opening new data channel from Jitsi Meet to the bridge.
// Although it's not a requirement to open separate channels from both bridge
@@ -179,9 +180,11 @@ var DataChannels =
var msgData = event.data;
console.info("Got My Data Channel Message:", msgData, dataChannel);
};*/
}
},
handleSelectedEndpointEvent: onSelectedEndpointChanged,
handlePinnedEndpointEvent: onPinnedEndpointChanged
}
};
function onSelectedEndpointChanged(userResource)
{
@@ -191,6 +194,8 @@ function onSelectedEndpointChanged(userResource)
_dataChannels.some(function (dataChannel) {
if (dataChannel.readyState == 'open')
{
console.log('sending selected endpoint changed '
+ 'notification to the bridge: ', userResource);
dataChannel.send(JSON.stringify({
'colibriClass': 'SelectedEndpointChangedEvent',
'selectedEndpoint':
@@ -204,10 +209,6 @@ function onSelectedEndpointChanged(userResource)
}
}
$(document).bind("selectedendpointchanged", function(event, userResource) {
onSelectedEndpointChanged(userResource);
});
function onPinnedEndpointChanged(userResource)
{
console.log('pinned endpoint changed: ', userResource);
@@ -229,9 +230,5 @@ function onPinnedEndpointChanged(userResource)
}
}
$(document).bind("pinnedendpointchanged", function(event, userResource) {
onPinnedEndpointChanged(userResource);
});
module.exports = DataChannels;

View File

@@ -1,4 +1,4 @@
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
function LocalStream(stream, type, eventEmitter, videoType)
{

View File

@@ -1,7 +1,6 @@
////These lines should be uncommented when require works in app.js
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
//var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
/**
* Creates a MediaStream object for the given data, session id and ssrc.
@@ -34,13 +33,6 @@ function MediaStream(data, sid, ssrc, browser) {
MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE;
this.videoType = null;
this.muted = false;
if(browser == RTCBrowserType.RTC_BROWSER_FIREFOX)
{
if (!this.getVideoTracks)
this.getVideoTracks = function () { return []; };
if (!this.getAudioTracks)
this.getAudioTracks = function () { return []; };
}
}

View File

@@ -3,9 +3,12 @@ var RTCUtils = require("./RTCUtils.js");
var LocalStream = require("./LocalStream.js");
var DataChannels = require("./DataChannels");
var MediaStream = require("./MediaStream.js");
//These lines should be uncommented when require works in app.js
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
//var XMPPEvents = require("../service/xmpp/XMPPEvents");
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var UIEvents = require("../../service/UI/UIEvents");
var eventEmitter = new EventEmitter();
@@ -18,6 +21,9 @@ var RTC = {
addStreamListener: function (listener, eventType) {
eventEmitter.on(eventType, listener);
},
addListener: function (type, listener) {
eventEmitter.on(type, listener);
},
removeStreamListener: function (listener, eventType) {
if(!(eventType instanceof StreamEventTypes))
throw "Illegal argument";
@@ -58,7 +64,7 @@ var RTC = {
createRemoteStream: function (data, sid, thessrc) {
var remoteStream = new MediaStream(data, sid, thessrc,
this.getBrowserType());
var jid = data.peerjid || xmpp.myJid();
var jid = data.peerjid || APP.xmpp.myJid();
if(!this.remoteStreams[jid]) {
this.remoteStreams[jid] = {};
}
@@ -102,11 +108,11 @@ var RTC = {
},
start: function () {
var self = this;
desktopsharing.addListener(
APP.desktopsharing.addListener(
function (stream, isUsingScreenStream, callback) {
self.changeLocalVideo(stream, isUsingScreenStream, callback);
}, DesktopSharingEventTypes.NEW_STREAM_CREATED);
xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
for(var i = 0; i < changedStreams.length; i++) {
var type = changedStreams[i].type;
if (type != "audio") {
@@ -120,9 +126,13 @@ var RTC = {
}
}
});
xmpp.addListener(XMPPEvents.CALL_INCOMING, function(event) {
DataChannels.bindDataChannelListener(event.peerconnection);
APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function(event) {
DataChannels.init(event.peerconnection, eventEmitter);
});
APP.UI.addListener(UIEvents.SELECTED_ENDPOINT,
DataChannels.handleSelectedEndpointEvent);
APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
DataChannels.handlePinnedEndpointEvent);
this.rtcUtils = new RTCUtils(this);
this.rtcUtils.obtainAudioAndVideoPermissions();
},
@@ -157,10 +167,10 @@ var RTC = {
changeLocalVideo: function (stream, isUsingScreenStream, callback) {
var oldStream = this.localVideo.getOriginalStream();
var type = (isUsingScreenStream? "screen" : "video");
RTC.localVideo = this.createLocalStream(stream, "video", true, type);
this.localVideo = this.createLocalStream(stream, "video", true, type);
// Stop the stream to trigger onended event for old stream
oldStream.stop();
xmpp.switchStreams(stream, oldStream,callback);
APP.xmpp.switchStreams(stream, oldStream,callback);
},
/**
* Checks if video identified by given src is desktop stream.
@@ -173,8 +183,8 @@ var RTC = {
return false;
var isDesktop = false;
var stream = null;
if (xmpp.myJid() &&
xmpp.myResource() === jid) {
if (APP.xmpp.myJid() &&
APP.xmpp.myResource() === jid) {
// local video
stream = this.localVideo;
} else {

View File

@@ -1,61 +1,52 @@
//This should be uncommented when app.js supports require
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
var Resolutions = require("../../service/RTC/Resolutions");
var currentResolution = null;
function getPreviousResolution(resolution) {
if(!Resolutions[resolution])
return null;
var order = Resolutions[resolution].order;
var res = null;
var resName = null;
for(var i in Resolutions)
{
var tmp = Resolutions[i];
if(res == null || (res.order < tmp.order && tmp.order < order))
{
resName = i;
res = tmp;
}
}
return resName;
}
function setResolutionConstraints(constraints, resolution, isAndroid)
{
if (resolution && !constraints.video || isAndroid) {
constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
}
// see https://code.google.com/p/chromium/issues/detail?id=143631#c9 for list of supported resolutions
switch (resolution) {
// 16:9 first
case '1080':
case 'fullhd':
constraints.video.mandatory.minWidth = 1920;
constraints.video.mandatory.minHeight = 1080;
break;
case '720':
case 'hd':
constraints.video.mandatory.minWidth = 1280;
constraints.video.mandatory.minHeight = 720;
break;
case '360':
constraints.video.mandatory.minWidth = 640;
constraints.video.mandatory.minHeight = 360;
break;
case '180':
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 180;
break;
// 4:3
case '960':
constraints.video.mandatory.minWidth = 960;
constraints.video.mandatory.minHeight = 720;
break;
case '640':
case 'vga':
constraints.video.mandatory.minWidth = 640;
constraints.video.mandatory.minHeight = 480;
break;
case '320':
if(Resolutions[resolution])
{
constraints.video.mandatory.minWidth = Resolutions[resolution].width;
constraints.video.mandatory.minHeight = Resolutions[resolution].height;
}
else
{
if (isAndroid) {
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 240;
break;
default:
if (isAndroid) {
constraints.video.mandatory.minWidth = 320;
constraints.video.mandatory.minHeight = 240;
constraints.video.mandatory.maxFrameRate = 15;
}
break;
constraints.video.mandatory.maxFrameRate = 15;
}
}
if (constraints.video.mandatory.minWidth)
constraints.video.mandatory.maxWidth = constraints.video.mandatory.minWidth;
if (constraints.video.mandatory.minHeight)
constraints.video.mandatory.maxHeight = constraints.video.mandatory.minHeight;
}
function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid)
{
var constraints = {audio: false, video: false};
@@ -115,7 +106,9 @@ function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid
}
}
setResolutionConstraints(constraints, resolution, isAndroid);
if (um.indexOf('video') >= 0) {
setResolutionConstraints(constraints, resolution, isAndroid);
}
if (bandwidth) { // doesn't work currently, see webrtc issue 1846
if (!constraints.video) constraints.video = {mandatory: {}, optional: []};//same behaviour as true
@@ -143,6 +136,13 @@ function RTCUtils(RTCService)
this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
this.pc_constraints = {};
this.attachMediaStream = function (element, stream) {
// srcObject is being standardized and FF will eventually
// support that unprefixed. FF also supports the
// "element.src = URL.createObjectURL(...)" combo, but that
// will be deprecated in favour of srcObject.
//
// https://groups.google.com/forum/#!topic/mozilla.dev.media/pKOiioXonJg
// https://github.com/webrtc/samples/issues/302
element[0].mozSrcObject = stream;
element[0].play();
};
@@ -202,13 +202,13 @@ function RTCUtils(RTCService)
{
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
window.location.href = 'webrtcrequired.html';
window.location.href = 'unsupported_browser.html';
return;
}
if (this.browser !== RTCBrowserType.RTC_BROWSER_CHROME &&
config.enableFirefoxSupport !== true) {
window.location.href = 'chromeonly.html';
window.location.href = 'unsupported_browser.html';
return;
}
@@ -219,6 +219,7 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
um, success_callback, failure_callback, resolution,bandwidth, fps,
desktopStream)
{
currentResolution = resolution;
// Check if we are running on Android device
var isAndroid = navigator.userAgent.indexOf('Android') != -1;
@@ -236,7 +237,7 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
// We currently do not support FF, as it doesn't have multistream support.
&& !isFF) {
simulcast.getUserMedia(constraints, function (stream) {
APP.simulcast.getUserMedia(constraints, function (stream) {
console.log('onUserMediaSuccess');
success_callback(stream);
},
@@ -277,28 +278,58 @@ RTCUtils.prototype.getUserMediaWithConstraints = function(
RTCUtils.prototype.obtainAudioAndVideoPermissions = function() {
var self = this;
// Get AV
var cb = function (stream) {
console.log('got', stream, stream.getAudioTracks().length, stream.getVideoTracks().length);
self.handleLocalStream(stream);
};
var self = this;
this.getUserMediaWithConstraints(
['audio', 'video'],
cb,
function (error) {
console.error('failed to obtain audio/video stream - trying audio only', error);
self.getUserMediaWithConstraints(
['audio'],
cb,
function (error) {
console.error('failed to obtain audio/video stream - stop', error);
UI.messageHandler.showError("Error",
"Failed to obtain permissions to use the local microphone" +
"and/or camera.");
}
);
function (stream) {
self.successCallback(stream);
},
config.resolution || '360');
function (error) {
self.errorCallback(error);
},
config.resolution || '360');
}
RTCUtils.prototype.successCallback = function (stream) {
console.log('got', stream, stream.getAudioTracks().length,
stream.getVideoTracks().length);
this.handleLocalStream(stream);
};
RTCUtils.prototype.errorCallback = function (error) {
var self = this;
console.error('failed to obtain audio/video stream - trying audio only', error);
var resolution = getPreviousResolution(currentResolution);
if(typeof error == "object" && error.constraintName && error.name
&& (error.name == "ConstraintNotSatisfiedError" ||
error.name == "OverconstrainedError") &&
(error.constraintName == "minWidth" || error.constraintName == "maxWidth" ||
error.constraintName == "minHeight" || error.constraintName == "maxHeight")
&& resolution != null)
{
self.getUserMediaWithConstraints(['audio', 'video'],
function (stream) {
return self.successCallback(stream);
}, function (error) {
return self.errorCallback(error);
}, resolution);
}
else
{
self.getUserMediaWithConstraints(
['audio'],
function (stream) {
return self.successCallback(stream);
},
function (error) {
console.error('failed to obtain audio/video stream - stop',
error);
APP.UI.messageHandler.showError("dialog.error",
"dialog.failedpermissions");
}
);
}
}
RTCUtils.prototype.handleLocalStream = function(stream)
@@ -331,4 +362,4 @@ RTCUtils.prototype.handleLocalStream = function(stream)
module.exports = RTCUtils;
module.exports = RTCUtils;

View File

@@ -1,8 +0,0 @@
{
"name": "RTC",
"version": "0.0.1",
"main": "RTC.js",
"description": "Provedes media streams and data channels utilities for Jitsi Meet",
"dependencies": {
}
}

View File

@@ -12,7 +12,7 @@ var ContactList = require("./side_pannels/contactlist/ContactList");
var Avatar = require("./avatar/Avatar");
var EventEmitter = require("events");
var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
var Settings = require("./side_pannels/settings/Settings");
var Settings = require("./../settings/Settings");
var PanelToggler = require("./side_pannels/SidePanelToggler");
var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
UI.messageHandler = require("./util/MessageHandler");
@@ -20,6 +20,12 @@ var messageHandler = UI.messageHandler;
var Authentication = require("./authentication/Authentication");
var UIUtil = require("./util/UIUtil");
var NicknameHandler = require("./util/NicknameHandler");
var CQEvents = require("../../service/connectionquality/CQEvents");
var DesktopSharingEventTypes
= require("../../service/desktopsharing/DesktopSharingEventTypes");
var RTCEvents = require("../../service/RTC/RTCEvents");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var eventEmitter = new EventEmitter();
var roomName = null;
@@ -73,22 +79,37 @@ function onDisplayNameChanged(jid, displayName) {
}
function registerListeners() {
RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
RTC.addStreamListener(function (stream) {
APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
APP.RTC.addStreamListener(function (stream) {
VideoLayout.onRemoteStreamAdded(stream);
}, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged);
APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (resourceJid) {
VideoLayout.onDominantSpeakerChanged(resourceJid);
});
APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
function (lastNEndpoints, endpointsEnteringLastN, stream) {
VideoLayout.onLastNEndpointsChanged(lastNEndpoints,
endpointsEnteringLastN, stream);
});
APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
function (endpointSimulcastLayers) {
VideoLayout.onSimulcastLayersChanged(endpointSimulcastLayers);
});
APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGING,
function (endpointSimulcastLayers) {
VideoLayout.onSimulcastLayersChanging(endpointSimulcastLayers);
});
VideoLayout.init();
statistics.addAudioLevelListener(function(jid, audioLevel)
APP.statistics.addAudioLevelListener(function(jid, audioLevel)
{
var resourceJid;
if(jid === statistics.LOCAL_JID)
if(jid === APP.statistics.LOCAL_JID)
{
resourceJid = AudioLevels.LOCAL_LEVEL;
if(RTC.localAudio.isMuted())
if(APP.RTC.localAudio.isMuted())
{
audioLevel = 0;
}
@@ -101,23 +122,64 @@ function registerListeners() {
AudioLevels.updateAudioLevel(resourceJid, audioLevel,
UI.getLargeVideoState().userResourceJid);
});
desktopsharing.addListener(function () {
APP.desktopsharing.addListener(function () {
ToolbarToggler.showDesktopSharingButton();
}, DesktopSharingEventTypes.INIT);
desktopsharing.addListener(
APP.desktopsharing.addListener(
Toolbar.changeDesktopSharingButtonState,
DesktopSharingEventTypes.SWITCHING_DONE);
xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
xmpp.addListener(XMPPEvents.KICKED, function () {
messageHandler.openMessageDialog("Session Terminated",
"Ouch! You have been kicked out of the meet!");
APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
VideoLayout.updateLocalConnectionStats);
APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
VideoLayout.updateConnectionStats);
APP.connectionquality.addListener(CQEvents.STOP,
VideoLayout.onStatsStop);
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
APP.xmpp.addListener(XMPPEvents.GRACEFUL_SHUTDOWN, function () {
messageHandler.openMessageDialog(
'dialog.serviceUnavailable',
'dialog.gracefulShutdown'
);
});
xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
messageHandler.showError("Error",
"Jitsi Videobridge is currently unavailable. Please try again later!");
APP.xmpp.addListener(XMPPEvents.RESERVATION_ERROR, function (code, msg) {
var title = APP.translation.generateTranslatonHTML(
"dialog.reservationError");
var message = APP.translation.generateTranslatonHTML(
"dialog.reservationErrorMsg", {code: code, msg: msg});
messageHandler.openDialog(
title,
message,
true, {},
function (event, value, message, formVals)
{
return false;
}
);
});
xmpp.addListener(XMPPEvents.USER_ID_CHANGED, Avatar.setUserAvatar);
xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
APP.xmpp.addListener(XMPPEvents.KICKED, function () {
messageHandler.openMessageDialog("dialog.sessTerminated",
"dialog.kickMessage");
});
APP.xmpp.addListener(XMPPEvents.MUC_DESTROYED, function (reason) {
//FIXME: use Session Terminated from translation, but
// 'reason' text comes from XMPP packet and is not translated
var title = APP.translation.generateTranslatonHTML("dialog.sessTerminated");
messageHandler.openDialog(
title, reason, true, {},
function (event, value, message, formVals)
{
return false;
}
);
});
APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
messageHandler.showError("dialog.error",
"dialog.bridgeUnavailable");
});
APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) {
Avatar.setUserAvatar(from, id);
});
APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
for(stream in changedStreams)
{
// might need to update the direction if participant just went from sendrecv to recvonly
@@ -137,26 +199,53 @@ function registerListeners() {
}
});
xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
xmpp.addListener(XMPPEvents.LOCALROLE_CHANGED, onLocalRoleChange);
xmpp.addListener(XMPPEvents.MUC_ENTER, onMucEntered);
xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
xmpp.addListener(XMPPEvents.MUC_LEFT, onMucLeft);
xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordReqiured);
xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
VideoLayout.updateLocalConnectionStats);
connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
VideoLayout.updateConnectionStats);
connectionquality.addListener(CQEvents.STOP,
VideoLayout.onStatsStop);
APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
APP.xmpp.addListener(XMPPEvents.LOCALROLE_CHANGED, onLocalRoleChange);
APP.xmpp.addListener(XMPPEvents.MUC_ENTER, onMucEntered);
APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
APP.xmpp.addListener(XMPPEvents.MUC_LEFT, onMucLeft);
APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordReqiured);
APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED, onAuthenticationRequired);
}
/**
* Mutes/unmutes the local video.
*
* @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
* @param options an object which specifies optional arguments such as the
* <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
* specifies whether the method was initiated in response to a user command (in
* contrast to an automatic decision taken by the application logic)
*/
function setVideoMute(mute, options) {
APP.xmpp.setVideoMute(
mute,
function (mute) {
var video = $('#video');
var communicativeClass = "icon-camera";
var muteClass = "icon-camera icon-camera-disabled";
if (mute) {
video.removeClass(communicativeClass);
video.addClass(muteClass);
} else {
video.removeClass(muteClass);
video.addClass(communicativeClass);
}
},
options);
}
function bindEvents()
{
/**
@@ -175,7 +264,7 @@ function bindEvents()
});
}
UI.start = function () {
UI.start = function (init) {
document.title = interfaceConfig.APP_NAME;
if(config.enableWelcomePage && window.location.pathname == "/" &&
(!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
@@ -220,7 +309,8 @@ UI.start = function () {
// Set the defaults for prompt dialogs.
jQuery.prompt.setDefaults({persistent: false});
VideoLayout.init(eventEmitter);
AudioLevels.init();
NicknameHandler.init(eventEmitter);
registerListeners();
bindEvents();
@@ -283,20 +373,8 @@ UI.start = function () {
"newestOnTop": false
};
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
});
SettingsMenu.init();
$("#updateSettings").click(function () {
SettingsMenu.update();
});
};
UI.toggleSmileys = function () {
Chat.toggleSmileys();
};
function chatAddError(errorMessage, originalText)
@@ -315,9 +393,8 @@ function updateChatConversation(from, displayName, message) {
function onMucJoined(jid, info) {
Toolbar.updateRoomUrl(window.location.href);
document.getElementById('localNick').appendChild(
document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
);
var meHTML = APP.translation.generateTranslatonHTML("me");
$("#localNick").html(Strophe.getResourceFromJid(jid) + " (" + meHTML + ")");
var settings = Settings.getSettings();
// Add myself to the contact list.
@@ -326,15 +403,11 @@ function onMucJoined(jid, info) {
// Once we've joined the muc show the toolbar
ToolbarToggler.showToolbar();
// Show authenticate button if needed
Toolbar.showAuthenticateButton(
xmpp.isExternalAuthEnabled() && !xmpp.isModerator());
var displayName = !config.displayJids
? info.displayName : Strophe.getResourceFromJid(jid);
if (displayName)
onDisplayNameChanged('localVideoContainer', displayName + ' (me)');
onDisplayNameChanged('localVideoContainer', displayName);
}
function initEtherpad(name) {
@@ -345,9 +418,9 @@ function onMucLeft(jid) {
console.log('left.muc', jid);
var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
'>.displayname').html();
messageHandler.notify(displayName || 'Somebody',
messageHandler.notify(displayName,'notify.somebody',
'disconnected',
'disconnected');
'notify.disconnected');
// Need to call this with a slight delay, otherwise the element couldn't be
// found for some reason.
// XXX(gp) it works fine without the timeout for me (with Chrome 38).
@@ -367,35 +440,18 @@ function onMucLeft(jid) {
};
UI.getSettings = function () {
return Settings.getSettings();
};
UI.toggleFilmStrip = function () {
return BottomToolbar.toggleFilmStrip();
};
UI.toggleChat = function () {
return BottomToolbar.toggleChat();
};
UI.toggleContactList = function () {
return BottomToolbar.toggleContactList();
};
function onLocalRoleChange(jid, info, pres, isModerator, isExternalAuthEnabled)
function onLocalRoleChange(jid, info, pres, isModerator)
{
console.info("My role changed, new role: " + info.role);
onModeratorStatusChanged(isModerator);
VideoLayout.showModeratorIndicator();
Toolbar.showAuthenticateButton(
isExternalAuthEnabled && !isModerator);
if (isModerator) {
Authentication.closeAuthenticationWindow();
messageHandler.notify(
'Me', 'connected', 'Moderator rights granted !');
messageHandler.notify(null, "notify.me",
'connected', "notify.moderator");
}
}
@@ -417,12 +473,18 @@ function onModeratorStatusChanged(isModerator) {
function onPasswordReqiured(callback) {
// password is required
Toolbar.lockLockButton();
var message = '<h2 data-i18n="dialog.passwordRequired">';
message += APP.translation.translateString(
"dialog.passwordRequired");
message += '</h2>' +
'<input id="lockKey" type="text" data-i18n=' +
'"[placeholder]dialog.password" placeholder="' +
APP.translation.translateString("dialog.password") +
'" autofocus>';
messageHandler.openTwoButtonDialog(null,
'<h2>Password required</h2>' +
'<input id="lockKey" type="text" placeholder="password" autofocus>',
messageHandler.openTwoButtonDialog(null, null, null, message,
true,
"Ok",
"dialog.Ok",
function (e, v, m, f) {},
function (event) {
document.getElementById('lockKey').focus();
@@ -439,9 +501,9 @@ function onPasswordReqiured(callback) {
);
}
function onMucEntered(jid, id, displayName) {
messageHandler.notify(displayName || 'Somebody',
messageHandler.notify(displayName,'notify.somebody',
'connected',
'connected');
'notify.connected');
// Add Peer's container
VideoLayout.ensurePeerContainerExists(jid,id);
@@ -456,26 +518,55 @@ function onMucRoleChanged(role, displayName) {
VideoLayout.showModeratorIndicator();
if (role === 'moderator') {
var displayName = displayName;
var messageKey, messageOptions = {};
if (!displayName) {
displayName = 'Somebody';
messageKey = "notify.grantedToUnknown";
}
else
{
messageKey = "notify.grantedTo";
messageOptions = {to: displayName};
}
messageHandler.notify(
displayName,
'connected',
'Moderator rights granted to ' + displayName + '!');
displayName,'notify.somebody',
'connected', messageKey,
messageOptions);
}
}
UI.onAuthenticationRequired = function (intervalCallback) {
function onAuthenticationRequired(intervalCallback) {
Authentication.openAuthenticationDialog(
roomName, intervalCallback, function () {
Toolbar.authenticateClicked();
});
};
UI.setRecordingButtonState = function (state) {
Toolbar.setRecordingButtonState(state);
function onLastNChanged(oldValue, newValue) {
if (config.muteLocalVideoIfNotInLastN) {
setVideoMute(!newValue, { 'byUser': false });
}
}
UI.toggleSmileys = function () {
Chat.toggleSmileys();
};
UI.getSettings = function () {
return Settings.getSettings();
};
UI.toggleFilmStrip = function () {
return BottomToolbar.toggleFilmStrip();
};
UI.toggleChat = function () {
return BottomToolbar.toggleChat();
};
UI.toggleContactList = function () {
return BottomToolbar.toggleContactList();
};
UI.inputDisplayNameHandler = function (value) {
@@ -488,10 +579,6 @@ UI.getLargeVideoState = function()
return VideoLayout.getLargeVideoState();
};
UI.showLocalAudioIndicator = function (mute) {
VideoLayout.showLocalAudioIndicator(mute);
};
UI.generateRoomName = function() {
if(roomName)
return roomName;
@@ -533,19 +620,15 @@ UI.connectionIndicatorShowMore = function(id)
return VideoLayout.connectionIndicators[id].showMore();
};
UI.showToolbar = function () {
return ToolbarToggler.showToolbar();
};
UI.dockToolbar = function (isDock) {
return ToolbarToggler.dockToolbar(isDock);
};
UI.getCreadentials = function () {
UI.getCredentials = function () {
var settings = this.getSettings();
return {
bosh: document.getElementById('boshURL').value,
password: document.getElementById('password').value,
jid: document.getElementById('jid').value
jid: document.getElementById('jid').value,
email: settings.email,
displayName: settings.displayName,
uid: settings.uid
};
};
@@ -556,13 +639,18 @@ UI.disableConnect = function () {
UI.showLoginPopup = function(callback)
{
console.log('password is required');
UI.messageHandler.openTwoButtonDialog(null,
'<h2>Password required</h2>' +
'<input id="passwordrequired.username" type="text" placeholder="user@domain.net" autofocus>' +
'<input id="passwordrequired.password" type="password" placeholder="user password">',
var message = '<h2 data-i18n="dialog.passwordRequired">';
message += APP.translation.translateString(
"dialog.passwordRequired");
message += '</h2>' +
'<input id="passwordrequired.username" type="text" ' +
'placeholder="user@domain.net" autofocus>' +
'<input id="passwordrequired.password" ' +
'type="password" data-i18n="[placeholder]dialog.userPassword"' +
' placeholder="user password">';
UI.messageHandler.openTwoButtonDialog(null, null, null, message,
true,
"Ok",
"dialog.Ok",
function (e, v, m, f) {
if (v) {
var username = document.getElementById('passwordrequired.username');
@@ -588,20 +676,20 @@ UI.checkForNicknameAndJoin = function () {
if (config.useNicks) {
nick = window.prompt('Your nickname (optional)');
}
xmpp.joinRoom(roomName, config.useNicks, nick);
}
APP.xmpp.joinRoom(roomName, config.useNicks, nick);
};
function dump(elem, filename) {
elem = elem.parentNode;
elem.download = filename || 'meetlog.json';
elem.href = 'data:application/json;charset=utf-8,\n';
var data = xmpp.populateData();
var data = APP.xmpp.populateData();
var metadata = {};
metadata.time = new Date();
metadata.url = window.location.href;
metadata.ua = navigator.userAgent;
var log = xmpp.getLogger();
var log = APP.xmpp.getLogger();
if (log) {
metadata.xmpp = log;
}
@@ -612,35 +700,7 @@ function dump(elem, filename) {
UI.getRoomName = function () {
return roomName;
}
/**
* Mutes/unmutes the local video.
*
* @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
* @param options an object which specifies optional arguments such as the
* <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
* specifies whether the method was initiated in response to a user command (in
* contrast to an automatic decision taken by the application logic)
*/
function setVideoMute(mute, options) {
xmpp.setVideoMute(
mute,
function (mute) {
var video = $('#video');
var communicativeClass = "icon-camera";
var muteClass = "icon-camera icon-camera-disabled";
if (mute) {
video.removeClass(communicativeClass);
video.addClass(muteClass);
} else {
video.removeClass(muteClass);
video.addClass(communicativeClass);
}
},
options);
}
};
/**
* Mutes/unmutes the local video.
@@ -648,14 +708,14 @@ function setVideoMute(mute, options) {
UI.toggleVideo = function () {
UIUtil.buttonClick("#video", "icon-camera icon-camera-disabled");
setVideoMute(!RTC.localVideo.isMuted());
setVideoMute(!APP.RTC.localVideo.isMuted());
};
/**
* Mutes / unmutes audio for the local participant.
*/
UI.toggleAudio = function() {
UI.setAudioMuted(!RTC.localAudio.isMuted());
UI.setAudioMuted(!APP.RTC.localAudio.isMuted());
};
/**
@@ -663,8 +723,8 @@ UI.toggleAudio = function() {
*/
UI.setAudioMuted = function (mute) {
if(!xmpp.setAudioMute(mute, function () {
UI.showLocalAudioIndicator(mute);
if(!APP.xmpp.setAudioMute(mute, function () {
VideoLayout.showLocalAudioIndicator(mute);
UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
}))
@@ -676,12 +736,6 @@ UI.setAudioMuted = function (mute) {
}
UI.onLastNChanged = function (oldValue, newValue) {
if (config.muteLocalVideoIfNotInLastN) {
setVideoMute(!newValue, { 'byUser': false });
}
}
UI.addListener = function (type, listener) {
eventEmitter.on(type, listener);
}
@@ -693,5 +747,15 @@ UI.clickOnVideo = function (videoNumber) {
}
}
//Used by torture
UI.showToolbar = function () {
return ToolbarToggler.showToolbar();
}
//Used by torture
UI.dockToolbar = function (isDock) {
return ToolbarToggler.dockToolbar(isDock);
}
module.exports = UI;

View File

@@ -1,5 +1,20 @@
var CanvasUtil = require("./CanvasUtils");
var ASDrawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
function initActiveSpeakerAudioLevels() {
var ASRadius = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
var ASCenter = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + ASRadius) / 2;
// Draw a circle.
ASDrawContext.arc(ASCenter, ASCenter, ASRadius, 0, 2 * Math.PI);
// Add a shadow around the circle
ASDrawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
ASDrawContext.shadowOffsetX = 0;
ASDrawContext.shadowOffsetY = 0;
}
/**
* The audio Levels plugin.
*/
@@ -8,6 +23,10 @@ var AudioLevels = (function(my) {
my.LOCAL_LEVEL = 'local';
my.init = function () {
initActiveSpeakerAudioLevels();
}
/**
* Updates the audio level canvas for the given peerJid. If the canvas
* didn't exist we create it.
@@ -87,51 +106,33 @@ var AudioLevels = (function(my) {
drawContext.drawImage(canvasCache, 0, 0);
if(resourceJid === AudioLevels.LOCAL_LEVEL) {
if(!xmpp.myJid()) {
if(!APP.xmpp.myJid()) {
return;
}
resourceJid = xmpp.myResource();
resourceJid = APP.xmpp.myResource();
}
if(resourceJid === largeVideoResourceJid) {
AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
window.requestAnimationFrame(function () {
AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
});
}
};
my.updateActiveSpeakerAudioLevel = function(audioLevel) {
var drawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
var r = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
var center = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + r) / 2;
if($("#activeSpeaker").css("visibility") == "hidden")
return;
// Save the previous state of the context.
drawContext.save();
drawContext.clearRect(0, 0, 300, 300);
ASDrawContext.clearRect(0, 0, 300, 300);
if(audioLevel == 0)
return;
// Draw a circle.
drawContext.arc(center, center, r, 0, 2 * Math.PI);
ASDrawContext.shadowBlur = getShadowLevel(audioLevel);
// Add a shadow around the circle
drawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
drawContext.shadowBlur = getShadowLevel(audioLevel);
drawContext.shadowOffsetX = 0;
drawContext.shadowOffsetY = 0;
// Fill the shape.
drawContext.fill();
drawContext.save();
drawContext.restore();
drawContext.arc(center, center, r, 0, 2 * Math.PI);
drawContext.clip();
drawContext.clearRect(0, 0, 277, 200);
// Restore the previous context state.
drawContext.restore();
ASDrawContext.fill();
};
/**
@@ -221,8 +222,8 @@ var AudioLevels = (function(my) {
function getVideoSpanId(resourceJid) {
var videoSpanId = null;
if (resourceJid === AudioLevels.LOCAL_LEVEL
|| (xmpp.myResource() && resourceJid
=== xmpp.myResource()))
|| (APP.xmpp.myResource() && resourceJid
=== APP.xmpp.myResource()))
videoSpanId = 'localVideoContainer';
else
videoSpanId = 'participant_' + resourceJid;

View File

@@ -16,15 +16,19 @@ var Authentication = {
// extract room name from 'room@muc.server.net'
var room = roomName.substr(0, roomName.indexOf('@'));
authDialog = messageHandler.openDialog(
'Stop',
'Authentication is required to create room:<br/><b>' + room +
'</b></br> You can either authenticate to create the room or ' +
'just wait for someone else to do so.',
var title = APP.translation.generateTranslatonHTML("dialog.Stop");
var msg = APP.translation.generateTranslatonHTML("dialog.AuthMsg",
{room: room});
var button = APP.translation.generateTranslatonHTML(
"dialog.Authenticate");
var buttons = {};
buttons.authenticate = {title: button, value: "authNow"};
authDialog = APP.UI.messageHandler.openDialog(
title,
msg,
true,
{
Authenticate: 'authNow'
},
buttons,
function (onSubmitEvent, submitValue) {
// Do not close the dialog yet
@@ -53,12 +57,12 @@ var Authentication = {
closeAuthenticationDialog: function () {
// Close authentication dialog if opened
if (authDialog) {
UI.messageHandler.closeDialog();
APP.UI.messageHandler.closeDialog();
authDialog = null;
}
},
createAuthenticationWindow: function (callback, url) {
authenticationWindow = messageHandler.openCenteredPopup(
authenticationWindow = APP.UI.messageHandler.openCenteredPopup(
url, 910, 660,
// On closed
function () {

View File

@@ -1,4 +1,5 @@
var Settings = require("../side_pannels/settings/Settings");
var Settings = require("../../settings/Settings");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
var users = {};
var activeSpeakerJid;
@@ -12,21 +13,21 @@ function setVisibility(selector, show) {
function isUserMuted(jid) {
// XXX(gp) we may want to rename this method to something like
// isUserStreaming, for example.
if (jid && jid != xmpp.myJid()) {
if (jid && jid != APP.xmpp.myJid()) {
var resource = Strophe.getResourceFromJid(jid);
if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
return true;
}
}
if (!RTC.remoteStreams[jid] || !RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
return null;
}
return RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
return APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
}
function getGravatarUrl(id, size) {
if(id === xmpp.myJid() || !id) {
if(id === APP.xmpp.myJid() || !id) {
id = Settings.getSettings().uid;
}
return 'https://www.gravatar.com/avatar/' +
@@ -57,7 +58,7 @@ var Avatar = {
// set the avatar in the settings menu if it is local user and get the
// local video container
if (jid === xmpp.myJid()) {
if (jid === APP.xmpp.myJid()) {
$('#avatar').get(0).src = thumbUrl;
thumbnail = $('#localVideoContainer');
}
@@ -100,7 +101,7 @@ var Avatar = {
var video = $('#participant_' + resourceJid + '>video');
var avatar = $('#avatar_' + resourceJid);
if (jid === xmpp.myJid()) {
if (jid === APP.xmpp.myJid()) {
video = $('#localVideoWrapper>video');
}
if (show === undefined || show === null) {
@@ -130,7 +131,7 @@ var Avatar = {
*/
updateActiveSpeakerAvatarSrc: function (jid) {
if (!jid) {
jid = xmpp.findJidFromResource(
jid = APP.xmpp.findJidFromResource(
require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
}
var avatar = $("#activeSpeakerAvatar")[0];

View File

@@ -1,4 +1,4 @@
/* global $, config, dockToolbar,
/* global $, config,
setLargeVideoVisible, Util */
var VideoLayout = require("../videolayout/VideoLayout");
@@ -30,7 +30,7 @@ function resize() {
* Shares the Etherpad name with other participants.
*/
function shareEtherpad() {
xmpp.addToPresence("etherpad", etherpadName);
APP.xmpp.addToPresence("etherpad", etherpadName);
}
/**

View File

@@ -31,39 +31,59 @@ var Prezi = {
* to load.
*/
openPreziDialog: function() {
var myprezi = xmpp.getPrezi();
var myprezi = APP.xmpp.getPrezi();
if (myprezi) {
messageHandler.openTwoButtonDialog("Remove Prezi",
"Are you sure you would like to remove your Prezi?",
messageHandler.openTwoButtonDialog("dialog.removePreziTitle",
null,
"dialog.removePreziMsg",
null,
false,
"Remove",
"dialog.Remove",
function(e,v,m,f) {
if(v) {
xmpp.removePreziFromPresence();
APP.xmpp.removePreziFromPresence();
}
}
);
}
else if (preziPlayer != null) {
messageHandler.openTwoButtonDialog("Share a Prezi",
"Another participant is already sharing a Prezi." +
"This conference allows only one Prezi at a time.",
messageHandler.openTwoButtonDialog("dialog.sharePreziTitle",
null, "dialog.sharePreziMsg",
null,
false,
"Ok",
"dialog.Ok",
function(e,v,m,f) {
$.prompt.close();
}
);
}
else {
var html = APP.translation.generateTranslatonHTML(
"dialog.sharePreziTitle");
var cancelButton = APP.translation.generateTranslatonHTML(
"dialog.Cancel");
var shareButton = APP.translation.generateTranslatonHTML(
"dialog.Share");
var backButton = APP.translation.generateTranslatonHTML(
"dialog.Back");
var buttons = {};
var buttons1 = {};
buttons1.button1 = buttons.button1 = {title: cancelButton, value: false};
buttons.button2 = {title: shareButton, value: true};
buttons1.button2 = {title: backButton, value: true};
var linkError = APP.translation.generateTranslatonHTML(
"dialog.preziLinkError");
var defaultUrl = APP.translation.translateString("defaultPreziLink",
{url: "http://prezi.com/wz7vhjycl7e6/my-prezi"});
var openPreziState = {
state0: {
html: '<h2>Share a Prezi</h2>' +
html: '<h2>' + html + '</h2>' +
'<input id="preziUrl" type="text" ' +
'placeholder="e.g. ' +
'http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
'data-i18n="[placeholder]defaultPreziLink" data-i18n-options=\'' +
JSON.stringify({"url": "http://prezi.com/wz7vhjycl7e6/my-prezi"}) +
'\' placeholder="' + defaultUrl + '" autofocus>',
persistent: false,
buttons: { "Share": true , "Cancel": false},
buttons: buttons,
defaultButton: 1,
submit: function(e,v,m,f){
e.preventDefault();
@@ -91,7 +111,7 @@ var Prezi = {
return false;
}
else {
xmpp.addToPresence("prezi", urlValue);
APP.xmpp.addToPresence("prezi", urlValue);
$.prompt.close();
}
}
@@ -102,10 +122,10 @@ var Prezi = {
}
},
state1: {
html: '<h2>Share a Prezi</h2>' +
'Please provide a correct prezi link.',
html: '<h2>' + html + '</h2>' +
linkError,
persistent: false,
buttons: { "Back": true, "Cancel": false },
buttons: buttons1,
defaultButton: 1,
submit:function(e,v,m,f) {
e.preventDefault();
@@ -149,7 +169,7 @@ function presentationAdded(event, jid, presUrl, currentSlide) {
VideoLayout.resizeThumbnails();
var controlsEnabled = false;
if (jid === xmpp.myJid())
if (jid === APP.xmpp.myJid())
controlsEnabled = true;
setPresentationVisible(true);
@@ -189,14 +209,14 @@ function presentationAdded(event, jid, presUrl, currentSlide) {
preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
console.log("prezi status", event.value);
if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
if (jid != xmpp.myJid())
if (jid != APP.xmpp.myJid())
preziPlayer.flyToStep(currentSlide);
}
});
preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
console.log("event value", event.value);
xmpp.addToPresence("preziSlide", event.value);
APP.xmpp.addToPresence("preziSlide", event.value);
});
$("#" + elementId).css( 'background-image',

View File

@@ -33,21 +33,22 @@
var message, item, player;
try {
message = JSON.parse(event.data);
} catch (e) {}
if (message.id && (player = PreziPlayer.players[message.id])){
if (player.options.debug === true) {
if (console && console.log) console.log('received', message);
}
if (message.type === "changes"){
player.changesHandler(message);
}
for (var i=0; i<player.callbacks.length; i++) {
item = player.callbacks[i];
if (item && message.type === item.event){
item.callback(message);
if (message.id && (player = PreziPlayer.players[message.id])) {
if (player.options.debug === true) {
if (console && console.log)
console.log('received', message);
}
if (message.type === "changes") {
player.changesHandler(message);
}
for (var i = 0; i < player.callbacks.length; i++) {
item = player.callbacks[i];
if (item && message.type === item.event) {
item.callback(message);
}
}
}
}
} catch (e) { }
};
function PreziPlayer(id, options) {

View File

@@ -1,6 +1,6 @@
var Chat = require("./chat/Chat");
var ContactList = require("./contactlist/ContactList");
var Settings = require("./settings/Settings");
var Settings = require("./../../settings/Settings");
var SettingsMenu = require("./settings/SettingsMenu");
var VideoLayout = require("../videolayout/VideoLayout");
var ToolbarToggler = require("../toolbars/ToolbarToggler");

View File

@@ -1,10 +1,11 @@
/* global $, Util, nickname:true, showToolbar */
/* global $, Util, nickname:true */
var Replacement = require("./Replacement");
var CommandsProcessor = require("./Commands");
var ToolbarToggler = require("../../toolbars/ToolbarToggler");
var smileys = require("./smileys.json").smileys;
var NicknameHandler = require("../../util/NicknameHandler");
var UIUtil = require("../../util/UIUtil");
var UIEvents = require("../../../../service/UI/UIEvents");
var notificationInterval = false;
var unreadMessages = 0;
@@ -204,7 +205,7 @@ var Chat = (function (my) {
else
{
var message = UIUtil.escapeHtml(value);
xmpp.sendChatMessage(message, NicknameHandler.getNickname());
APP.xmpp.sendChatMessage(message, NicknameHandler.getNickname());
}
}
});
@@ -230,7 +231,7 @@ var Chat = (function (my) {
my.updateChatConversation = function (from, displayName, message) {
var divClassName = '';
if (xmpp.myJid() === from) {
if (APP.xmpp.myJid() === from) {
divClassName = "localuser";
}
else {

View File

@@ -34,7 +34,7 @@ function getCommand(message)
function processTopic(commandArguments)
{
var topic = UIUtil.escapeHtml(commandArguments);
xmpp.setSubject(topic);
APP.xmpp.setSubject(topic);
}
/**

View File

@@ -38,9 +38,15 @@ function createAvatar(id) {
*
* @param displayName the display name to set
*/
function createDisplayNameParagraph(displayName) {
function createDisplayNameParagraph(key, displayName) {
var p = document.createElement('p');
p.innerText = displayName;
if(displayName)
p.innerText = displayName;
else if(key)
{
p.setAttribute("data-i18n",key);
p.innerText = APP.translation.translateString(key);
}
return p;
}
@@ -106,11 +112,11 @@ var ContactList = {
};
newContact.appendChild(createAvatar(id));
newContact.appendChild(createDisplayNameParagraph("Participant"));
newContact.appendChild(createDisplayNameParagraph("participant"));
var clElement = contactlist.get(0);
if (resourceJid === xmpp.myResource()
if (resourceJid === APP.xmpp.myResource()
&& $('#contactlist>ul .title')[0].nextSibling.nextSibling) {
clElement.insertBefore(newContact,
$('#contactlist>ul .title')[0].nextSibling.nextSibling);
@@ -169,7 +175,7 @@ var ContactList = {
onDisplayNameChange: function (peerJid, displayName) {
if (peerJid === 'localVideoContainer')
peerJid = xmpp.myJid();
peerJid = APP.xmpp.myJid();
var resourceJid = Strophe.getResourceFromJid(peerJid);

View File

@@ -1,25 +1,62 @@
var Avatar = require("../../avatar/Avatar");
var Settings = require("./Settings");
var Settings = require("./../../../settings/Settings");
var UIUtil = require("../../util/UIUtil");
var languages = require("../../../../service/translation/languages");
function generateLanguagesSelectBox()
{
var currentLang = APP.translation.getCurrentLanguage();
var html = "<select id=\"languages_selectbox\">";
var langArray = languages.getLanguages();
for(var i = 0; i < langArray.length; i++)
{
var lang = langArray[i];
html += "<option ";
if(lang === currentLang)
html += "selected ";
html += "value=\"" + lang + "\" data-i18n='languages:" + lang + "'>";
html += "</option>";
}
return html + "</select>";
}
var SettingsMenu = {
init: function () {
$("#updateSettings").before(generateLanguagesSelectBox());
APP.translation.translateElement($("#languages_selectbox"));
$('#settingsmenu>input').keyup(function(event){
if(event.keyCode === 13) {//enter
SettingsMenu.update();
}
});
$("#updateSettings").click(function () {
SettingsMenu.update();
});
},
update: function() {
var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
if(newDisplayName) {
var displayName = Settings.setDisplayName(newDisplayName);
xmpp.addToPresence("displayName", displayName, true);
APP.xmpp.addToPresence("displayName", displayName, true);
}
var language = $("#languages_selectbox").val();
APP.translation.setLanguage(language);
Settings.setLanguage(language);
xmpp.addToPresence("email", newEmail);
APP.xmpp.addToPresence("email", newEmail);
var email = Settings.setEmail(newEmail);
Avatar.setUserAvatar(xmpp.myJid(), email);
Avatar.setUserAvatar(APP.xmpp.myJid(), email);
},
isVisible: function() {
@@ -33,7 +70,7 @@ var SettingsMenu = {
onDisplayNameChange: function(peerJid, newDisplayName) {
if(peerJid === 'localVideoContainer' ||
peerJid === xmpp.myJid()) {
peerJid === APP.xmpp.myJid()) {
this.setDisplayName(newDisplayName);
}
}

View File

@@ -1,4 +1,4 @@
/* global $, buttonClick, config, lockRoom,
/* global APP,$, buttonClick, config, lockRoom,
setSharedKey, Util */
var messageHandler = require("../util/MessageHandler");
var BottomToolbar = require("./BottomToolbar");
@@ -7,6 +7,8 @@ var Etherpad = require("../etherpad/Etherpad");
var PanelToggler = require("../side_pannels/SidePanelToggler");
var Authentication = require("../authentication/Authentication");
var UIUtil = require("../util/UIUtil");
var AuthenticationEvents
= require("../../../service/authentication/AuthenticationEvents");
var roomUrl = null;
var sharedKey = '';
@@ -15,14 +17,14 @@ var UI = null;
var buttonHandlers =
{
"toolbar_button_mute": function () {
return UI.toggleAudio();
return APP.UI.toggleAudio();
},
"toolbar_button_camera": function () {
return UI.toggleVideo();
return APP.UI.toggleVideo();
},
"toolbar_button_authentication": function () {
/*"toolbar_button_authentication": function () {
return Toolbar.authenticateClicked();
},
},*/
"toolbar_button_record": function () {
return toggleRecording();
},
@@ -42,7 +44,7 @@ var buttonHandlers =
return Etherpad.toggleEtherpad(0);
},
"toolbar_button_desktopsharing": function () {
return desktopsharing.toggleScreenSharing();
return APP.desktopsharing.toggleScreenSharing();
},
"toolbar_button_fullScreen": function()
{
@@ -57,11 +59,35 @@ var buttonHandlers =
},
"toolbar_button_hangup": function () {
return hangup();
},
"toolbar_button_login": function () {
Toolbar.authenticateClicked();
},
"toolbar_button_logout": function () {
// Ask for confirmation
messageHandler.openTwoButtonDialog(
"dialog.logoutTitle",
null,
"dialog.logoutQuestion",
null,
false,
"dialog.Yes",
function (evt, yes) {
if (yes) {
APP.xmpp.logout(function (url) {
if (url) {
window.location.href = url;
} else {
hangup();
}
});
}
});
}
};
function hangup() {
xmpp.disposeConference();
APP.xmpp.disposeConference();
if(config.enableWelcomePage)
{
setTimeout(function()
@@ -72,11 +98,20 @@ function hangup() {
}
var title = APP.translation.generateTranslatonHTML(
"dialog.sessTerminated");
var msg = APP.translation.generateTranslatonHTML(
"dialog.hungUp");
var button = APP.translation.generateTranslatonHTML(
"dialog.joinAgain");
var buttons = {};
buttons.joinAgain = {title: button, value: true};
UI.messageHandler.openDialog(
"Session Terminated",
"You hung up the call",
title,
msg,
true,
{ "Join again": true },
buttons,
function(event, value, message, formVals)
{
window.location.reload();
@@ -90,13 +125,17 @@ function hangup() {
*/
function toggleRecording() {
xmpp.toggleRecording(function (callback) {
UI.messageHandler.openTwoButtonDialog(null,
'<h2>Enter recording token</h2>' +
APP.xmpp.toggleRecording(function (callback) {
var msg = APP.translation.generateTranslatonHTML(
"dialog.recordingToken");
var token = APP.translation.translateString("dialog.token");
APP.UI.messageHandler.openTwoButtonDialog(null, null, null,
'<h2>' + msg + '</h2>' +
'<input id="recordingToken" type="text" ' +
'placeholder="token" autofocus>',
' data-i18n="[placeholder]dialog.token" ' +
'placeholder="' + token + '" autofocus>',
false,
"Save",
"dialog.Save",
function (e, v, m, f) {
if (v) {
var token = document.getElementById('recordingToken');
@@ -123,7 +162,7 @@ function lockRoom(lock) {
if (lock)
currentSharedKey = sharedKey;
xmpp.lockRoom(currentSharedKey, function (res) {
APP.xmpp.lockRoom(currentSharedKey, function (res) {
// password is required
if (sharedKey)
{
@@ -137,14 +176,13 @@ function lockRoom(lock) {
}
}, function (err) {
console.warn('setting password failed', err);
messageHandler.showError('Lock failed',
'Failed to lock conference.',
err);
messageHandler.showError("dialog.lockTitle",
"dialog.lockMessage");
Toolbar.setSharedKey('');
}, function () {
console.warn('room passwords not supported');
messageHandler.showError('Warning',
'Room passwords are currently not supported.');
messageHandler.showError("dialog.warning",
"dialog.passwordNotSupported");
Toolbar.setSharedKey('');
});
};
@@ -159,25 +197,20 @@ function inviteParticipants() {
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";
APP.translation.translateString("email.sharedKey",
{sharedKey: sharedKey});
sharedKeyText = sharedKeyText.replace(/\n/g, "%0D%0A");
}
var supportedBrowsers = "Chromium, Google Chrome " +
APP.translation.translateString("email.and") + " Opera";
var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
var subject = "Invitation to a " + interfaceConfig.APP_NAME + " (" + conferenceName + ")";
var body = "Hey there, I%27d like to invite you to a " + interfaceConfig.APP_NAME +
" 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 " + interfaceConfig.APP_NAME + " is currently" +
" only supported by Chromium," +
" Google Chrome and Opera, so you need" +
" to be using one of these browsers.%0D%0A%0D%0A" +
"Talk to you in a sec!";
var subject = APP.translation.translateString("email.subject",
{appName:interfaceConfig.APP_NAME, conferenceName: conferenceName});
var body = APP.translation.translateString("email.body",
{appName:interfaceConfig.APP_NAME, sharedKeyText: sharedKeyText,
roomUrl: roomUrl, supportedBrowsers: supportedBrowsers});
body = body.replace(/\n/g, "%0D%0A");
if (window.localStorage.displayname) {
body += "%0D%0A%0D%0A" + window.localStorage.displayname;
@@ -195,17 +228,19 @@ function callSipButtonClicked()
var defaultNumber
= config.defaultSipNumber ? config.defaultSipNumber : '';
messageHandler.openTwoButtonDialog(null,
'<h2>Enter SIP number</h2>' +
var sipMsg = APP.translation.generateTranslatonHTML(
"dialog.sipMsg");
messageHandler.openTwoButtonDialog(null, null, null,
'<h2>' + sipMsg + '</h2>' +
'<input id="sipNumber" type="text"' +
' value="' + defaultNumber + '" autofocus>',
false,
"Dial",
"dialog.Dial",
function (e, v, m, f) {
if (v) {
var numberInput = document.getElementById('sipNumber');
if (numberInput.value) {
xmpp.dial(numberInput.value, 'fromnumber',
APP.xmpp.dial(numberInput.value, 'fromnumber',
UI.getRoomName(), sharedKey);
}
}
@@ -222,7 +257,33 @@ var Toolbar = (function (my) {
for(var k in buttonHandlers)
$("#" + k).click(buttonHandlers[k]);
UI = ui;
}
// Update login info
APP.xmpp.addListener(
AuthenticationEvents.IDENTITY_UPDATED,
function (authenticationEnabled, userIdentity) {
var loggedIn = false;
if (userIdentity) {
loggedIn = true;
}
//FIXME: XMPP authentication need improvements for "live" login
if (!APP.xmpp.isExternalAuthEnabled() && !loggedIn)
{
authenticationEnabled = false;
}
Toolbar.showAuthenticateButton(authenticationEnabled);
if (authenticationEnabled) {
Toolbar.setAuthenticatedIdentity(userIdentity);
Toolbar.showLoginButton(!loggedIn);
Toolbar.showLogoutButton(loggedIn);
}
}
);
},
/**
* Sets shared key
@@ -235,20 +296,28 @@ var Toolbar = (function (my) {
my.authenticateClicked = function () {
Authentication.focusAuthenticationWindow();
// Get authentication URL
xmpp.getAuthUrl(UI.getRoomName(), function (url) {
// Open popup with authentication URL
var authenticationWindow = Authentication.createAuthenticationWindow(function () {
// On popup closed - retry room allocation
xmpp.allocateConferenceFocus(UI.getRoomName(), UI.checkForNicknameAndJoin);
}, url);
if (!authenticationWindow) {
Toolbar.showAuthenticateButton(true);
messageHandler.openMessageDialog(
null, "Your browser is blocking popup windows from this site." +
" Please enable popups in your browser security settings" +
" and try again.");
}
});
if (!APP.xmpp.getMUCJoined()) {
APP.xmpp.getLoginUrl(UI.getRoomName(), function (url) {
// If conference has not been started yet - redirect to login page
window.location.href = url;
});
} else {
APP.xmpp.getPopupLoginUrl(UI.getRoomName(), function (url) {
// Otherwise - open popup with authentication URL
var authenticationWindow = Authentication.createAuthenticationWindow(
function () {
// On popup closed - retry room allocation
APP.xmpp.allocateConferenceFocus(
APP.UI.getRoomName(),
function () { console.info("AUTH DONE"); }
);
}, url);
if (!authenticationWindow) {
messageHandler.openMessageDialog(
null, "dialog.popupError");
}
});
}
};
/**
@@ -281,28 +350,20 @@ var Toolbar = (function (my) {
*/
my.openLockDialog = function () {
// Only the focus is able to set a shared key.
if (!xmpp.isModerator()) {
if (!APP.xmpp.isModerator()) {
if (sharedKey) {
messageHandler.openMessageDialog(null,
"This conversation is currently protected by" +
" a password. Only the owner of the conference" +
" could set a password.",
false,
"Password");
"dialog.passwordError");
} else {
messageHandler.openMessageDialog(null,
"This conversation isn't currently protected by" +
" a password. Only the owner of the conference" +
" could set a password.",
false,
"Password");
messageHandler.openMessageDialog(null, "dialog.passwordError2");
}
} else {
if (sharedKey) {
messageHandler.openTwoButtonDialog(null,
"Are you sure you would like to remove your password?",
messageHandler.openTwoButtonDialog(null, null,
"dialog.passwordCheck",
null,
false,
"Remove",
"dialog.Remove",
function (e, v) {
if (v) {
Toolbar.setSharedKey('');
@@ -310,12 +371,17 @@ var Toolbar = (function (my) {
}
});
} else {
messageHandler.openTwoButtonDialog(null,
'<h2>Set a password to lock your room</h2>' +
var msg = APP.translation.generateTranslatonHTML(
"dialog.passwordMsg");
var yourPassword = APP.translation.translateString(
"dialog.yourPassword");
messageHandler.openTwoButtonDialog(null, null, null,
'<h2>' + msg + '</h2>' +
'<input id="lockKey" type="text"' +
'placeholder="your password" autofocus>',
' data-i18n="[placeholder]dialog.yourPassword" ' +
'placeholder="' + yourPassword + '" autofocus>',
false,
"Save",
"dialog.Save",
function (e, v) {
if (v) {
var lockKey = document.getElementById('lockKey');
@@ -338,18 +404,20 @@ var Toolbar = (function (my) {
* Opens the invite link dialog.
*/
my.openLinkDialog = function () {
var inviteLink;
var inviteAttreibutes;
if (roomUrl === null) {
inviteLink = "Your conference is currently being created...";
inviteAttreibutes = 'data-i18n="[value]roomUrlDefaultMsg" value="' +
APP.translation.translateString("roomUrlDefaultMsg") + '"';
} else {
inviteLink = encodeURI(roomUrl);
inviteAttreibutes = "value=\"" + encodeURI(roomUrl) + "\"";
}
messageHandler.openTwoButtonDialog(
"Share this link with everyone you want to invite",
'<input id="inviteLinkRef" type="text" value="' +
inviteLink + '" onclick="this.select();" readonly>',
messageHandler.openTwoButtonDialog("dialog.shareLink",
null, null,
'<input id="inviteLinkRef" type="text" ' +
inviteAttreibutes + ' onclick="this.select();" readonly>',
false,
"Invite",
"dialog.Invite",
function (e, v) {
if (v) {
if (roomUrl) {
@@ -372,18 +440,28 @@ var Toolbar = (function (my) {
* Opens the settings dialog.
*/
my.openSettingsDialog = function () {
messageHandler.openTwoButtonDialog(
'<h2>Configure your conference</h2>' +
var settings1 = APP.translation.generateTranslatonHTML(
"dialog.settings1");
var settings2 = APP.translation.generateTranslatonHTML(
"dialog.settings2");
var settings3 = APP.translation.generateTranslatonHTML(
"dialog.settings3");
var yourPassword = APP.translation.translateString(
"dialog.yourPassword");
messageHandler.openTwoButtonDialog(null,
'<h2>' + settings1 + '</h2>' +
'<input type="checkbox" id="initMuted">' +
'Participants join muted<br/>' +
settings2 + '<br/>' +
'<input type="checkbox" id="requireNicknames">' +
'Require nicknames<br/><br/>' +
'Set a password to lock your room:' +
'<input id="lockKey" type="text" placeholder="your password"' +
'autofocus>',
settings3 +
'<input id="lockKey" type="text" placeholder="' + yourPassword +
'" data-i18n="[placeholder]dialog.yourPassword" autofocus>',
null,
null,
false,
"Save",
"dialog.Save",
function () {
document.getElementById('lockKey').focus();
},
@@ -488,13 +566,50 @@ var Toolbar = (function (my) {
// Shows or hides SIP calls button
my.showSipCallButton = function (show) {
if (xmpp.isSipGatewayEnabled() && show) {
$('#sipCallButton').css({display: "inline"});
if (APP.xmpp.isSipGatewayEnabled() && show) {
$('#sipCallButton').css({display: "inline-block"});
} else {
$('#sipCallButton').css({display: "none"});
}
};
/**
* Displays user authenticated identity name(login).
* @param authIdentity identity name to be displayed.
*/
my.setAuthenticatedIdentity = function (authIdentity) {
if (authIdentity) {
$('#toolbar_auth_identity').css({display: "list-item"});
$('#toolbar_auth_identity').text(authIdentity);
} else {
$('#toolbar_auth_identity').css({display: "none"});
}
};
/**
* Shows/hides login button.
* @param show <tt>true</tt> to show
*/
my.showLoginButton = function (show) {
if (show) {
$('#toolbar_button_login').css({display: "list-item"});
} else {
$('#toolbar_button_login').css({display: "none"});
}
};
/**
* Shows/hides logout button.
* @param show <tt>true</tt> to show
*/
my.showLogoutButton = function (show) {
if (show) {
$('#toolbar_button_logout').css({display: "list-item"});
} else {
$('#toolbar_button_logout').css({display: "none"});
}
};
/**
* Sets the state of the button. The button has blue glow if desktop
* streaming is active.

View File

@@ -4,7 +4,7 @@ var toolbarTimeoutObject,
toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
function showDesktopSharingButton() {
if (desktopsharing.isDesktopSharingEnabled()) {
if (APP.desktopsharing.isDesktopSharingEnabled()) {
$('#desktopsharing').css({display: "inline"});
} else {
$('#desktopsharing').css({display: "none"});
@@ -67,7 +67,7 @@ var ToolbarToggler = {
toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
}
if (xmpp.isModerator())
if (APP.xmpp.isModerator())
{
// TODO: Enable settings functionality.
// Need to uncomment the settings button in index.html.

View File

@@ -7,10 +7,16 @@ var messageHandler = (function(my) {
* @param titleString the title of the message
* @param messageString the text of the message
*/
my.openMessageDialog = function(titleString, messageString) {
$.prompt(messageString,
my.openMessageDialog = function(titleKey, messageKey) {
var title = null;
if(titleKey)
{
title = APP.translation.generateTranslatonHTML(titleKey);
}
var message = APP.translation.generateTranslatonHTML(messageKey);
$.prompt(message,
{
title: titleString,
title: title,
persistent: false
}
);
@@ -27,13 +33,25 @@ var messageHandler = (function(my) {
* @param loadedFunction function to be called after the prompt is fully loaded
* @param closeFunction function to be called after the prompt is closed
*/
my.openTwoButtonDialog = function(titleString, msgString, persistent, leftButton,
submitFunction, loadedFunction, closeFunction) {
my.openTwoButtonDialog = function(titleKey, titleString, msgKey, msgString,
persistent, leftButtonKey, submitFunction, loadedFunction,
closeFunction)
{
var leftButton = APP.translation.generateTranslatonHTML(leftButtonKey);
var buttons = {};
buttons[leftButton] = true;
buttons.Cancel = false;
$.prompt(msgString, {
title: titleString,
buttons.button1 = {title: leftButton, value: true};
var cancelButton = APP.translation.generateTranslatonHTML("dialog.Cancel");
buttons.button2 = {title: cancelButton, value: false};
var message = msgString, title = titleString;
if(titleKey)
{
title = APP.translation.generateTranslatonHTML(titleKey);
}
if(msgKey) {
message = APP.translation.generateTranslatonHTML(msgKey);
}
$.prompt(message, {
title: title,
persistent: false,
buttons: buttons,
defaultButton: 1,
@@ -54,7 +72,7 @@ var messageHandler = (function(my) {
* @param submitFunction function to be called on submit
* @param loadedFunction function to be called after the prompt is fully loaded
*/
my.openDialog = function (titleString, msgString, persistent, buttons,
my.openDialog = function (titleString, msgString, persistent, buttons,
submitFunction, loadedFunction) {
var args = {
title: titleString,
@@ -130,8 +148,8 @@ var messageHandler = (function(my) {
* @param msgString the text of the message
* @param error the error that is being reported
*/
my.openReportDialog = function(titleString, msgString, error) {
my.openMessageDialog(titleString, msgString);
my.openReportDialog = function(titleKey, msgKey, error) {
my.openMessageDialog(titleKey, msgKey);
console.log(error);
//FIXME send the error to the server
};
@@ -141,21 +159,39 @@ var messageHandler = (function(my) {
* @param title the title of the message
* @param message the text of the messafe
*/
my.showError = function(title, message) {
if(!(title || message)) {
title = title || "Oops!";
message = message || "There was some kind of error";
my.showError = function(titleKey, msgKey) {
if(!titleKey) {
titleKey = "dialog.oops";
}
messageHandler.openMessageDialog(title, message);
if(!msgKey)
{
msgKey = "dialog.defaultError";
}
messageHandler.openMessageDialog(titleKey, msgKey);
};
my.notify = function(displayName, cls, message) {
my.notify = function(displayName, displayNameKey,
cls, messageKey, messageArguments) {
var displayNameSpan = '<span class="nickname" ';
if(displayName)
{
displayNameSpan += ">" + displayName;
}
else
{
displayNameSpan += "data-i18n='" + displayNameKey +
"'>" + APP.translation.translateString(displayNameKey);
}
displayNameSpan += "</span>";
toastr.info(
'<span class="nickname">' +
displayName +
'</span><br>' +
'<span class=' + cls + '>' +
message +
displayNameSpan + '<br>' +
'<span class=' + cls + ' data-i18n="' + messageKey + '"' +
(messageArguments?
" data-i18n-options='" + JSON.stringify(messageArguments) + "'"
: "") + ">" +
APP.translation.translateString(messageKey,
messageArguments) +
'</span>');
};

View File

@@ -1,3 +1,5 @@
var UIEvents = require("../../../service/UI/UIEvents");
var nickname = null;
var eventEmitter = null;

View File

@@ -69,8 +69,8 @@ module.exports = {
context.putImageData(imgData, 0, 0);
},
setTooltip: function (element, tooltipText, position) {
element.setAttribute("data-content", tooltipText);
setTooltip: function (element, key, position) {
element.setAttribute("data-i18n", "[data-content]" + key);
element.setAttribute("data-toggle", "popover");
element.setAttribute("data-placement", position);
element.setAttribute("data-html", true);

View File

@@ -64,6 +64,8 @@ ConnectionIndicator.getStringFromArray = function (array) {
ConnectionIndicator.prototype.generateText = function () {
var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
var translate = APP.translation.translateString;
if(this.bitrate === null)
{
downloadBitrate = "N/A";
@@ -103,7 +105,7 @@ ConnectionIndicator.prototype.generateText = function () {
}
else if(keys.length > 1)
{
var displayedSsrc = simulcast.getReceivingSSRC(this.jid);
var displayedSsrc = APP.simulcast.getReceivingSSRC(this.jid);
resolutionValue = this.resolution[displayedSsrc];
}
}
@@ -145,22 +147,28 @@ ConnectionIndicator.prototype.generateText = function () {
var result = "<table style='width:100%'>" +
"<tr>" +
"<td><span class='jitsipopover_blue'>Bitrate:</span></td>" +
"<td><span class='jitsipopover_blue' data-i18n='connectionindicator.bitrate'>" +
translate("connectionindicator.bitrate") + "</span></td>" +
"<td><span class='jitsipopover_green'>&darr;</span>" +
downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
uploadBitrate + "</td>" +
"</tr><tr>" +
"<td><span class='jitsipopover_blue'>Packet loss: </span></td>" +
"<td><span class='jitsipopover_blue' data-i18n='connectionindicator.packetloss'>" +
translate("connectionindicator.packetloss") + "</span></td>" +
"<td>" + packetLoss + "</td>" +
"</tr><tr>" +
"<td><span class='jitsipopover_blue'>Resolution:</span></td>" +
"<td><span class='jitsipopover_blue' data-i18n='connectionindicator.resolution'>" +
translate("connectionindicator.resolution") + "</span></td>" +
"<td>" + resolution + "</td></tr></table>";
if(this.videoContainer.id == "localVideoContainer")
if(this.videoContainer.id == "localVideoContainer") {
result += "<div class=\"jitsipopover_showmore\" " +
"onclick = \"UI.connectionIndicatorShowMore('" +
this.videoContainer.id + "')\">" +
(this.showMoreValue? "Show less" : "Show More") + "</div><br />";
"onclick = \"APP.UI.connectionIndicatorShowMore('" +
this.videoContainer.id + "')\" data-i18n='connectionindicator." +
(this.showMoreValue ? "less" : "more") + "'>" +
translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
"</div><br />";
}
if(this.showMoreValue)
{
@@ -183,7 +191,9 @@ ConnectionIndicator.prototype.generateText = function () {
if(!this.transport || this.transport.length === 0)
{
transport = "<tr>" +
"<td><span class='jitsipopover_blue'>Address:</span></td>" +
"<td><span class='jitsipopover_blue' " +
"data-i18n='connectionindicator.address'>" +
translate("connectionindicator.address") + "</span></td>" +
"<td> N/A</td></tr>";
}
else
@@ -218,40 +228,44 @@ ConnectionIndicator.prototype.generateText = function () {
}
}
var local_address_key = "connectionindicator.localaddress";
var remote_address_key = "connectionindicator.remoteaddress";
var localTransport =
"<tr><td><span class='jitsipopover_blue'>Local address" +
(data.localIP.length > 1? "es" : "") + ": </span></td><td> " +
"<tr><td><span class='jitsipopover_blue' data-i18n='" +
local_address_key +"' data-i18n-options='" +
JSON.stringify({count: data.localIP.length}) + "'>" +
translate(local_address_key, {count: data.localIP.length}) +
"</span></td><td> " +
ConnectionIndicator.getStringFromArray(data.localIP) +
"</td></tr>";
transport =
"<tr><td><span class='jitsipopover_blue'>Remote address"+
(data.remoteIP.length > 1? "es" : "") + ":</span></td><td> " +
"<tr><td><span class='jitsipopover_blue' data-i18n='" +
remote_address_key + "' data-i18n-options='" +
JSON.stringify({count: data.remoteIP.length}) + "'>" +
translate(remote_address_key,
{count: data.remoteIP.length}) +
"</span></td><td> " +
ConnectionIndicator.getStringFromArray(data.remoteIP) +
"</td></tr>";
if(this.transport.length > 1)
{
transport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Remote ports:</span>" +
"</td><td>";
localTransport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Local ports:</span>" +
"</td><td>";
}
else
{
transport +=
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Remote port:</span>" +
"</td><td>";
localTransport +=
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Local port:</span>" +
"</td><td>";
}
var key_remote = "connectionindicator.remoteport",
key_local = "connectionindicator.localport";
transport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue' data-i18n='" + key_remote +
"' data-i18n-options='" +
JSON.stringify({count: this.transport.length}) + "'>" +
translate(key_remote, {count: this.transport.length}) +
"</span></td><td>";
localTransport += "<tr>" +
"<td>" +
"<span class='jitsipopover_blue' data-i18n='" + key_local +
"' data-i18n-options='" +
JSON.stringify({count: this.transport.length}) + "'>" +
translate(key_local, {count: this.transport.length}) +
"</span></td><td>";
transport +=
ConnectionIndicator.getStringFromArray(data.remotePort);
@@ -260,7 +274,8 @@ ConnectionIndicator.prototype.generateText = function () {
transport += "</td></tr>";
transport += localTransport + "</td></tr>";
transport +="<tr>" +
"<td><span class='jitsipopover_blue'>Transport:</span></td>" +
"<td><span class='jitsipopover_blue' data-i18n='connectionindicator.transport'>" +
translate("connectionindicator.transport") + "</span></td>" +
"<td>" + this.transport[0].type + "</td></tr>";
}
@@ -268,7 +283,8 @@ ConnectionIndicator.prototype.generateText = function () {
result += "<table style='width:100%'>" +
"<tr>" +
"<td>" +
"<span class='jitsipopover_blue'>Estimated bandwidth:</span>" +
"<span class='jitsipopover_blue' data-i18n='connectionindicator.bandwidth'>" +
translate("connectionindicator.bandwidth") + "</span>" +
"</td><td>" +
"<span class='jitsipopover_green'>&darr;</span>" +
downloadBandwidth +
@@ -313,8 +329,8 @@ ConnectionIndicator.prototype.create = function () {
this.videoContainer.appendChild(this.connectionIndicatorContainer);
this.popover = new JitsiPopover(
$("#" + this.videoContainer.id + " > .connectionindicator"),
{content: "<div class=\"connection_info\">Come back here for " +
"connection information once the conference starts</div>",
{content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
APP.translation.translateString("connectionindicator.na") + "</div>",
skin: "black"});
this.emptyIcon = this.connectionIndicatorContainer.appendChild(
@@ -388,7 +404,8 @@ ConnectionIndicator.prototype.updateResolution = function (resolution) {
*/
ConnectionIndicator.prototype.updatePopoverData = function () {
this.popover.updateContent(
"<div class=\"connection_info\">" + this.generateText() + "</div>");
"<div class=\"connection_info\">" + this.generateText() + "</div>");
APP.translation.translateElement($(".connection_info"));
};
/**

View File

@@ -5,6 +5,8 @@ var ContactList = require("../side_pannels/contactlist/ContactList");
var UIUtil = require("../util/UIUtil");
var ConnectionIndicator = require("./ConnectionIndicator");
var NicknameHandler = require("../util/NicknameHandler");
var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
var UIEvents = require("../../../service/UI/UIEvents");
var currentDominantSpeaker = null;
var lastNCount = config.channelLastN;
@@ -16,6 +18,9 @@ var largeVideoState = {
updateInProgress: false,
newSrc: ''
};
var eventEmitter = null;
/**
* Currently focused video "src"(displayed in large video).
* @type {String}
@@ -36,8 +41,6 @@ var currentVideoHeight = null;
var localVideoSrc = null;
var defaultLocalDisplayName = "Me";
function videoactive( videoelem) {
if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
// ignore mixedmslabela0 and v0
@@ -60,7 +63,7 @@ function videoactive( videoelem) {
(parentResourceJid &&
VideoLayout.getDominantSpeakerResourceJid() === parentResourceJid)) {
VideoLayout.updateLargeVideo(
RTC.getVideoSrc(videoelem[0]),
APP.RTC.getVideoSrc(videoelem[0]),
1,
parentResourceJid);
}
@@ -96,8 +99,8 @@ function waitForRemoteVideo(selector, ssrc, stream, jid) {
if (stream.id === 'mixedmslabel') return;
if (selector[0].currentTime > 0) {
var videoStream = simulcast.getReceivingVideoStream(stream);
RTC.attachMediaStream(selector, videoStream); // FIXME: why do i have to do this for FF?
var videoStream = APP.simulcast.getReceivingVideoStream(stream);
APP.RTC.attachMediaStream(selector, videoStream); // FIXME: why do i have to do this for FF?
videoactive(selector);
} else {
setTimeout(function () {
@@ -188,9 +191,10 @@ function getCameraVideoSize(videoWidth,
/**
* Sets the display name for the given video span id.
*/
function setDisplayName(videoSpanId, displayName) {
function setDisplayName(videoSpanId, displayName, key) {
var nameSpan = $('#' + videoSpanId + '>span.displayname');
var defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
var defaultLocalDisplayName = APP.translation.generateTranslatonHTML(
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
// If we already have a display name for this video.
if (nameSpan.length > 0) {
@@ -199,14 +203,25 @@ function setDisplayName(videoSpanId, displayName) {
if (nameSpanElement.id === 'localDisplayName' &&
$('#localDisplayName').text() !== displayName) {
if (displayName && displayName.length > 0)
$('#localDisplayName').html(displayName + ' (me)');
{
var meHTML = APP.translation.generateTranslatonHTML("me");
$('#localDisplayName').html(displayName + ' (' + meHTML + ')');
}
else
$('#localDisplayName').text(defaultLocalDisplayName);
$('#localDisplayName').html(defaultLocalDisplayName);
} else {
if (displayName && displayName.length > 0)
{
$('#' + videoSpanId + '_name').html(displayName);
}
else if (key && key.length > 0)
{
var nameHtml = APP.translation.generateTranslatonHTML(key);
$('#' + videoSpanId + '_name').html(nameHtml);
}
else
$('#' + videoSpanId + '_name').text(interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
$('#' + videoSpanId + '_name').text(
interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
}
} else {
var editButton = null;
@@ -217,21 +232,30 @@ function setDisplayName(videoSpanId, displayName) {
if (videoSpanId === 'localVideoContainer') {
editButton = createEditDisplayNameButton();
nameSpan.innerText = defaultLocalDisplayName;
if (displayName && displayName.length > 0) {
var meHTML = APP.translation.generateTranslatonHTML("me");
nameSpan.innerHTML = displayName + meHTML;
}
else
nameSpan.innerHTML = defaultLocalDisplayName;
}
else {
nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
if (displayName && displayName.length > 0) {
nameSpan.innerText = displayName;
}
else
nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
}
if (displayName && displayName.length > 0) {
nameSpan.innerText = displayName;
}
if (!editButton) {
nameSpan.id = videoSpanId + '_name';
} else {
nameSpan.id = 'localDisplayName';
$('#' + videoSpanId)[0].appendChild(editButton);
//translates popover of edit button
APP.translation.translateElement($("a.displayname"));
var editableText = document.createElement('input');
editableText.className = 'displayname';
@@ -240,11 +264,18 @@ function setDisplayName(videoSpanId, displayName) {
if (displayName && displayName.length) {
editableText.value
= displayName.substring(0, displayName.indexOf(' (me)'));
= displayName;
}
var defaultNickname = APP.translation.translateString(
"defaultNickname", {name: "Jane Pink"});
editableText.setAttribute('style', 'display:none;');
editableText.setAttribute('placeholder', 'ex. Jane Pink');
editableText.setAttribute('data-18n',
'[placeholder]defaultNickname');
editableText.setAttribute("data-i18n-options",
JSON.stringify({name: "Jane Pink"}));
editableText.setAttribute("placeholder", defaultNickname);
$('#' + videoSpanId)[0].appendChild(editableText);
$('#localVideoContainer .displayname')
@@ -282,7 +313,7 @@ function getParticipantContainer(resourceJid)
if (!resourceJid)
return null;
if (resourceJid === xmpp.myResource())
if (resourceJid === APP.xmpp.myResource())
return $("#localVideoContainer");
else
return $("#participant_" + resourceJid);
@@ -342,14 +373,16 @@ function addRemoteVideoMenu(jid, parentElement) {
var muteMenuItem = document.createElement('li');
var muteLinkItem = document.createElement('a');
var mutedIndicator = "<i class='icon-mic-disabled'></i>";
var mutedIndicator = "<i style='float:left;' class='icon-mic-disabled'></i>";
if (!mutedAudios[jid]) {
muteLinkItem.innerHTML = mutedIndicator + 'Mute';
muteLinkItem.innerHTML = mutedIndicator +
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
muteLinkItem.className = 'mutelink';
}
else {
muteLinkItem.innerHTML = mutedIndicator + ' Muted';
muteLinkItem.innerHTML = mutedIndicator +
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
muteLinkItem.className = 'mutelink disabled';
}
@@ -358,16 +391,18 @@ function addRemoteVideoMenu(jid, parentElement) {
event.preventDefault();
}
var isMute = mutedAudios[jid] == true;
xmpp.setMute(jid, !isMute);
APP.xmpp.setMute(jid, !isMute);
popupmenuElement.setAttribute('style', 'display:none;');
if (isMute) {
this.innerHTML = mutedIndicator + ' Muted';
this.innerHTML = mutedIndicator +
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
this.className = 'mutelink disabled';
}
else {
this.innerHTML = mutedIndicator + ' Mute';
this.innerHTML = mutedIndicator +
" <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
this.className = 'mutelink';
}
};
@@ -375,13 +410,14 @@ function addRemoteVideoMenu(jid, parentElement) {
muteMenuItem.appendChild(muteLinkItem);
popupmenuElement.appendChild(muteMenuItem);
var ejectIndicator = "<i class='fa fa-eject'></i>";
var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
var ejectMenuItem = document.createElement('li');
var ejectLinkItem = document.createElement('a');
ejectLinkItem.innerHTML = ejectIndicator + ' Kick out';
var ejectText = "<div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.kick'>&nbsp;</div>";
ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
ejectLinkItem.onclick = function(){
xmpp.eject(jid);
APP.xmpp.eject(jid);
popupmenuElement.setAttribute('style', 'display:none;');
};
@@ -391,6 +427,7 @@ function addRemoteVideoMenu(jid, parentElement) {
var paddingSpan = document.createElement('span');
paddingSpan.className = 'popupmenuPadding';
popupmenuElement.appendChild(paddingSpan);
APP.translation.translateElement($("#" + popupmenuElement.id + " > li > a > div"));
}
/**
@@ -465,7 +502,7 @@ function createEditDisplayNameButton() {
var editButton = document.createElement('a');
editButton.className = 'displayname';
UIUtil.setTooltip(editButton,
'Click to edit your<br/>display name',
"videothumbnail.editnickname",
"top");
editButton.innerHTML = '<i class="fa fa-pencil"></i>';
@@ -484,7 +521,7 @@ function createModeratorIndicatorElement(parentElement) {
parentElement.appendChild(moderatorIndicator);
UIUtil.setTooltip(parentElement,
"The owner of<br/>this conference",
"videothumbnail.moderator",
"top");
}
@@ -496,7 +533,7 @@ var VideoLayout = (function (my) {
my.getVideoSize = getCameraVideoSize;
my.getVideoPosition = getCameraVideoPosition;
my.init = function () {
my.init = function (emitter) {
// Listen for large video size updates
document.getElementById('largeVideo')
.addEventListener('loadedmetadata', function (e) {
@@ -504,6 +541,7 @@ var VideoLayout = (function (my) {
currentVideoHeight = this.videoHeight;
VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
});
eventEmitter = emitter;
};
my.isInLastN = function(resource) {
@@ -517,11 +555,11 @@ var VideoLayout = (function (my) {
};
my.changeLocalAudio = function(stream) {
RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
document.getElementById('localAudio').autoplay = true;
document.getElementById('localAudio').volume = 0;
if (preMuted) {
if(!UI.setAudioMuted(true))
if(!APP.UI.setAudioMuted(true))
{
preMuted = mute;
}
@@ -535,7 +573,7 @@ var VideoLayout = (function (my) {
flipX = false;
var localVideo = document.createElement('video');
localVideo.id = 'localVideo_' +
RTC.getStreamID(stream.getOriginalStream());
APP.RTC.getStreamID(stream.getOriginalStream());
localVideo.autoplay = true;
localVideo.volume = 0; // is it required if audio is separated ?
localVideo.oncontextmenu = function () { return false; };
@@ -554,22 +592,18 @@ var VideoLayout = (function (my) {
AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
var localVideoSelector = $('#' + localVideo.id);
function localVideoClick(event) {
event.stopPropagation();
VideoLayout.handleVideoThumbClicked(
APP.RTC.getVideoSrc(localVideo),
false,
APP.xmpp.myResource());
}
// Add click handler to both video and video wrapper elements in case
// there's no video.
localVideoSelector.click(function (event) {
event.stopPropagation();
VideoLayout.handleVideoThumbClicked(
RTC.getVideoSrc(localVideo),
false,
xmpp.myResource());
});
$('#localVideoContainer').click(function (event) {
event.stopPropagation();
VideoLayout.handleVideoThumbClicked(
RTC.getVideoSrc(localVideo),
false,
xmpp.myResource());
});
localVideoSelector.click(localVideoClick);
$('#localVideoContainer').click(localVideoClick);
// Add hover handler
$('#localVideoContainer').hover(
@@ -578,14 +612,14 @@ var VideoLayout = (function (my) {
},
function() {
if (!VideoLayout.isLargeVideoVisible()
|| RTC.getVideoSrc(localVideo) !== RTC.getVideoSrc($('#largeVideo')[0]))
|| APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName('localVideoContainer', false);
}
);
// Add stream ended handler
stream.getOriginalStream().onended = function () {
localVideoContainer.removeChild(localVideo);
VideoLayout.updateRemovedVideo(RTC.getVideoSrc(localVideo));
VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
};
// Flip video x axis if needed
flipXLocalVideo = flipX;
@@ -593,12 +627,12 @@ var VideoLayout = (function (my) {
localVideoSelector.addClass("flipVideoX");
}
// Attach WebRTC stream
var videoStream = simulcast.getLocalVideoStream();
RTC.attachMediaStream(localVideoSelector, videoStream);
var videoStream = APP.simulcast.getLocalVideoStream();
APP.RTC.attachMediaStream(localVideoSelector, videoStream);
localVideoSrc = RTC.getVideoSrc(localVideo);
localVideoSrc = APP.RTC.getVideoSrc(localVideo);
var myResourceJid = xmpp.myResource();
var myResourceJid = APP.xmpp.myResource();
VideoLayout.updateLargeVideo(localVideoSrc, 0,
myResourceJid);
@@ -611,7 +645,7 @@ var VideoLayout = (function (my) {
* @param removedVideoSrc src stream identifier of the video.
*/
my.updateRemovedVideo = function(removedVideoSrc) {
if (removedVideoSrc === RTC.getVideoSrc($('#largeVideo')[0])) {
if (removedVideoSrc === APP.RTC.getVideoSrc($('#largeVideo')[0])) {
// this is currently displayed as large
// pick the last visible video in the row
// if nobody else is left, this picks the local video
@@ -623,7 +657,7 @@ var VideoLayout = (function (my) {
console.info("Last visible video no longer exists");
pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
if (!pick || !RTC.getVideoSrc(pick)) {
if (!pick || !APP.RTC.getVideoSrc(pick)) {
// Try local video
console.info("Fallback to local video...");
pick = $('#remoteVideos>span>span>video').get(0);
@@ -638,7 +672,7 @@ var VideoLayout = (function (my) {
{
if(container.id == "localVideoWrapper")
{
jid = xmpp.myResource();
jid = APP.xmpp.myResource();
}
else
{
@@ -646,7 +680,7 @@ var VideoLayout = (function (my) {
}
}
VideoLayout.updateLargeVideo(RTC.getVideoSrc(pick), pick.volume, jid);
VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(pick), pick.volume, jid);
} else {
console.warn("Failed to elect large video");
}
@@ -701,7 +735,7 @@ var VideoLayout = (function (my) {
my.updateLargeVideo = function(newSrc, vol, resourceJid) {
console.log('hover in', newSrc);
if (RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
$('#activeSpeaker').css('visibility', 'hidden');
// Due to the simulcast the localVideoSrc may have changed when the
@@ -714,7 +748,7 @@ var VideoLayout = (function (my) {
largeVideoState.newSrc = newSrc;
largeVideoState.isVisible = $('#largeVideo').is(':visible');
largeVideoState.isDesktop = RTC.isVideoSrcDesktop(resourceJid);
largeVideoState.isDesktop = APP.RTC.isVideoSrcDesktop(resourceJid);
if(largeVideoState.userResourceJid) {
largeVideoState.oldResourceJid = largeVideoState.userResourceJid;
} else {
@@ -730,7 +764,8 @@ var VideoLayout = (function (my) {
userChanged = true;
// we want the notification to trigger even if userJid is undefined,
// or null.
$(document).trigger("selectedendpointchanged", [largeVideoState.userResourceJid]);
eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
largeVideoState.userResourceJid);
}
if (!largeVideoState.updateInProgress) {
@@ -739,12 +774,12 @@ var VideoLayout = (function (my) {
var doUpdate = function () {
Avatar.updateActiveSpeakerAvatarSrc(
xmpp.findJidFromResource(
APP.xmpp.findJidFromResource(
largeVideoState.userResourceJid));
if (!userChanged && largeVideoState.preload &&
largeVideoState.preload !== null &&
RTC.getVideoSrc($(largeVideoState.preload)[0]) === newSrc)
APP.RTC.getVideoSrc($(largeVideoState.preload)[0]) === newSrc)
{
console.info('Switching to preloaded video');
@@ -771,7 +806,7 @@ var VideoLayout = (function (my) {
largeVideoState.preload = null;
largeVideoState.preload_ssrc = 0;
} else {
RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
APP.RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
}
var videoTransform = document.getElementById('largeVideo')
@@ -819,7 +854,7 @@ var VideoLayout = (function (my) {
if(userChanged) {
Avatar.showUserAvatar(
xmpp.findJidFromResource(
APP.xmpp.findJidFromResource(
largeVideoState.oldResourceJid));
}
@@ -834,7 +869,7 @@ var VideoLayout = (function (my) {
}
} else {
Avatar.showUserAvatar(
xmpp.findJidFromResource(
APP.xmpp.findJidFromResource(
largeVideoState.userResourceJid));
}
@@ -867,14 +902,14 @@ var VideoLayout = (function (my) {
if (dominantSpeakerVideo) {
VideoLayout.updateLargeVideo(
RTC.getVideoSrc(dominantSpeakerVideo),
APP.RTC.getVideoSrc(dominantSpeakerVideo),
1,
currentDominantSpeaker);
}
}
if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged");
eventEmitter.emit(UIEvents.PINNED_ENDPOINT);
}
return;
}
@@ -892,7 +927,7 @@ var VideoLayout = (function (my) {
container.addClass("videoContainerFocused");
if (!noPinnedEndpointChangedEvent) {
$(document).trigger("pinnedendpointchanged", [resourceJid]);
eventEmitter.emit(UIEvents.PINNED_ENDPOINT, resourceJid);
}
}
@@ -973,7 +1008,7 @@ var VideoLayout = (function (my) {
focusedVideoInfo = null;
if(focusResourceJid) {
Avatar.showUserAvatar(
xmpp.findJidFromResource(focusResourceJid));
APP.xmpp.findJidFromResource(focusResourceJid));
}
}
}
@@ -1042,13 +1077,11 @@ var VideoLayout = (function (my) {
container.id = spanId;
container.className = 'videocontainer';
var remotes = document.getElementById('remoteVideos');
remotes.appendChild(container);
// If the peerJid is null then this video span couldn't be directly
// associated with a participant (this could happen in the case of prezi).
if (xmpp.isModerator() && peerJid !== null)
if (APP.xmpp.isModerator() && peerJid !== null)
addRemoteVideoMenu(peerJid, container);
remotes.appendChild(container);
AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
return container;
@@ -1064,7 +1097,7 @@ var VideoLayout = (function (my) {
? document.createElement('video')
: document.createElement('audio');
var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
+ sid + '_' + RTC.getStreamID(stream);
+ sid + '_' + APP.RTC.getStreamID(stream);
element.id = id;
element.autoplay = true;
@@ -1091,8 +1124,8 @@ var VideoLayout = (function (my) {
// If the container is currently visible we attach the stream.
if (!isVideo
|| (container.offsetParent !== null && isVideo)) {
var videoStream = simulcast.getReceivingVideoStream(stream);
RTC.attachMediaStream(sel, videoStream);
var videoStream = APP.simulcast.getReceivingVideoStream(stream);
APP.RTC.attachMediaStream(sel, videoStream);
if (isVideo)
waitForRemoteVideo(sel, thessrc, stream, peerJid);
@@ -1130,7 +1163,7 @@ var VideoLayout = (function (my) {
var videoThumb = $('#' + container.id + '>video').get(0);
if (videoThumb) {
VideoLayout.handleVideoThumbClicked(
RTC.getVideoSrc(videoThumb),
APP.RTC.getVideoSrc(videoThumb),
false,
Strophe.getResourceFromJid(peerJid));
}
@@ -1149,13 +1182,13 @@ var VideoLayout = (function (my) {
var videoSrc = null;
if ($('#' + container.id + '>video')
&& $('#' + container.id + '>video').length > 0) {
videoSrc = RTC.getVideoSrc($('#' + container.id + '>video').get(0));
videoSrc = APP.RTC.getVideoSrc($('#' + container.id + '>video').get(0));
}
// If the video has been "pinned" by the user we want to
// keep the display name on place.
if (!VideoLayout.isLargeVideoVisible()
|| videoSrc !== RTC.getVideoSrc($('#largeVideo')[0]))
|| videoSrc !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
VideoLayout.showDisplayName(container.id, false);
}
);
@@ -1180,7 +1213,7 @@ var VideoLayout = (function (my) {
var removedVideoSrc = null;
if (isVideo) {
select = $('#' + container.id + '>video');
removedVideoSrc = RTC.getVideoSrc(select.get(0));
removedVideoSrc = APP.RTC.getVideoSrc(select.get(0));
}
else
select = $('#' + container.id + '>audio');
@@ -1227,16 +1260,16 @@ var VideoLayout = (function (my) {
peerContainer.show();
}
var jid = APP.xmpp.findJidFromResource(resourceJid);
if (state == 'show')
{
// peerContainer.css('-webkit-filter', '');
var jid = xmpp.findJidFromResource(resourceJid);
Avatar.showUserAvatar(jid, false);
}
else // if (state == 'avatar')
{
// peerContainer.css('-webkit-filter', 'grayscale(100%)');
var jid = xmpp.findJidFromResource(resourceJid);
Avatar.showUserAvatar(jid, true);
}
}
@@ -1263,10 +1296,17 @@ var VideoLayout = (function (my) {
if (!$('#localDisplayName').is(":visible")) {
if (NicknameHandler.getNickname())
$('#localDisplayName').text(NicknameHandler.getNickname() + " (me)");
{
var meHTML = APP.translation.generateTranslatonHTML("me");
$('#localDisplayName').html(NicknameHandler.getNickname() + " (" + meHTML + ")");
}
else
{
var defaultHTML = APP.translation.generateTranslatonHTML(
interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
$('#localDisplayName')
.text(interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
.html(defaultHTML);
}
$('#localDisplayName').show();
}
@@ -1327,17 +1367,19 @@ var VideoLayout = (function (my) {
*/
my.showModeratorIndicator = function () {
var isModerator = xmpp.isModerator();
var isModerator = APP.xmpp.isModerator();
if (isModerator) {
var indicatorSpan = $('#localVideoContainer .focusindicator');
if (indicatorSpan.children().length === 0)
{
createModeratorIndicatorElement(indicatorSpan[0]);
//translates text in focus indicator
APP.translation.translateElement($('#localVideoContainer .focusindicator'));
}
}
var members = xmpp.getMembers();
var members = APP.xmpp.getMembers();
Object.keys(members).forEach(function (jid) {
@@ -1374,6 +1416,8 @@ var VideoLayout = (function (my) {
videoContainer.appendChild(indicatorSpan);
createModeratorIndicatorElement(indicatorSpan);
//translates text in focus indicators
APP.translation.translateElement($('#' + videoSpanId + ' .focusindicator'));
}
} else if (isModerator) {
// We are moderator, but user is not - add menu
@@ -1407,9 +1451,11 @@ var VideoLayout = (function (my) {
var mutedIndicator = document.createElement('i');
mutedIndicator.className = 'icon-camera-disabled';
UIUtil.setTooltip(mutedIndicator,
"Participant has<br/>stopped the camera.",
"videothumbnail.videomute",
"top");
videoMutedSpan.appendChild(mutedIndicator);
//translate texts for muted indicator
APP.translation.translateElement($('#' + videoSpanId + " > span > i"));
}
VideoLayout.updateMutePosition(videoSpanId);
@@ -1450,10 +1496,11 @@ var VideoLayout = (function (my) {
audioMutedSpan = document.createElement('span');
audioMutedSpan.className = 'audioMuted';
UIUtil.setTooltip(audioMutedSpan,
"Participant is muted",
"videothumbnail.mute",
"top");
$('#' + videoSpanId)[0].appendChild(audioMutedSpan);
APP.translation.translateElement($('#' + videoSpanId + " > span"));
var mutedIndicator = document.createElement('i');
mutedIndicator.className = 'icon-mic-disabled';
audioMutedSpan.appendChild(mutedIndicator);
@@ -1511,6 +1558,8 @@ var VideoLayout = (function (my) {
$('.userAvatar').css('left', (width - height) / 2);
$(document).trigger("remotevideo.resized", [width, height]);
};
@@ -1527,7 +1576,7 @@ var VideoLayout = (function (my) {
var videoSpanId = null;
var videoContainerId = null;
if (resourceJid
=== xmpp.myResource()) {
=== APP.xmpp.myResource()) {
videoSpanId = 'localVideoWrapper';
videoContainerId = 'localVideoContainer';
}
@@ -1570,7 +1619,7 @@ var VideoLayout = (function (my) {
}
Avatar.showUserAvatar(
xmpp.findJidFromResource(resourceJid));
APP.xmpp.findJidFromResource(resourceJid));
}
};
@@ -1693,9 +1742,10 @@ var VideoLayout = (function (my) {
// picked up later by the lastN changed event handler.
lastNPickupJid = jid;
$(document).trigger("pinnedendpointchanged", [Strophe.getResourceFromJid(jid)]);
eventEmitter.emit(UIEvents.PINNED_ENDPOINT,
Strophe.getResourceFromJid(jid));
}
} else if (jid == xmpp.myJid()) {
} else if (jid == APP.xmpp.myJid()) {
$("#localVideoContainer").click();
}
}
@@ -1713,7 +1763,7 @@ var VideoLayout = (function (my) {
return;
}*/
var videoSpanId = null;
if (jid === xmpp.myJid()) {
if (jid === APP.xmpp.myJid()) {
videoSpanId = 'localVideoContainer';
} else {
VideoLayout.ensurePeerContainerExists(jid);
@@ -1722,7 +1772,7 @@ var VideoLayout = (function (my) {
mutedAudios[jid] = isMuted;
if (xmpp.isModerator()) {
if (APP.xmpp.isModerator()) {
VideoLayout.updateRemoteVideoMenu(jid, isMuted);
}
@@ -1735,12 +1785,12 @@ var VideoLayout = (function (my) {
*/
$(document).bind('videomuted.muc', function (event, jid, value) {
var isMuted = (value === "true");
if(!RTC.muteRemoteVideoStream(jid, isMuted))
if(!APP.RTC.muteRemoteVideoStream(jid, isMuted))
return;
Avatar.showUserAvatar(jid, isMuted);
var videoSpanId = null;
if (jid === xmpp.myJid()) {
if (jid === APP.xmpp.myJid()) {
videoSpanId = 'localVideoContainer';
} else {
VideoLayout.ensurePeerContainerExists(jid);
@@ -1757,7 +1807,7 @@ var VideoLayout = (function (my) {
my.onDisplayNameChanged =
function (jid, displayName, status) {
if (jid === 'localVideoContainer'
|| jid === xmpp.myJid()) {
|| jid === APP.xmpp.myJid()) {
setDisplayName('localVideoContainer',
displayName);
} else {
@@ -1773,23 +1823,26 @@ var VideoLayout = (function (my) {
/**
* On dominant speaker changed event.
*/
$(document).bind('dominantspeakerchanged', function (event, resourceJid) {
my.onDominantSpeakerChanged = function (resourceJid) {
// We ignore local user events.
if (resourceJid
=== xmpp.myResource())
=== APP.xmpp.myResource())
return;
var members = APP.xmpp.getMembers();
// Update the current dominant speaker.
if (resourceJid !== currentDominantSpeaker) {
var oldSpeakerVideoSpanId = "participant_" + currentDominantSpeaker,
newSpeakerVideoSpanId = "participant_" + resourceJid;
if($("#" + oldSpeakerVideoSpanId + ">span.displayname").text() ===
interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME) {
var currentJID = APP.xmpp.findJidFromResource(currentDominantSpeaker);
var newJID = APP.xmpp.findJidFromResource(resourceJid);
if(currentDominantSpeaker && (!members || !members[currentJID] ||
!members[currentJID].displayName)) {
setDisplayName(oldSpeakerVideoSpanId, null);
}
if($("#" + newSpeakerVideoSpanId + ">span.displayname").text() ===
interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME) {
setDisplayName(newSpeakerVideoSpanId,
if(resourceJid && (!members || !members[newJID] ||
!members[newJID].displayName)) {
setDisplayName(newSpeakerVideoSpanId, null,
interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME);
}
currentDominantSpeaker = resourceJid;
@@ -1810,20 +1863,18 @@ var VideoLayout = (function (my) {
// Update the large video if the video source is already available,
// otherwise wait for the "videoactive.jingle" event.
if (video.length && video[0].currentTime > 0)
VideoLayout.updateLargeVideo(RTC.getVideoSrc(video[0]), resourceJid);
VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(video[0]), resourceJid);
}
});
};
/**
* On last N change event.
*
* @param event the event that notified us
* @param lastNEndpoints the list of last N endpoints
* @param endpointsEnteringLastN the list currently entering last N
* endpoints
*/
$(document).bind('lastnchanged', function ( event,
lastNEndpoints,
my.onLastNEndpointsChanged = function ( lastNEndpoints,
endpointsEnteringLastN,
stream) {
if (lastNCount !== lastNEndpoints.length)
@@ -1907,13 +1958,13 @@ var VideoLayout = (function (my) {
if (!isVisible) {
console.log("Add to last N", resourceJid);
var jid = xmpp.findJidFromResource(resourceJid);
var mediaStream = RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var jid = APP.xmpp.findJidFromResource(resourceJid);
var mediaStream = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var sel = $('#participant_' + resourceJid + '>video');
var videoStream = simulcast.getReceivingVideoStream(
var videoStream = APP.simulcast.getReceivingVideoStream(
mediaStream.stream);
RTC.attachMediaStream(sel, videoStream);
APP.RTC.attachMediaStream(sel, videoStream);
if (lastNPickupJid == mediaStream.peerjid) {
// Clean up the lastN pickup jid.
lastNPickupJid = null;
@@ -1940,7 +1991,7 @@ var VideoLayout = (function (my) {
var resource, container, src;
var myResource
= xmpp.myResource();
= APP.xmpp.myResource();
// Find out which endpoint to show in the large video.
for (var i = 0; i < lastNEndpoints.length; i++) {
@@ -1962,9 +2013,9 @@ var VideoLayout = (function (my) {
}
}
});
};
$(document).bind('simulcastlayerschanging', function (event, endpointSimulcastLayers) {
my.onSimulcastLayersChanging = function (endpointSimulcastLayers) {
endpointSimulcastLayers.forEach(function (esl) {
var resource = esl.endpoint;
@@ -1983,18 +2034,16 @@ var VideoLayout = (function (my) {
var primarySSRC = esl.simulcastLayer.primarySSRC;
// Get session and stream from primary ssrc.
var res = simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
var sid = res.sid;
var electedStream = res.stream;
if (sid && electedStream) {
var msid = simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
console.info([esl, primarySSRC, msid, sid, electedStream]);
var msidParts = msid.split(' ');
var preload = (Strophe.getResourceFromJid(xmpp.getJidFromSSRC(primarySSRC)) == largeVideoState.userResourceJid);
var preload = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC)) == largeVideoState.userResourceJid);
if (preload) {
if (largeVideoState.preload)
@@ -2006,19 +2055,19 @@ var VideoLayout = (function (my) {
// ssrcs are unique in an rtp session
largeVideoState.preload_ssrc = primarySSRC;
RTC.attachMediaStream(largeVideoState.preload, electedStream)
APP.RTC.attachMediaStream(largeVideoState.preload, electedStream)
}
} else {
console.error('Could not find a stream or a session.', sid, electedStream);
}
});
});
};
/**
* On simulcast layers changed event.
*/
$(document).bind('simulcastlayerschanged', function (event, endpointSimulcastLayers) {
my.onSimulcastLayersChanged = function (endpointSimulcastLayers) {
endpointSimulcastLayers.forEach(function (esl) {
var resource = esl.endpoint;
@@ -2041,12 +2090,12 @@ var VideoLayout = (function (my) {
var primarySSRC = esl.simulcastLayer.primarySSRC;
// Get session and stream from primary ssrc.
var res = simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
var sid = res.sid;
var electedStream = res.stream;
if (sid && electedStream) {
var msid = simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
console.info('Switching simulcast substream.');
console.info([esl, primarySSRC, msid, sid, electedStream]);
@@ -2054,15 +2103,15 @@ var VideoLayout = (function (my) {
var msidParts = msid.split(' ');
var selRemoteVideo = $(['#', 'remoteVideo_', sid, '_', msidParts[0]].join(''));
var updateLargeVideo = (Strophe.getResourceFromJid(xmpp.getJidFromSSRC(primarySSRC))
var updateLargeVideo = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC))
== largeVideoState.userResourceJid);
var updateFocusedVideoSrc = (focusedVideoInfo && focusedVideoInfo.src && focusedVideoInfo.src != '' &&
(RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoInfo.src));
(APP.RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoInfo.src));
var electedStreamUrl;
if (largeVideoState.preload_ssrc == primarySSRC)
{
RTC.setVideoSrc(selRemoteVideo[0], RTC.getVideoSrc(largeVideoState.preload[0]));
APP.RTC.setVideoSrc(selRemoteVideo[0], APP.RTC.getVideoSrc(largeVideoState.preload[0]));
}
else
{
@@ -2073,22 +2122,22 @@ var VideoLayout = (function (my) {
largeVideoState.preload_ssrc = 0;
RTC.attachMediaStream(selRemoteVideo, electedStream);
APP.RTC.attachMediaStream(selRemoteVideo, electedStream);
}
var jid = xmpp.getJidFromSSRC(primarySSRC);
var jid = APP.xmpp.getJidFromSSRC(primarySSRC);
if (updateLargeVideo) {
VideoLayout.updateLargeVideo(RTC.getVideoSrc(selRemoteVideo[0]), null,
VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(selRemoteVideo[0]), null,
Strophe.getResourceFromJid(jid));
}
if (updateFocusedVideoSrc) {
focusedVideoInfo.src = RTC.getVideoSrc(selRemoteVideo[0]);
focusedVideoInfo.src = APP.RTC.getVideoSrc(selRemoteVideo[0]);
}
var videoId;
if(resource == xmpp.myResource())
if(resource == APP.xmpp.myResource())
{
videoId = "localVideoContainer";
}
@@ -2104,7 +2153,7 @@ var VideoLayout = (function (my) {
console.error('Could not find a stream or a sid.', sid, electedStream);
}
});
});
};
/**
* Updates local stats
@@ -2116,8 +2165,8 @@ var VideoLayout = (function (my) {
if(object.resolution !== null)
{
resolution = object.resolution;
object.resolution = resolution[xmpp.myJid()];
delete resolution[xmpp.myJid()];
object.resolution = resolution[APP.xmpp.myJid()];
delete resolution[APP.xmpp.myJid()];
}
updateStatsIndicator("localVideoContainer", percent, object);
for(var jid in resolution)

View File

@@ -37,8 +37,6 @@ function setupWelcomePage()
$("#videoconference_page").hide();
$("#domain_name").text(
window.location.protocol + "//" + window.location.host + "/");
$("span[name='appName']").text(interfaceConfig.APP_NAME);
if (interfaceConfig.SHOW_JITSI_WATERMARK) {
var leftWatermarkDiv
= $("#welcome_page_header div[class='watermark leftwatermark']");

View File

@@ -1,5 +1,7 @@
var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
var CQEvents = require("../../service/connectionquality/CQEvents");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
/**
* local stats
@@ -32,7 +34,7 @@ function startSendingStats() {
* Sends statistics to other participants
*/
function sendStats() {
xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
APP.xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
}
/**
@@ -72,9 +74,9 @@ function parseMUCStats(stats) {
var ConnectionQuality = {
init: function () {
xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
statistics.addConnectionStatsListener(this.updateLocalStats);
statistics.addRemoteStatsStopListener(this.stopSendingStats);
APP.xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
APP.statistics.addConnectionStatsListener(this.updateLocalStats);
APP.statistics.addRemoteStatsStopListener(this.stopSendingStats);
},

View File

@@ -27,12 +27,14 @@ var EventEmitter = require("events");
var eventEmitter = new EventEmitter();
var DesktopSharingEventTypes = require("../../service/desktopsharing/DesktopSharingEventTypes");
/**
* Method obtains desktop stream from WebRTC 'screen' source.
* Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
*/
function obtainWebRTCScreen(streamCallback, failCallback) {
RTC.getUserMediaWithConstraints(
APP.RTC.getUserMediaWithConstraints(
['screen'],
streamCallback,
failCallback
@@ -90,8 +92,8 @@ function isUpdateRequired(minVersion, extVersion)
catch (e)
{
console.error("Failed to parse extension version", e);
UI.messageHandler.showError('Error',
'Error when trying to detect desktopsharing extension.');
APP.UI.messageHandler.showError("dialog.error",
"dialog.detectext");
return true;
}
}
@@ -139,7 +141,7 @@ function doGetStreamFromExtension(streamCallback, failCallback) {
}
console.log("Response from extension: " + response);
if (response.streamId) {
RTC.getUserMediaWithConstraints(
APP.RTC.getUserMediaWithConstraints(
['desktop'],
function (stream) {
streamCallback(stream);
@@ -172,8 +174,8 @@ function obtainScreenFromExtension(streamCallback, failCallback) {
function (arg) {
console.log("Failed to install the extension", arg);
failCallback(arg);
UI.messageHandler.showError('Error',
'Failed to install desktop sharing extension');
APP.UI.messageHandler.showError("dialog.error",
"dialog.failtoinstall");
}
);
}
@@ -306,7 +308,7 @@ module.exports = {
getSwitchStreamFailed);
} else {
// Disable screen stream
RTC.getUserMediaWithConstraints(
APP.RTC.getUserMediaWithConstraints(
['video'],
function (stream) {
// We are now using camera stream

View File

@@ -3,30 +3,30 @@ var shortcuts = {
67: {
character: "C",
id: "toggleChatPopover",
function: UI.toggleChat
function: APP.UI.toggleChat
},
70: {
character: "F",
id: "filmstripPopover",
function: UI.toggleFilmStrip
function: APP.UI.toggleFilmStrip
},
77: {
character: "M",
id: "mutePopover",
function: UI.toggleAudio
function: APP.UI.toggleAudio
},
84: {
character: "T",
function: function() {
if(!RTC.localAudio.isMuted()) {
UI.toggleAudio();
if(!APP.RTC.localAudio.isMuted()) {
APP.UI.toggleAudio();
}
}
},
86: {
character: "V",
id: "toggleVideoPopover",
function: UI.toggleVideo
function: APP.UI.toggleVideo
}
};
@@ -43,11 +43,11 @@ var KeyboardShortcut = {
}
else if (keycode >= "0".charCodeAt(0) &&
keycode <= "9".charCodeAt(0)) {
UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1);
APP.UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1);
}
//esc while the smileys are visible hides them
} else if (keycode === 27 && $('#smileysContainer').is(':visible')) {
UI.toggleSmileys();
APP.UI.toggleSmileys();
}
};
@@ -56,8 +56,8 @@ var KeyboardShortcut = {
$(":focus").is("input[type=password]") ||
$(":focus").is("textarea"))) {
if(e.which === "T".charCodeAt(0)) {
if(RTC.localAudio.isMuted()) {
UI.toggleAudio();
if(APP.RTC.localAudio.isMuted()) {
APP.UI.toggleAudio();
}
}
}

View File

@@ -1,6 +1,7 @@
var email = '';
var displayName = '';
var userId;
var language = null;
function supportsLocalStorage() {
@@ -15,19 +16,20 @@ function supportsLocalStorage() {
function generateUniqueId() {
function _p8() {
return (Math.random().toString(16)+"000000000").substr(2,8);
return (Math.random().toString(16) + "000000000").substr(2, 8);
}
return _p8() + _p8() + _p8() + _p8();
}
if(supportsLocalStorage()) {
if(!window.localStorage.jitsiMeetId) {
if (supportsLocalStorage()) {
if (!window.localStorage.jitsiMeetId) {
window.localStorage.jitsiMeetId = generateUniqueId();
console.log("generated id", window.localStorage.jitsiMeetId);
}
userId = window.localStorage.jitsiMeetId || '';
email = window.localStorage.email || '';
displayName = window.localStorage.displayname || '';
language = window.localStorage.language;
} else {
console.log("local storage is not supported");
userId = generateUniqueId();
@@ -40,7 +42,7 @@ var Settings =
window.localStorage.displayname = displayName;
return displayName;
},
setEmail: function(newEmail)
setEmail: function (newEmail)
{
email = newEmail;
window.localStorage.email = newEmail;
@@ -50,8 +52,13 @@ var Settings =
return {
email: email,
displayName: displayName,
uid: userId
uid: userId,
language: language
};
},
setLanguage: function (lang) {
language = lang;
window.localStorage.language = lang;
}
};

View File

@@ -1,5 +1,6 @@
var SimulcastLogger = require("./SimulcastLogger");
var SimulcastUtils = require("./SimulcastUtils");
var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
function SimulcastReceiver() {
this.simulcastUtils = new SimulcastUtils();
@@ -161,7 +162,7 @@ SimulcastReceiver.prototype.getReceivingSSRC = function (jid) {
// low quality (that the sender always streams).
if(!ssrc)
{
var remoteStreamObject = RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var remoteStream = remoteStreamObject.getOriginalStream();
var tracks = remoteStream.getVideoTracks();
if (tracks) {
@@ -184,10 +185,10 @@ SimulcastReceiver.prototype.getReceivingVideoStreamBySSRC = function (ssrc)
{
var sid, electedStream;
var i, j, k;
var jid = xmpp.getJidFromSSRC(ssrc);
if(jid && RTC.remoteStreams[jid])
var jid = APP.xmpp.getJidFromSSRC(ssrc);
if(jid && APP.RTC.remoteStreams[jid])
{
var remoteStreamObject = RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
var remoteStream = remoteStreamObject.getOriginalStream();
var tracks = remoteStream.getVideoTracks();
if (tracks) {
@@ -207,7 +208,7 @@ SimulcastReceiver.prototype.getReceivingVideoStreamBySSRC = function (ssrc)
}
else
{
console.debug(RTC.remoteStreams, jid, ssrc);
console.debug(APP.RTC.remoteStreams, jid, ssrc);
}
return {

View File

@@ -32,7 +32,7 @@ SimulcastSender.prototype.getLocalVideoStream = function () {
return (this.displayedLocalVideoStream != null)
? this.displayedLocalVideoStream
// in case we have no simulcast at all, i.e. we didn't perform the GUM
: RTC.localVideo.getOriginalStream();
: APP.RTC.localVideo.getOriginalStream();
};
function NativeSimulcastSender() {
@@ -47,7 +47,7 @@ NativeSimulcastSender.prototype._localVideoSourceCache = '';
NativeSimulcastSender.prototype.reset = function () {
this._localExplosionMap = {};
this._isUsingScreenStream = desktopsharing.isUsingScreenStream();
this._isUsingScreenStream = APP.desktopsharing.isUsingScreenStream();
};
NativeSimulcastSender.prototype._cacheLocalVideoSources = function (lines) {
@@ -78,10 +78,12 @@ NativeSimulcastSender.prototype._appendSimulcastGroup = function (lines) {
simSSRC = this._generateRandomSSRC();
ssrcGroup.push(simSSRC);
sb.splice.apply(sb, [sb.length, 0].concat(
[["a=ssrc:", simSSRC, " cname:", videoSources.base.cname].join(''),
["a=ssrc:", simSSRC, " msid:", videoSources.base.msid].join('')]
));
if (videoSources.base) {
sb.splice.apply(sb, [sb.length, 0].concat(
[["a=ssrc:", simSSRC, " cname:", videoSources.base.cname].join(''),
["a=ssrc:", simSSRC, " msid:", videoSources.base.msid].join('')]
));
}
this.logger.info(['Generated substream ', i, ' with SSRC ', simSSRC, '.'].join(''));

View File

@@ -6,6 +6,7 @@ var NoSimulcastSender = SimulcastSender["no"];
var NativeSimulcastSender = SimulcastSender["native"];
var SimulcastReceiver = require("./SimulcastReceiver");
var SimulcastUtils = require("./SimulcastUtils");
var RTCEvents = require("../../service/RTC/RTCEvents");
/**
@@ -46,6 +47,22 @@ function SimulcastManager() {
}
}
APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
function (endpointSimulcastLayers) {
endpointSimulcastLayers.forEach(function (esl) {
var ssrc = esl.simulcastLayer.primarySSRC;
simulcast._setReceivingVideoStream(esl.endpoint, ssrc);
});
});
APP.RTC.addListener(RTCEvents.SIMULCAST_START, function (simulcastLayer) {
var ssrc = simulcastLayer.primarySSRC;
simulcast._setLocalVideoStreamEnabled(ssrc, true);
});
APP.RTC.addListener(RTCEvents.SIMULCAST_STOP, function (simulcastLayer) {
var ssrc = simulcastLayer.primarySSRC;
simulcast._setLocalVideoStreamEnabled(ssrc, false);
});
}
/**
@@ -180,24 +197,6 @@ SimulcastManager.prototype.resetSender = function() {
}
};
$(document).bind('simulcastlayerschanged', function (event, endpointSimulcastLayers) {
endpointSimulcastLayers.forEach(function (esl) {
var ssrc = esl.simulcastLayer.primarySSRC;
simulcast._setReceivingVideoStream(esl.endpoint, ssrc);
});
});
$(document).bind('startsimulcastlayer', function (event, simulcastLayer) {
var ssrc = simulcastLayer.primarySSRC;
simulcast._setLocalVideoStreamEnabled(ssrc, true);
});
$(document).bind('stopsimulcastlayer', function (event, simulcastLayer) {
var ssrc = simulcastLayer.primarySSRC;
simulcast._setLocalVideoStreamEnabled(ssrc, false);
});
var simulcast = new SimulcastManager();
module.exports = simulcast;

View File

@@ -84,7 +84,7 @@ function LocalStatsCollector(stream, interval, statisticsService, eventEmitter)
* Starts the collecting the statistics.
*/
LocalStatsCollector.prototype.start = function () {
if (!window.AudioContext)
if (config.disableAudioLevels || !window.AudioContext)
return;
var context = new AudioContext();

View File

@@ -1,5 +1,8 @@
/* global ssrc2jid */
/* jshint -W117 */
var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
/**
* Calculates packet lost percent using the number of lost packets and the
* number of all packet.
@@ -14,10 +17,10 @@ function calculatePacketLoss(lostPackets, totalPackets) {
}
function getStatValue(item, name) {
if(!keyMap[RTC.getBrowserType()][name])
if(!keyMap[APP.RTC.getBrowserType()][name])
throw "The property isn't supported!";
var key = keyMap[RTC.getBrowserType()][name];
return RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
var key = keyMap[APP.RTC.getBrowserType()][name];
return APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
}
/**
@@ -108,9 +111,13 @@ PeerStats.prototype.setSsrcBitrate = function (ssrc, bitrate)
PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel)
{
// Range limit 0 - 1
this.ssrc2AudioLevel[ssrc] = Math.min(Math.max(audioLevel, 0), 1);
this.ssrc2AudioLevel[ssrc] = formatAudioLevel(audioLevel);
};
function formatAudioLevel(audioLevel) {
return Math.min(Math.max(audioLevel, 0), 1);
}
/**
* Array with the transport information.
* @type {Array}
@@ -144,7 +151,7 @@ function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, even
/**
* Gather PeerConnection stats once every this many milliseconds.
*/
this.GATHER_INTERVAL = 10000;
this.GATHER_INTERVAL = 15000;
/**
* Log stats via the focus once every this many milliseconds.
@@ -185,16 +192,26 @@ module.exports = StatsCollector;
/**
* Stops stats updates.
*/
StatsCollector.prototype.stop = function ()
{
if (this.audioLevelsIntervalId)
{
StatsCollector.prototype.stop = function () {
if (this.audioLevelsIntervalId) {
clearInterval(this.audioLevelsIntervalId);
this.audioLevelsIntervalId = null;
}
if (this.statsIntervalId)
{
clearInterval(this.statsIntervalId);
this.statsIntervalId = null;
}
if(this.logStatsIntervalId)
{
clearInterval(this.logStatsIntervalId);
this.logStatsIntervalId = null;
}
if(this.gatherStatsIntervalId)
{
clearInterval(this.gatherStatsIntervalId);
this.gatherStatsIntervalId = null;
}
@@ -216,69 +233,68 @@ StatsCollector.prototype.errorCallback = function (error)
StatsCollector.prototype.start = function ()
{
var self = this;
this.audioLevelsIntervalId = setInterval(
function ()
{
// Interval updates
self.peerconnection.getStats(
function (report)
{
var results = null;
if(!report || !report.result || typeof report.result != 'function')
{
results = report;
}
else
{
results = report.result();
}
//console.error("Got interval report", results);
self.currentAudioLevelsReport = results;
self.processAudioLevelReport();
self.baselineAudioLevelsReport =
self.currentAudioLevelsReport;
},
self.errorCallback
);
},
self.audioLevelsIntervalMilis
);
if(!config.disableAudioLevels) {
console.debug("set audio levels interval");
this.audioLevelsIntervalId = setInterval(
function () {
// Interval updates
self.peerconnection.getStats(
function (report) {
var results = null;
if (!report || !report.result ||
typeof report.result != 'function') {
results = report;
}
else {
results = report.result();
}
//console.error("Got interval report", results);
self.currentAudioLevelsReport = results;
self.processAudioLevelReport();
self.baselineAudioLevelsReport =
self.currentAudioLevelsReport;
},
self.errorCallback
);
},
self.audioLevelsIntervalMilis
);
}
this.statsIntervalId = setInterval(
function () {
// Interval updates
self.peerconnection.getStats(
function (report)
{
var results = null;
if(!report || !report.result || typeof report.result != 'function')
{
//firefox
results = report;
}
else
{
//chrome
results = report.result();
}
//console.error("Got interval report", results);
self.currentStatsReport = results;
try
{
self.processStatsReport();
}
catch (e)
{
console.error("Unsupported key:" + e, e);
}
if(!config.disableStats) {
console.debug("set stats interval");
this.statsIntervalId = setInterval(
function () {
// Interval updates
self.peerconnection.getStats(
function (report) {
var results = null;
if (!report || !report.result ||
typeof report.result != 'function') {
//firefox
results = report;
}
else {
//chrome
results = report.result();
}
//console.error("Got interval report", results);
self.currentStatsReport = results;
try {
self.processStatsReport();
}
catch (e) {
console.error("Unsupported key:" + e, e);
}
self.baselineStatsReport = self.currentStatsReport;
},
self.errorCallback
);
},
self.statsIntervalMilis
);
self.baselineStatsReport = self.currentStatsReport;
},
self.errorCallback
);
},
self.statsIntervalMilis
);
}
if (config.logStats) {
this.gatherStatsIntervalId = setInterval(
@@ -300,6 +316,38 @@ StatsCollector.prototype.start = function ()
}
};
/**
* Checks whether a certain record should be included in the logged statistics.
*/
function acceptStat(reportId, reportType, statName) {
if (reportType == "googCandidatePair" && statName == "googChannelId")
return false;
if (reportType == "ssrc") {
if (statName == "googTrackId" ||
statName == "transportId" ||
statName == "ssrc")
return false;
}
return true;
}
/**
* Checks whether a certain record should be included in the logged statistics.
*/
function acceptReport(id, type) {
if (id.substring(0, 15) == "googCertificate" ||
id.substring(0, 9) == "googTrack" ||
id.substring(0, 20) == "googLibjingleSession")
return false;
if (type == "googComponent")
return false;
return true;
}
/**
* Converts the stats to the format used for logging, and saves the data in
* this.statsToBeLogged.
@@ -310,12 +358,16 @@ StatsCollector.prototype.addStatsToBeLogged = function (reports) {
var num_records = this.statsToBeLogged.timestamps.length;
this.statsToBeLogged.timestamps.push(new Date().getTime());
reports.map(function (report) {
if (!acceptReport(report.id, report.type))
return;
var stat = self.statsToBeLogged.stats[report.id];
if (!stat) {
stat = self.statsToBeLogged.stats[report.id] = {};
}
stat.type = report.type;
report.names().map(function (name) {
if (!acceptStat(report.id, report.type, name))
return;
var values = stat[name];
if (!values) {
values = stat[name] = [];
@@ -330,7 +382,7 @@ StatsCollector.prototype.addStatsToBeLogged = function (reports) {
StatsCollector.prototype.logStats = function () {
if(!xmpp.sendLogs(this.statsToBeLogged))
if(!APP.xmpp.sendLogs(this.statsToBeLogged))
return;
// Reset the stats
this.statsToBeLogged.stats = {};
@@ -444,7 +496,7 @@ StatsCollector.prototype.processStatsReport = function () {
var ssrc = getStatValue(now, 'ssrc');
if(!ssrc)
continue;
var jid = xmpp.getJidFromSSRC(ssrc);
var jid = APP.xmpp.getJidFromSSRC(ssrc);
if (!jid && (Date.now() - now.timestamp) < 3000) {
console.warn("No jid for ssrc: " + ssrc);
continue;
@@ -645,7 +697,7 @@ StatsCollector.prototype.processAudioLevelReport = function ()
}
var ssrc = getStatValue(now, 'ssrc');
var jid = xmpp.getJidFromSSRC(ssrc);
var jid = APP.xmpp.getJidFromSSRC(ssrc);
if (!jid && (Date.now() - now.timestamp) < 3000)
{
console.warn("No jid for ssrc: " + ssrc);
@@ -679,11 +731,11 @@ StatsCollector.prototype.processAudioLevelReport = function ()
// but it seems to vary between 0 and around 32k.
audioLevel = audioLevel / 32767;
jidStats.setSsrcAudioLevel(ssrc, audioLevel);
if(jid != xmpp.myJid())
if(jid != APP.xmpp.myJid())
this.eventEmitter.emit("statistics.audioLevel", jid, audioLevel);
}
}
};
};

View File

@@ -1,8 +0,0 @@
{
"name": "statistics",
"version": "0.0.1",
"main": "statistics.js",
"description": "Statistics module for Jitsi Meet",
"dependencies": {
}
}

View File

@@ -4,10 +4,8 @@
var LocalStats = require("./LocalStatsCollector.js");
var RTPStats = require("./RTPStatsCollector.js");
var EventEmitter = require("events");
//These lines should be uncommented when require works in app.js
//var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
//var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
//var XMPPEvents = require("../service/xmpp/XMPPEvents");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var eventEmitter = new EventEmitter();
@@ -35,18 +33,14 @@ function stopRemote()
}
function startRemoteStats (peerconnection) {
if (config.enableRtpStats)
if(rtpStats)
{
if(rtpStats)
{
rtpStats.stop();
rtpStats = null;
}
rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter);
rtpStats.start();
rtpStats.stop();
rtpStats = null;
}
rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter);
rtpStats.start();
}
function onStreamCreated(stream)
@@ -54,7 +48,7 @@ function onStreamCreated(stream)
if(stream.getOriginalStream().getAudioTracks().length === 0)
return;
localStats = new LocalStats(stream.getOriginalStream(), 100, statistics,
localStats = new LocalStats(stream.getOriginalStream(), 200, statistics,
eventEmitter);
localStats.start();
}
@@ -122,10 +116,10 @@ var statistics =
},
start: function () {
RTC.addStreamListener(onStreamCreated,
APP.RTC.addStreamListener(onStreamCreated,
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
startRemoteStats(event.peerconnection);
});
}

View File

@@ -0,0 +1,132 @@
var i18n = require("i18next-client");
var languages = require("../../service/translation/languages");
var Settings = require("../settings/Settings");
var DEFAULT_LANG = languages.EN;
i18n.addPostProcessor("resolveAppName", function(value, key, options) {
return value.replace("__app__", interfaceConfig.APP_NAME);
});
var defaultOptions = {
detectLngQS: "lang",
useCookie: false,
fallbackLng: DEFAULT_LANG,
load: "unspecific",
resGetPath: 'lang/__ns__-__lng__.json',
ns: {
namespaces: ['main', 'languages'],
defaultNs: 'main'
},
lngWhitelist : languages.getLanguages(),
fallbackOnNull: true,
fallbackOnEmpty: true,
useDataAttrOptions: true,
defaultValueFromContent: false,
app: interfaceConfig.APP_NAME,
getAsync: false,
defaultValueFromContent: false,
customLoad: function(lng, ns, options, done) {
var resPath = "lang/__ns__-__lng__.json";
if(lng === languages.EN)
resPath = "lang/__ns__.json";
var url = i18n.functions.applyReplacement(resPath, { lng: lng, ns: ns });
i18n.functions.ajax({
url: url,
success: function(data, status, xhr) {
i18n.functions.log('loaded: ' + url);
done(null, data);
},
error : function(xhr, status, error) {
if ((status && status == 200) ||
(xhr && xhr.status && xhr.status == 200)) {
// file loaded but invalid json, stop waste time !
i18n.functions.error('There is a typo in: ' + url);
} else if ((status && status == 404) ||
(xhr && xhr.status && xhr.status == 404)) {
i18n.functions.log('Does not exist: ' + url);
} else {
var theStatus = status ? status :
((xhr && xhr.status) ? xhr.status : null);
i18n.functions.log(theStatus + ' when loading ' + url);
}
done(error, {});
},
dataType: "json",
async : options.getAsync
});
}
// options for caching
// useLocalStorage: true,
// localStorageExpirationTime: 86400000 // in ms, default 1 week
};
function initCompleted(t)
{
$("[data-i18n]").i18n();
}
function checkForParameter() {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == "lang")
{
return pair[1];
}
}
return null;
}
module.exports = {
init: function (lang) {
var options = defaultOptions;
if(!lang)
{
lang = checkForParameter();
if(!lang)
{
var settings = Settings.getSettings();
if(settings)
lang = settings.language;
}
}
if(lang) {
options.lng = lang;
}
i18n.init(options, initCompleted);
},
translateString: function (key, options) {
return i18n.t(key, options);
},
setLanguage: function (lang) {
if(!lang)
lang = DEFAULT_LANG;
i18n.setLng(lang, defaultOptions, initCompleted);
},
getCurrentLanguage: function () {
return i18n.lng();
},
translateElement: function (selector) {
selector.i18n();
},
generateTranslatonHTML: function (key, options) {
var str = "<span data-i18n=\"" + key + "\"";
if(options)
{
str += " data-i18n-options=\"" + JSON.stringify(options) + "\"";
}
str += ">";
str += this.translateString(key, options);
str += "</span>";
return str;
}
};

View File

@@ -3,6 +3,7 @@ var TraceablePeerConnection = require("./TraceablePeerConnection");
var SDPDiffer = require("./SDPDiffer");
var SDPUtil = require("./SDPUtil");
var SDP = require("./SDP");
var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
// Jingle stuff
function JingleSession(me, sid, connection, service) {
@@ -105,7 +106,7 @@ JingleSession.prototype.initiate = function (peerjid, isInitiator) {
onIceConnectionStateChange(self.sid, self);
};
// add any local and relayed stream
RTC.localStreams.forEach(function(stream) {
APP.RTC.localStreams.forEach(function(stream) {
self.peerconnection.addStream(stream.getOriginalStream());
});
this.relayedStreams.forEach(function(stream) {
@@ -176,7 +177,7 @@ JingleSession.prototype.accept = function () {
// FIXME: change any inactive to sendrecv or whatever they were originally
pranswer.sdp = pranswer.sdp.replace('a=inactive', 'a=sendrecv');
}
pranswer = simulcast.reverseTransformLocalDescription(pranswer);
pranswer = APP.simulcast.reverseTransformLocalDescription(pranswer);
var prsdp = new SDP(pranswer.sdp);
var accept = $iq({to: this.peerjid,
type: 'set'})
@@ -629,7 +630,7 @@ JingleSession.prototype.createdAnswer = function (sdp, provisional) {
initiator: self.initiator,
responder: self.responder,
sid: self.sid });
var publicLocalDesc = simulcast.reverseTransformLocalDescription(sdp);
var publicLocalDesc = APP.simulcast.reverseTransformLocalDescription(sdp);
var publicLocalSDP = new SDP(publicLocalDesc.sdp);
publicLocalSDP.toJingle(accept, self.initiator == self.me ? 'initiator' : 'responder', ssrcs);
self.connection.sendIQ(accept,
@@ -735,7 +736,7 @@ JingleSession.prototype.addSource = function (elem, fromJid) {
$(elem).each(function (idx, content) {
var name = $(content).attr('name');
var lines = '';
tmp = $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
$(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
var semantics = this.getAttribute('semantics');
var ssrcs = $(this).find('>source').map(function () {
return this.getAttribute('ssrc');
@@ -745,7 +746,7 @@ JingleSession.prototype.addSource = function (elem, fromJid) {
lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
}
});
tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
var tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
tmp.each(function () {
var ssrc = $(this).attr('ssrc');
if(mySdp.containsSSRC(ssrc)){
@@ -800,7 +801,7 @@ JingleSession.prototype.removeSource = function (elem, fromJid) {
$(elem).each(function (idx, content) {
var name = $(content).attr('name');
var lines = '';
tmp = $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
$(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
var semantics = this.getAttribute('semantics');
var ssrcs = $(this).find('>source').map(function () {
return this.getAttribute('ssrc');
@@ -810,7 +811,7 @@ JingleSession.prototype.removeSource = function (elem, fromJid) {
lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
}
});
tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
var tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
tmp.each(function () {
var ssrc = $(this).attr('ssrc');
// This should never happen, but can be useful for bug detection
@@ -973,7 +974,7 @@ JingleSession.prototype.switchStreams = function (new_stream, oldStream, success
self.peerconnection.addStream(new_stream);
}
RTC.switchVideoStreams(new_stream, oldStream);
APP.RTC.switchVideoStreams(new_stream, oldStream);
// Conference is not active
if(!oldSdp || !self.peerconnection) {
@@ -1063,7 +1064,7 @@ JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
* disabled; otherwise, <tt>false</tt>
*/
JingleSession.prototype.isVideoMute = function () {
var tracks = RTC.localVideo.getVideoTracks();
var tracks = APP.RTC.localVideo.getVideoTracks();
var mute = true;
for (var i = 0; i < tracks.length; ++i) {
@@ -1115,7 +1116,7 @@ JingleSession.prototype.setVideoMute = function (mute, callback, options) {
return callback(mute)
};
if (mute == RTC.localVideo.isMuted())
if (mute == APP.RTC.localVideo.isMuted())
{
// Even if no change occurs, the specified callback is to be executed.
// The specified callback may, optionally, return a successCallback
@@ -1126,7 +1127,7 @@ JingleSession.prototype.setVideoMute = function (mute, callback, options) {
successCallback();
}
} else {
RTC.localVideo.setMute(!mute);
APP.RTC.localVideo.setMute(!mute);
this.hardMuteVideo(mute);
@@ -1137,7 +1138,7 @@ JingleSession.prototype.setVideoMute = function (mute, callback, options) {
// SDP-based mute by going recvonly/sendrecv
// FIXME: should probably black out the screen as well
JingleSession.prototype.toggleVideoMute = function (callback) {
this.service.setVideoMute(RTC.localVideo.isMuted(), callback);
this.service.setVideoMute(APP.RTC.localVideo.isMuted(), callback);
};
JingleSession.prototype.hardMuteVideo = function (muted) {
@@ -1224,15 +1225,15 @@ JingleSession.onJingleError = function (session, error)
JingleSession.onJingleFatalError = function (session, error)
{
this.service.sessionTerminated = true;
connection.emuc.doLeave();
UI.messageHandler.showError( "Sorry",
"Internal application error[setRemoteDescription]");
this.connection.emuc.doLeave();
APP.UI.messageHandler.showError("dialog.sorry",
"dialog.internalError");
}
JingleSession.prototype.setLocalDescription = function () {
// put our ssrcs into presence so other clients can identify our stream
var newssrcs = [];
var media = simulcast.parseMedia(this.peerconnection.localDescription);
var media = APP.simulcast.parseMedia(this.peerconnection.localDescription);
media.forEach(function (media) {
if(Object.keys(media.sources).length > 0) {
@@ -1264,7 +1265,7 @@ JingleSession.prototype.setLocalDescription = function () {
if (newssrcs.length > 0) {
for (var i = 1; i <= newssrcs.length; i ++) {
// Change video type to screen
if (newssrcs[i-1].type === 'video' && desktopsharing.isUsingScreenStream()) {
if (newssrcs[i-1].type === 'video' && APP.desktopsharing.isUsingScreenStream()) {
newssrcs[i-1].type = 'screen';
}
this.connection.emuc.addMediaToPresence(i,
@@ -1291,25 +1292,25 @@ function sendKeyframe(pc) {
},
function (error) {
console.log('triggerKeyframe setLocalDescription failed', error);
UI.messageHandler.showError();
APP.UI.messageHandler.showError();
}
);
},
function (error) {
console.log('triggerKeyframe createAnswer failed', error);
UI.messageHandler.showError();
APP.UI.messageHandler.showError();
}
);
},
function (error) {
console.log('triggerKeyframe setRemoteDescription failed', error);
UI.messageHandler.showError();
APP.UI.messageHandler.showError();
}
);
}
JingleSession.prototype.remoteStreamAdded = function (data) {
JingleSession.prototype.remoteStreamAdded = function (data, times) {
var self = this;
var thessrc;
var ssrc2jid = this.connection.emuc.ssrc2jid;
@@ -1338,12 +1339,24 @@ JingleSession.prototype.remoteStreamAdded = function (data) {
// presence to arrive.
if (!ssrc2jid[thessrc]) {
// TODO(gp) limit wait duration to 1 sec.
setTimeout(function(d) {
return function() {
self.remoteStreamAdded(d);
}
}(data), 250);
if (typeof times === 'undefined')
{
times = 0;
}
if (times > 10)
{
console.warning('Waiting for jid timed out', thessrc);
}
else
{
setTimeout(function(d) {
return function() {
self.remoteStreamAdded(d, times++);
}
}(data), 250);
}
return;
}
@@ -1355,39 +1368,18 @@ JingleSession.prototype.remoteStreamAdded = function (data) {
}
}
//TODO: this code should be removed when firefox implement multistream support
if(RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_FIREFOX)
{
if((JingleSession.notReceivedSSRCs.length == 0) ||
!ssrc2jid[JingleSession.notReceivedSSRCs[JingleSession.notReceivedSSRCs.length - 1]])
{
// TODO(gp) limit wait duration to 1 sec.
setTimeout(function(d) {
return function() {
self.remoteStreamAdded(d);
}
}(data), 250);
return;
}
thessrc = JingleSession.notReceivedSSRCs.pop();
if (ssrc2jid[thessrc]) {
data.peerjid = ssrc2jid[thessrc];
}
}
RTC.createRemoteStream(data, this.sid, thessrc);
APP.RTC.createRemoteStream(data, this.sid, thessrc);
var isVideo = data.stream.getVideoTracks().length > 0;
// an attempt to work around https://github.com/jitsi/jitmeet/issues/32
if (isVideo &&
data.peerjid && this.peerjid === data.peerjid &&
data.stream.getVideoTracks().length === 0 &&
RTC.localVideo.getTracks().length > 0) {
APP.RTC.localVideo.getTracks().length > 0) {
window.setTimeout(function () {
sendKeyframe(self.peerconnection);
}, 3000);
}
}
module.exports = JingleSession;
module.exports = JingleSession;

View File

@@ -235,11 +235,11 @@ SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
var msid = null;
if(mline.media == "audio")
{
msid = RTC.localAudio.getId();
msid = APP.RTC.localAudio.getId();
}
else
{
msid = RTC.localVideo.getId();
msid = APP.RTC.localVideo.getId();
}
if(msid != null)
{

View File

@@ -6,6 +6,8 @@ function TraceablePeerConnection(ice_config, constraints) {
this.stats = {};
this.statsinterval = null;
this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable
var Interop = require('sdp-interop').Interop;
this.interop = new Interop();
// override as desired
this.trace = function (what, info) {
@@ -98,25 +100,45 @@ function TraceablePeerConnection(ice_config, constraints) {
};
dumpSDP = function(description) {
if (typeof description === 'undefined' || description == null) {
return '';
}
return 'type: ' + description.type + '\r\n' + description.sdp;
}
};
if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
TraceablePeerConnection.prototype.__defineGetter__('signalingState', function() { return this.peerconnection.signalingState; });
TraceablePeerConnection.prototype.__defineGetter__('iceConnectionState', function() { return this.peerconnection.iceConnectionState; });
TraceablePeerConnection.prototype.__defineGetter__('localDescription', function() {
var publicLocalDescription = simulcast.reverseTransformLocalDescription(this.peerconnection.localDescription);
return publicLocalDescription;
this.trace('getLocalDescription::preTransform (Plan A)', dumpSDP(this.peerconnection.localDescription));
// if we're running on FF, transform to Plan B first.
var desc = this.peerconnection.localDescription;
if (navigator.mozGetUserMedia) {
desc = this.interop.toPlanB(desc);
} else {
desc = APP.simulcast.reverseTransformLocalDescription(this.peerconnection.localDescription);
}
this.trace('getLocalDescription::postTransform (Plan B)', dumpSDP(desc));
return desc;
});
TraceablePeerConnection.prototype.__defineGetter__('remoteDescription', function() {
var publicRemoteDescription = simulcast.reverseTransformRemoteDescription(this.peerconnection.remoteDescription);
return publicRemoteDescription;
this.trace('getRemoteDescription::preTransform (Plan A)', dumpSDP(this.peerconnection.remoteDescription));
// if we're running on FF, transform to Plan B first.
var desc = this.peerconnection.remoteDescription;
if (navigator.mozGetUserMedia) {
desc = this.interop.toPlanB(desc);
} else {
desc = APP.simulcast.reverseTransformRemoteDescription(this.peerconnection.remoteDescription);
}
this.trace('getRemoteDescription::postTransform (Plan B)', dumpSDP(desc));
return desc;
});
}
TraceablePeerConnection.prototype.addStream = function (stream) {
this.trace('addStream', stream.id);
simulcast.resetSender();
APP.simulcast.resetSender();
try
{
this.peerconnection.addStream(stream);
@@ -130,7 +152,7 @@ TraceablePeerConnection.prototype.addStream = function (stream) {
TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
this.trace('removeStream', stream.id);
simulcast.resetSender();
APP.simulcast.resetSender();
if(stopStreams) {
stream.getAudioTracks().forEach(function (track) {
track.stop();
@@ -148,9 +170,15 @@ TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
};
TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
this.trace('setLocalDescription::preTransform (Plan B)', dumpSDP(description));
// if we're running on FF, transform to Plan A first.
if (navigator.mozGetUserMedia) {
description = this.interop.toPlanA(description);
} else {
description = APP.simulcast.transformLocalDescription(description);
}
this.trace('setLocalDescription::postTransform (Plan A)', dumpSDP(description));
var self = this;
description = simulcast.transformLocalDescription(description);
this.trace('setLocalDescription', dumpSDP(description));
this.peerconnection.setLocalDescription(description,
function () {
self.trace('setLocalDescriptionOnSuccess');
@@ -169,9 +197,16 @@ TraceablePeerConnection.prototype.setLocalDescription = function (description, s
};
TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
this.trace('setRemoteDescription::preTransform (Plan B)', dumpSDP(description));
// if we're running on FF, transform to Plan A first.
if (navigator.mozGetUserMedia) {
description = this.interop.toPlanA(description);
}
else {
description = APP.simulcast.transformRemoteDescription(description);
}
this.trace('setRemoteDescription::postTransform (Plan A)', dumpSDP(description));
var self = this;
description = simulcast.transformRemoteDescription(description);
this.trace('setRemoteDescription', dumpSDP(description));
this.peerconnection.setRemoteDescription(description,
function () {
self.trace('setRemoteDescriptionOnSuccess');
@@ -203,7 +238,12 @@ TraceablePeerConnection.prototype.createOffer = function (successCallback, failu
this.trace('createOffer', JSON.stringify(constraints, null, ' '));
this.peerconnection.createOffer(
function (offer) {
self.trace('createOfferOnSuccess', dumpSDP(offer));
self.trace('createOfferOnSuccess::preTransform (Plan A)', dumpSDP(offer));
// if we're running on FF, transform to Plan B first.
if (navigator.mozGetUserMedia) {
offer = self.interop.toPlanB(offer);
}
self.trace('createOfferOnSuccess::postTransform (Plan B)', dumpSDP(offer));
successCallback(offer);
},
function(err) {
@@ -219,8 +259,14 @@ TraceablePeerConnection.prototype.createAnswer = function (successCallback, fail
this.trace('createAnswer', JSON.stringify(constraints, null, ' '));
this.peerconnection.createAnswer(
function (answer) {
answer = simulcast.transformAnswer(answer);
self.trace('createAnswerOnSuccess', dumpSDP(answer));
self.trace('createAnswerOnSuccess::preTransfom (Plan A)', dumpSDP(answer));
// if we're running on FF, transform to Plan A first.
if (navigator.mozGetUserMedia) {
answer = self.interop.toPlanB(answer);
} else {
answer = APP.simulcast.transformAnswer(answer);
}
self.trace('createAnswerOnSuccess::postTransfom (Plan B)', dumpSDP(answer));
successCallback(answer);
},
function(err) {

View File

@@ -1,11 +1,18 @@
/* global $, $iq, config, connection, UI, messageHandler,
/* global $, $iq, APP, config, connection, UI, messageHandler,
roomName, sessionTerminated, Strophe, Util */
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Settings = require("../settings/Settings");
var AuthenticationEvents
= require("../../service/authentication/AuthenticationEvents");
/**
* Contains logic responsible for enabling/disabling functionality available
* only to moderator users.
*/
var connection = null;
var focusUserJid;
function createExpBackoffTimer(step) {
var count = 1;
return function (reset) {
@@ -30,6 +37,8 @@ var externalAuthEnabled = false;
// service discovery.
var sipGatewayEnabled = config.hosts.call_control !== undefined;
var eventEmitter = null;
var Moderator = {
isModerator: function () {
return connection && connection.emuc.isModerator();
@@ -52,8 +61,28 @@ var Moderator = {
connection = con;
},
init: function (xmpp) {
init: function (xmpp, emitter) {
this.xmppService = xmpp;
eventEmitter = emitter;
// Message listener that talks to POPUP window
function listener(event) {
if (event.data && event.data.sessionId) {
if (event.origin !== window.location.origin) {
console.warn(
"Ignoring sessionId from different origin: " + event.origin);
return;
}
localStorage.setItem('sessionId', event.data.sessionId);
// After popup is closed we will authenticate
}
}
// Register
if (window.addEventListener) {
window.addEventListener("message", listener, false);
} else {
window.attachEvent("onmessage", listener);
}
},
onMucLeft: function (jid) {
@@ -93,10 +122,24 @@ var Moderator = {
createConferenceIq: function (roomName) {
// Generate create conference IQ
var elem = $iq({to: Moderator.getFocusComponent(), type: 'set'});
// Session Id used for authentication
var sessionId = localStorage.getItem('sessionId');
var machineUID = Settings.getSettings().uid;
console.info(
"Session ID: " + sessionId + " machine UID: " + machineUID);
elem.c('conference', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
room: roomName,
'machine-uid': machineUID
});
if (sessionId) {
elem.attrs({ 'session-id': sessionId});
}
if (config.hosts.bridge !== undefined) {
elem.c(
'property',
@@ -146,22 +189,44 @@ var Moderator = {
},
parseConfigOptions: function (resultIq) {
Moderator.setFocusUserJid(
$(resultIq).find('conference').attr('focusjid'));
var extAuthParam
= $(resultIq).find('>conference>property[name=\'externalAuth\']');
if (extAuthParam.length) {
externalAuthEnabled = extAuthParam.attr('value') === 'true';
var authenticationEnabled
= $(resultIq).find(
'>conference>property' +
'[name=\'authentication\'][value=\'true\']').length > 0;
console.info("Authentication enabled: " + authenticationEnabled);
externalAuthEnabled
= $(resultIq).find(
'>conference>property' +
'[name=\'externalAuth\'][value=\'true\']').length > 0;
console.info('External authentication enabled: ' + externalAuthEnabled);
if (!externalAuthEnabled) {
// We expect to receive sessionId in 'internal' authentication mode
var sessionId
= $(resultIq).find('conference').attr('session-id');
if (sessionId) {
console.info('Received sessionId: ' + sessionId);
localStorage.setItem('sessionId', sessionId);
}
}
console.info("External authentication enabled: " + externalAuthEnabled);
var authIdentity = $(resultIq).find('>conference').attr('identity');
eventEmitter.emit(AuthenticationEvents.IDENTITY_UPDATED,
authenticationEnabled, authIdentity);
// Check if focus has auto-detected Jigasi component(this will be also
// included if we have passed our host from the config)
if ($(resultIq).find(
'>conference>property[name=\'sipGatewayEnabled\']').length) {
'>conference>property' +
'[name=\'sipGatewayEnabled\'][value=\'true\']').length) {
sipGatewayEnabled = true;
}
@@ -179,12 +244,14 @@ var Moderator = {
connection.sendIQ(
iq,
function (result) {
// Setup config options
Moderator.parseConfigOptions(result);
if ('true' === $(result).find('conference').attr('ready')) {
// Reset both timers
getNextTimeout(true);
getNextErrorTimeout(true);
// Setup config options
Moderator.parseConfigOptions(result);
// Exec callback
callback();
} else {
@@ -200,34 +267,66 @@ var Moderator = {
}
},
function (error) {
// Invalid session ? remove and try again
// without session ID to get a new one
var invalidSession
= $(error).find('>error>session-invalid').length;
if (invalidSession) {
console.info("Session expired! - removing");
localStorage.removeItem("sessionId");
}
if ($(error).find('>error>graceful-shutdown').length) {
eventEmitter.emit(XMPPEvents.GRACEFUL_SHUTDOWN);
return;
}
// Check for error returned by the reservation system
var reservationErr = $(error).find('>error>reservation-error');
if (reservationErr.length) {
// Trigger error event
var errorCode = reservationErr.attr('error-code');
var errorMsg;
if ($(error).find('>error>text')) {
errorMsg = $(error).find('>error>text').text();
}
eventEmitter.emit(
XMPPEvents.RESERVATION_ERROR, errorCode, errorMsg);
return;
}
// Not authorized to create new room
if ($(error).find('>error>not-authorized').length) {
console.warn("Unauthorized to start the conference");
console.warn("Unauthorized to start the conference", error);
var toDomain
= Strophe.getDomainFromJid(error.getAttribute('to'));
if (toDomain === config.hosts.anonymousdomain) {
// we are connected with anonymous domain and
// only non anonymous users can create rooms
// we must authorize the user
self.xmppService.promptLogin();
} else {
// External authentication mode
UI.onAuthenticationRequired(function () {
Moderator.allocateConferenceFocus(
roomName, callback);
});
eventEmitter.emit(
XMPPEvents.AUTHENTICATION_REQUIRED,
function () {
Moderator.allocateConferenceFocus(
roomName, callback);
});
}
return;
}
var waitMs = getNextErrorTimeout();
console.error("Focus error, retry after " + waitMs, error);
// Show message
UI.messageHandler.notify(
'Conference focus', 'disconnected',
Moderator.getFocusComponent() +
' not available - retry in ' +
(waitMs / 1000) + ' sec');
var focusComponent = Moderator.getFocusComponent();
var retrySec = waitMs / 1000;
// FIXME: message is duplicated ?
// Do not show in case of session invalid
// which means just a retry
if (!invalidSession) {
APP.UI.messageHandler.notify(
null, "notify.focus",
'disconnected', "notify.focusFail",
{component: focusComponent, ms: retrySec});
}
// Reset response timeout
getNextTimeout(true);
window.setTimeout(
@@ -238,28 +337,83 @@ var Moderator = {
);
},
getAuthUrl: function (roomName, urlCallback) {
getLoginUrl: function (roomName, urlCallback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
iq.c('auth-url', {
iq.c('login-url', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName
room: roomName,
'machine-uid': Settings.getSettings().uid
});
connection.sendIQ(
iq,
function (result) {
var url = $(result).find('auth-url').attr('url');
var url = $(result).find('login-url').attr('url');
url = url = decodeURIComponent(url);
if (url) {
console.info("Got auth url: " + url);
urlCallback(url);
} else {
console.error(
"Failed to get auth url fro mthe focus", result);
"Failed to get auth url from the focus", result);
}
},
function (error) {
console.error("Get auth url error", error);
}
);
},
getPopupLoginUrl: function (roomName, urlCallback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
iq.c('login-url', {
xmlns: 'http://jitsi.org/protocol/focus',
room: roomName,
'machine-uid': Settings.getSettings().uid,
popup: true
});
connection.sendIQ(
iq,
function (result) {
var url = $(result).find('login-url').attr('url');
url = url = decodeURIComponent(url);
if (url) {
console.info("Got POPUP auth url: " + url);
urlCallback(url);
} else {
console.error(
"Failed to get POPUP auth url from the focus", result);
}
},
function (error) {
console.error('Get POPUP auth url error', error);
}
);
},
logout: function (callback) {
var iq = $iq({to: Moderator.getFocusComponent(), type: 'set'});
var sessionId = localStorage.getItem('sessionId');
if (!sessionId) {
callback();
return;
}
iq.c('logout', {
xmlns: 'http://jitsi.org/protocol/focus',
'session-id': sessionId
});
connection.sendIQ(
iq,
function (result) {
var logoutUrl = $(result).find('logout').attr('logout-url');
if (logoutUrl) {
logoutUrl = decodeURIComponent(logoutUrl);
}
console.info("Log out OK, url: " + logoutUrl, result);
localStorage.removeItem('sessionId');
callback(logoutUrl);
},
function (error) {
console.error("Logout error", error);
}
);
}
};

View File

@@ -103,11 +103,13 @@ var Recording = {
return;
}
var self = this;
// Jirecon does not (currently) support a token.
if (!recordingToken && !useJirecon) {
tokenEmptyCallback(function (value) {
setRecordingToken(value);
this.toggleRecording();
self.toggleRecording(tokenEmptyCallback,
startingCallback, startedCallback, connection);
});
return;

View File

@@ -2,12 +2,12 @@
/* a simple MUC connection plugin
* can only handle a single MUC room
*/
var bridgeIsDown = false;
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var Moderator = require("./moderator");
var JingleSession = require("./JingleSession");
var bridgeIsDown = false;
module.exports = function(XMPP, eventEmitter) {
Strophe.addConnectionPlugin('emuc', {
connection: null,
@@ -183,8 +183,7 @@ module.exports = function(XMPP, eventEmitter) {
this.role = member.role;
eventEmitter.emit(XMPPEvents.LOCALROLE_CHANGED,
from, member, pres, Moderator.isModerator(),
Moderator.isExternalAuthEnabled());
from, member, pres, Moderator.isModerator());
}
if (!this.joined) {
this.joined = true;
@@ -230,6 +229,20 @@ module.exports = function(XMPP, eventEmitter) {
},
onPresenceUnavailable: function (pres) {
var from = pres.getAttribute('from');
// room destroyed ?
if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]' +
'>destroy').length) {
var reason;
var reasonSelect = $(pres).find(
'>x[xmlns="http://jabber.org/protocol/muc#user"]' +
'>destroy>reason');
if (reasonSelect.length) {
reason = reasonSelect.text();
}
XMPP.disposeConference(false);
eventEmitter.emit(XMPPEvents.MUC_DESTROYED, reason);
return true;
}
// Status code 110 indicates that this notification is "self-presence".
if (!$(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="110"]').length) {
delete this.members[from];
@@ -272,21 +285,18 @@ module.exports = function(XMPP, eventEmitter) {
// We're either missing Jicofo/Prosody config for anonymous
// domains or something is wrong.
// XMPP.promptLogin();
UI.messageHandler.openReportDialog(null,
'Oops ! We couldn`t join the conference.' +
' There might be some problem with security' +
' configuration. Please contact service' +
' administrator.', pres);
APP.UI.messageHandler.openReportDialog(null,
"dialog.joinError", pres);
} else {
console.warn('onPresError ', pres);
UI.messageHandler.openReportDialog(null,
'Oops! Something went wrong and we couldn`t connect to the conference.',
APP.UI.messageHandler.openReportDialog(null,
"dialog.connectError",
pres);
}
} else {
console.warn('onPresError ', pres);
UI.messageHandler.openReportDialog(null,
'Oops! Something went wrong and we couldn`t connect to the conference.',
APP.UI.messageHandler.openReportDialog(null,
"dialog.connectError",
pres);
}
return true;
@@ -570,7 +580,7 @@ module.exports = function(XMPP, eventEmitter) {
var self = this;
// Remove old ssrcs coming from the jid
Object.keys(this.ssrc2jid).forEach(function (ssrc) {
if (self.ssrc2jid[ssrc] == jid) {
if (self.ssrc2jid[ssrc] == from) {
delete self.ssrc2jid[ssrc];
}
});

View File

@@ -1,6 +1,8 @@
/* jshint -W117 */
var JingleSession = require("./JingleSession");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
module.exports = function(XMPP, eventEmitter)
{

View File

@@ -44,7 +44,7 @@ module.exports = function (XMPP) {
var mute = $(iq).find('mute');
if (mute.length) {
var doMuteAudio = mute.text() === "true";
UI.setAudioMuted(doMuteAudio);
APP.UI.setAudioMuted(doMuteAudio);
XMPP.forceMuted = doMuteAudio;
}
return true;

View File

@@ -3,6 +3,9 @@ var EventEmitter = require("events");
var Recording = require("./recording");
var SDP = require("./SDP");
var Pako = require("pako");
var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
var UIEvents = require("../../service/UI/UIEvents");
var XMPPEvents = require("../../service/xmpp/XMPPEvents");
var eventEmitter = new EventEmitter();
var connection = null;
@@ -10,26 +13,28 @@ var authenticatedUser = false;
function connect(jid, password, uiCredentials) {
var bosh
= uiCredentials.bosh || config.bosh || '/http-bind';
= (uiCredentials && uiCredentials.bosh? uiCredentials.bosh : null)
|| config.bosh || '/http-bind';
connection = new Strophe.Connection(bosh);
Moderator.setConnection(connection);
var settings = UI.getSettings();
var email = settings.email;
var displayName = settings.displayName;
if(email) {
connection.emuc.addEmailToPresence(email);
} else {
connection.emuc.addUserIdToPresence(settings.uid);
}
if(displayName) {
connection.emuc.addDisplayNameToPresence(displayName);
if(uiCredentials) {
var email = uiCredentials.email;
var displayName = uiCredentials.displayName;
if (email) {
connection.emuc.addEmailToPresence(email);
} else {
connection.emuc.addUserIdToPresence(uiCredentials.uid);
}
if (displayName) {
connection.emuc.addDisplayNameToPresence(displayName);
}
}
if (connection.disco) {
// for chrome, add multistream cap
}
connection.jingle.pc_constraints = RTC.getPCConstraints();
connection.jingle.pc_constraints = APP.RTC.getPCConstraints();
if (config.useIPv6) {
// https://code.google.com/p/webrtc/issues/detail?id=2828
if (!connection.jingle.pc_constraints.optional)
@@ -48,7 +53,7 @@ function connect(jid, password, uiCredentials) {
if (config.useStunTurn) {
connection.jingle.getStunAndTurnCredentials();
}
UI.disableConnect();
APP.UI.disableConnect();
console.info("My Jabber ID: " + connection.jid);
@@ -77,17 +82,17 @@ function connect(jid, password, uiCredentials) {
function maybeDoJoin() {
if (connection && connection.connected &&
Strophe.getResourceFromJid(connection.jid)
&& (RTC.localAudio || RTC.localVideo)) {
&& (APP.RTC.localAudio || APP.RTC.localVideo)) {
// .connected is true while connecting?
doJoin();
}
}
function doJoin() {
var roomName = UI.generateRoomName();
var roomName = APP.UI.generateRoomName();
Moderator.allocateConferenceFocus(
roomName, UI.checkForNicknameAndJoin);
roomName, APP.UI.checkForNicknameAndJoin);
}
function initStrophePlugins()
@@ -101,9 +106,9 @@ function initStrophePlugins()
}
function registerListeners() {
RTC.addStreamListener(maybeDoJoin,
APP.RTC.addStreamListener(maybeDoJoin,
StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
APP.UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
XMPP.addToPresence("displayName", nickname);
});
}
@@ -149,7 +154,7 @@ var XMPP = {
setupEvents();
initStrophePlugins();
registerListeners();
Moderator.init();
Moderator.init(this, eventEmitter);
var configDomain = config.hosts.anonymousdomain || config.hosts.domain;
// Force authenticated domain if room is appended with '?login=true'
if (config.hosts.anonymousdomain &&
@@ -160,7 +165,7 @@ var XMPP = {
connect(jid, null, uiCredentials);
},
promptLogin: function () {
UI.showLoginPopup(connect);
APP.UI.showLoginPopup(connect);
},
joinRoom: function(roomName, useNicks, nick)
{
@@ -200,11 +205,11 @@ var XMPP = {
if (handler && handler.peerconnection) {
// FIXME: probably removing streams is not required and close() should
// be enough
if (RTC.localAudio) {
handler.peerconnection.removeStream(RTC.localAudio.getOriginalStream(), onUnload);
if (APP.RTC.localAudio) {
handler.peerconnection.removeStream(APP.RTC.localAudio.getOriginalStream(), onUnload);
}
if (RTC.localVideo) {
handler.peerconnection.removeStream(RTC.localVideo.getOriginalStream(), onUnload);
if (APP.RTC.localVideo) {
handler.peerconnection.removeStream(APP.RTC.localVideo.getOriginalStream(), onUnload);
}
handler.peerconnection.close();
}
@@ -225,6 +230,12 @@ var XMPP = {
allocateConferenceFocus: function(roomName, callback) {
Moderator.allocateConferenceFocus(roomName, callback);
},
getLoginUrl: function (roomName, callback) {
Moderator.getLoginUrl(roomName, callback);
},
getPopupLoginUrl: function (roomName, callback) {
Moderator.getPopupLoginUrl(roomName, callback);
},
isModerator: function () {
return Moderator.isModerator();
},
@@ -240,20 +251,18 @@ var XMPP = {
connection.jingle.activecall.switchStreams(stream, oldStream, callback);
} else {
// We are done immediately
console.error("No conference handler");
UI.messageHandler.showError('Error',
'Unable to switch video stream.');
console.warn("No conference handler or conference not started yet");
callback();
}
},
setVideoMute: function (mute, callback, options) {
if(connection && RTC.localVideo && connection.jingle.activecall)
if(connection && APP.RTC.localVideo && connection.jingle.activecall)
{
connection.jingle.activecall.setVideoMute(mute, callback, options);
}
},
setAudioMute: function (mute, callback) {
if (!(connection && RTC.localAudio)) {
if (!(connection && APP.RTC.localAudio)) {
return false;
}
@@ -265,7 +274,7 @@ var XMPP = {
this.forceMuted = false;
}
if (mute == RTC.localAudio.isMuted()) {
if (mute == APP.RTC.localAudio.isMuted()) {
// Nothing to do
return true;
}
@@ -273,7 +282,7 @@ var XMPP = {
// It is not clear what is the right way to handle multiple tracks.
// So at least make sure that they are all muted or all unmuted and
// that we send presence just once.
RTC.localAudio.mute();
APP.RTC.localAudio.mute();
// isMuted is the opposite of audioEnabled
connection.emuc.addAudioInfoToPresence(mute);
connection.emuc.sendPresence();
@@ -303,23 +312,21 @@ var XMPP = {
},
function (error) {
console.log('mute SLD error');
UI.messageHandler.showError('Error',
'Oops! Something went wrong and we failed to ' +
'mute! (SLD Failure)');
APP.UI.messageHandler.showError("dialog.error",
"dialog.SLDFailure");
}
);
},
function (error) {
console.log(error);
UI.messageHandler.showError();
APP.UI.messageHandler.showError();
}
);
},
function (error) {
console.log('muteVideo SRD error');
UI.messageHandler.showError('Error',
'Oops! Something went wrong and we failed to stop video!' +
'(SRD Failure)');
APP.UI.messageHandler.showError("dialog.error",
"dialog.SRDFailure");
}
);
@@ -356,9 +363,15 @@ var XMPP = {
if(!dontSend)
connection.emuc.sendPresence();
},
/**
* Sends 'data' as a log message to the focus. Returns true iff a message
* was sent.
* @param data
* @returns {boolean} true iff a message was sent.
*/
sendLogs: function (data) {
if(!connection.emuc.focusMucJid)
return;
return false;
var deflate = true;
@@ -378,6 +391,7 @@ var XMPP = {
message.up();
connection.send(message);
return true;
},
populateData: function () {
var data = {};
@@ -416,6 +430,9 @@ var XMPP = {
eject: function (jid) {
connection.moderate.eject(jid);
},
logout: function (callback) {
Moderator.logout(callback);
},
findJidFromResource: function (resource) {
return connection.emuc.findJidFromResource(resource);
},
@@ -426,6 +443,12 @@ var XMPP = {
if(!connection)
return null;
return connection.emuc.ssrc2jid[ssrc];
},
getMUCJoined: function () {
return connection.emuc.joined;
},
getSessions: function () {
return connection.jingle.sessions;
}
};

View File

@@ -16,7 +16,9 @@
"readmeFilename": "README.md",
"dependencies": {
"events": "*",
"pako": "*"
"pako": "*",
"i18next-client": "*",
"sdp-interop": "jitsi/sdp-interop#f65fedfe57a"
},
"devDependencies": {
},

Some files were not shown because too many files have changed in this diff Show More