Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
652daab30f
2
Makefile
2
Makefile
|
@ -46,7 +46,7 @@ uglify:
|
|||
|
||||
source-package:
|
||||
mkdir -p source_package/jitsi-meet/css && \
|
||||
cp -r analytics.js external_api.js favicon.ico fonts images index.html interface_config.js libs plugin.*html sounds title.html unsupported_browser.html LICENSE config.js lang source_package/jitsi-meet && \
|
||||
cp -r *.js connection_optimization favicon.ico fonts images index.html libs plugin.*html sounds title.html unsupported_browser.html LICENSE lang source_package/jitsi-meet && \
|
||||
cp css/all.css source_package/jitsi-meet/css && \
|
||||
cp css/unsupported_browser.css source_package/jitsi-meet/css && \
|
||||
(cd source_package ; tar cjf ../jitsi-meet.tar.bz2 jitsi-meet) && \
|
||||
|
|
|
@ -126,15 +126,14 @@ function muteLocalVideo (muted) {
|
|||
* @param {boolean} [requestFeedback=false] if user feedback should be requested
|
||||
*/
|
||||
function hangup (requestFeedback = false) {
|
||||
let promise = Promise.resolve();
|
||||
|
||||
if (requestFeedback) {
|
||||
promise = APP.UI.requestFeedback();
|
||||
}
|
||||
|
||||
promise.then(function () {
|
||||
APP.conference._room.leave().then(() => {
|
||||
connection.disconnect();
|
||||
|
||||
if (requestFeedback) {
|
||||
return APP.UI.requestFeedback();
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}).then(function () {
|
||||
if (!config.enableWelcomePage) {
|
||||
return;
|
||||
}
|
||||
|
@ -475,20 +474,13 @@ export default {
|
|||
return this.audioLevelsMap[id];
|
||||
},
|
||||
/**
|
||||
* Will check for number of remote particiapnts that have at least one
|
||||
* remote track.
|
||||
* @return {boolean} whether we have enough participants with remote streams
|
||||
* @return {number} the number of participants in the conference with at
|
||||
* least one track.
|
||||
*/
|
||||
checkEnoughParticipants (number) {
|
||||
var participants = this._room.getParticipants();
|
||||
|
||||
var foundParticipants = 0;
|
||||
for (var i = 0; i < participants.length; i += 1) {
|
||||
if (participants[i].getTracks().length > 0) {
|
||||
foundParticipants++;
|
||||
}
|
||||
}
|
||||
return foundParticipants >= number;
|
||||
getNumberOfParticipantsWithTracks() {
|
||||
return this._room.getParticipants()
|
||||
.filter((p) => p.getTracks().length > 0)
|
||||
.length;
|
||||
},
|
||||
/**
|
||||
* Returns the stats.
|
||||
|
@ -565,6 +557,9 @@ export default {
|
|||
this.useAudioStream(track);
|
||||
} else if (track.isVideoTrack()) {
|
||||
this.useVideoStream(track);
|
||||
} else {
|
||||
console.error(
|
||||
"Ignored not an audio nor a video track: ", track);
|
||||
}
|
||||
});
|
||||
roomLocker = createRoomLocker(room);
|
||||
|
@ -753,18 +748,21 @@ export default {
|
|||
|
||||
|
||||
room.on(ConferenceEvents.USER_JOINED, (id, user) => {
|
||||
if (user.isHidden())
|
||||
return;
|
||||
|
||||
console.log('USER %s connnected', id, user);
|
||||
APP.API.notifyUserJoined(id);
|
||||
APP.UI.addUser(id, user.getDisplayName());
|
||||
|
||||
// chek the roles for the new user and reflect them
|
||||
// check the roles for the new user and reflect them
|
||||
APP.UI.updateUserRole(user);
|
||||
});
|
||||
room.on(ConferenceEvents.USER_LEFT, (id, user) => {
|
||||
console.log('USER %s LEFT', id, user);
|
||||
APP.API.notifyUserLeft(id);
|
||||
APP.UI.removeUser(id, user.getDisplayName());
|
||||
APP.UI.stopSharedVideo(id);
|
||||
APP.UI.onSharedVideoStop(id);
|
||||
});
|
||||
|
||||
|
||||
|
@ -1098,7 +1096,7 @@ export default {
|
|||
);
|
||||
|
||||
APP.UI.addListener(UIEvents.UPDATE_SHARED_VIDEO,
|
||||
(url, state, time, volume) => {
|
||||
(url, state, time, isMuted, volume) => {
|
||||
// send start and stop commands once, and remove any updates
|
||||
// that had left
|
||||
if (state === 'stop' || state === 'start' || state === 'playing') {
|
||||
|
@ -1108,6 +1106,7 @@ export default {
|
|||
attributes: {
|
||||
state: state,
|
||||
time: time,
|
||||
muted: isMuted,
|
||||
volume: volume
|
||||
}
|
||||
});
|
||||
|
@ -1121,6 +1120,7 @@ export default {
|
|||
attributes: {
|
||||
state: state,
|
||||
time: time,
|
||||
muted: isMuted,
|
||||
volume: volume
|
||||
}
|
||||
});
|
||||
|
@ -1130,13 +1130,23 @@ export default {
|
|||
this.commands.defaults.SHARED_VIDEO, ({value, attributes}, id) => {
|
||||
|
||||
if (attributes.state === 'stop') {
|
||||
APP.UI.stopSharedVideo(id, attributes);
|
||||
} else if (attributes.state === 'start') {
|
||||
APP.UI.showSharedVideo(id, value, attributes);
|
||||
} else if (attributes.state === 'playing'
|
||||
APP.UI.onSharedVideoStop(id, attributes);
|
||||
}
|
||||
else if (attributes.state === 'start') {
|
||||
APP.UI.onSharedVideoStart(id, value, attributes);
|
||||
}
|
||||
else if (attributes.state === 'playing'
|
||||
|| attributes.state === 'pause') {
|
||||
APP.UI.updateSharedVideo(id, value, attributes);
|
||||
APP.UI.onSharedVideoUpdate(id, value, attributes);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Adss any room listener.
|
||||
* @param eventName one of the ConferenceEvents
|
||||
* @param callBack the function to be called when the event occurs
|
||||
*/
|
||||
addConferenceListener(eventName, callBack) {
|
||||
room.on(eventName, callBack);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
|||
// When connection optimization is not deployed or enabled the default
|
||||
// value will be window.XMPPAttachInfo.status = "error"
|
||||
// If the connection optimization is deployed and enabled and there is
|
||||
// a failure the value will be window.XMPPAttachInfo.status = "error"
|
||||
// a failure the value will be window.XMPPAttachInfo.status = "error"
|
||||
if(window.XMPPAttachInfo.status === "error") {
|
||||
connection.connect({id, password});
|
||||
return;
|
||||
|
@ -31,6 +31,7 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
|||
var attachOptions = window.XMPPAttachInfo.data;
|
||||
if(attachOptions) {
|
||||
connection.attach(attachOptions);
|
||||
delete window.XMPPAttachInfo.data;
|
||||
} else {
|
||||
connection.connect({id, password});
|
||||
}
|
||||
|
@ -51,11 +52,11 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
|||
*/
|
||||
function connect(id, password, roomName) {
|
||||
|
||||
let connectionConfig = config;
|
||||
let connectionConfig = Object.assign({}, config);
|
||||
|
||||
connectionConfig.bosh += '?room=' + roomName;
|
||||
let connection
|
||||
= new JitsiMeetJS.JitsiConnection(null, config.token, config);
|
||||
= new JitsiMeetJS.JitsiConnection(null, config.token, connectionConfig);
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
connection.addEventListener(
|
||||
|
@ -95,13 +96,14 @@ function connect(id, password, roomName) {
|
|||
* Show Authentication Dialog and try to connect with new credentials.
|
||||
* If failed to connect because of PASSWORD_REQUIRED error
|
||||
* then ask for password again.
|
||||
* @param {string} [roomName]
|
||||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
function requestAuth() {
|
||||
function requestAuth(roomName) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let authDialog = LoginDialog.showAuthDialog(
|
||||
function (id, password) {
|
||||
connect(id, password).then(function (connection) {
|
||||
connect(id, password, roomName).then(function (connection) {
|
||||
authDialog.close();
|
||||
resolve(connection);
|
||||
}, function (err) {
|
||||
|
@ -131,6 +133,20 @@ function requestAuth() {
|
|||
* @returns {Promise<JitsiConnection>}
|
||||
*/
|
||||
export function openConnection({id, password, retry, roomName}) {
|
||||
|
||||
let usernameOverride
|
||||
= window.localStorage.getItem("xmpp_username_override");
|
||||
let passwordOverride
|
||||
= window.localStorage.getItem("xmpp_password_override");
|
||||
|
||||
if (usernameOverride && usernameOverride.length > 0) {
|
||||
id = usernameOverride;
|
||||
}
|
||||
|
||||
if (passwordOverride && passwordOverride.length > 0) {
|
||||
password = passwordOverride;
|
||||
}
|
||||
|
||||
return connect(id, password, roomName).catch(function (err) {
|
||||
if (!retry) {
|
||||
throw err;
|
||||
|
@ -141,7 +157,7 @@ export function openConnection({id, password, retry, roomName}) {
|
|||
if (config.token) {
|
||||
throw err;
|
||||
} else {
|
||||
return requestAuth();
|
||||
return requestAuth(roomName);
|
||||
}
|
||||
} else {
|
||||
throw err;
|
||||
|
|
|
@ -12,23 +12,16 @@
|
|||
* exrnal_connect.js.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the token from the URL.
|
||||
*/
|
||||
function buildToken(){
|
||||
var params = getConfigParamsFromUrl();
|
||||
return params["config.token"] || config.token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes createConnectionExternally function.
|
||||
*/
|
||||
(function () {
|
||||
// FIXME: Add implementation for changing that config from the url for
|
||||
// consistency
|
||||
var params = getConfigParamsFromUrl();
|
||||
|
||||
//Url params have higher proirity than config params
|
||||
var url = config.externalConnectUrl;
|
||||
if(params.hasOwnProperty('config.externalConnectUrl'))
|
||||
url = params["config.externalConnectUrl"];
|
||||
|
||||
/**
|
||||
* Check if connect from connection.js was executed and executes the handler
|
||||
|
@ -64,7 +57,7 @@ function buildToken(){
|
|||
|
||||
url += "?room=" + room_name;
|
||||
|
||||
var token = buildToken();
|
||||
var token = params["config.token"] || config.token;
|
||||
if(token)
|
||||
url += "&token=" + token;
|
||||
|
||||
|
|
|
@ -3,5 +3,8 @@
|
|||
"bg": "Български",
|
||||
"de": "Немски",
|
||||
"tr": "Турски",
|
||||
"it": "Италиански"
|
||||
"it": "Италиански",
|
||||
"fr": "Френски",
|
||||
"sl": "Словенски",
|
||||
"sk": "Словашки"
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
"it": "Italienisch",
|
||||
"fr": "Französisch",
|
||||
"sl": "Slowenisch",
|
||||
"sk": "Slowakisch"
|
||||
"sk": "Slowakisch",
|
||||
"sv": "Schwedisch"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"en": "Inglés",
|
||||
"bg": "Búlgaro",
|
||||
"de": "Alemán",
|
||||
"tr": "Turco",
|
||||
"it": "Italiano",
|
||||
"fr": "Francés",
|
||||
"sl": "Esloveno",
|
||||
"sk": "Eslovaco"
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"en": "",
|
||||
"bg": "",
|
||||
"de": "",
|
||||
"tr": "",
|
||||
"it": "",
|
||||
"fr": "",
|
||||
"sl": "",
|
||||
"sk": ""
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
"connectionsettings": "Настройки на връзката",
|
||||
"poweredby": "powered by",
|
||||
"downloadlogs": "Изтегли логовете",
|
||||
"feedback": "Кажете ни как върви",
|
||||
"roomUrlDefaultMsg": "Конференцията се създава...",
|
||||
"participant": "Участник",
|
||||
"me": "аз",
|
||||
|
@ -18,12 +19,12 @@
|
|||
"content": "Не е необходимо да сваляте нищо. _app_ работи директно във вашия браузър. Просто споделете адреса на вашата конференция с другите за да започнете."
|
||||
},
|
||||
"feature2": {
|
||||
"title": "",
|
||||
"title": "Нисък дебит",
|
||||
"content": "Видео конференциите могат да работят с по-малко от 128Kbps, а аудио конференциите и конференциите с споделен екран дори с по-малко."
|
||||
},
|
||||
"feature3": {
|
||||
"title": "Отворен код",
|
||||
"content": "__app__ е лицензиран под MIT лиценз. Можете свободно да го изтеглите, използвате, променяте и споделяте според тези лицензи."
|
||||
"content": "__app__ се разпространява под лицензе Apache. Свободни сте да го сваляте ползвате, променяте и споделяте спрямо правилата на лиценза."
|
||||
},
|
||||
"feature4": {
|
||||
"title": "Неограничен брой потребители",
|
||||
|
@ -48,21 +49,22 @@
|
|||
},
|
||||
"toolbar": {
|
||||
"mute": "Включи / Изключи микрофона",
|
||||
"videomute": "Спри / пусни камерата",
|
||||
"authenticate": "",
|
||||
"videomute": "Включи / Изключи камерата",
|
||||
"authenticate": "Идентификация",
|
||||
"record": "Запис",
|
||||
"lock": "Заключи / отключи стаята",
|
||||
"invite": "Поканване на други",
|
||||
"chat": "",
|
||||
"invite": "Покани други",
|
||||
"chat": "Отвори / затвори чат",
|
||||
"prezi": "Сподели Prezi",
|
||||
"etherpad": "Споделяне на документ",
|
||||
"sharescreen": "Споделяне на екрана",
|
||||
"etherpad": "Покажи споделения документ",
|
||||
"sharescreen": "Сподели екрана",
|
||||
"fullscreen": "Влез / Излез от Пълен екран",
|
||||
"sip": "Обади се на SIP номер",
|
||||
"Settings": "Настройки",
|
||||
"hangup": "Затвори",
|
||||
"login": "Влез",
|
||||
"logout": ""
|
||||
"logout": "Изход",
|
||||
"dialpad": "Цифров панел"
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "Отвори / затвори чат",
|
||||
|
@ -79,7 +81,9 @@
|
|||
"settings": {
|
||||
"title": "НАСТРОЙКИ",
|
||||
"update": "Актуализиране",
|
||||
"name": "Име"
|
||||
"name": "Име",
|
||||
"startAudioMuted": "започни без аудио",
|
||||
"startVideoMuted": "започни без видео"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"editnickname": "Натиснете за да<br/>промените името",
|
||||
|
@ -91,7 +95,7 @@
|
|||
"domute": "Изключи микрофона"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"bitrate": "",
|
||||
"bitrate": "Дебит:",
|
||||
"packetloss": "Загуба на пакети:",
|
||||
"resolution": "Резолюция:",
|
||||
"less": "Скрий",
|
||||
|
@ -106,7 +110,7 @@
|
|||
"remoteaddress": "Отдалечен адрес:",
|
||||
"remoteaddress_plural": "Отдалечени адреси:",
|
||||
"transport": "Транспорт:",
|
||||
"bandwidth": "",
|
||||
"bandwidth": "Оценка макс. дебит:",
|
||||
"na": "Върнете се тук за информацията относно вашата връзка, когато започне конференцията"
|
||||
},
|
||||
"notify": {
|
||||
|
@ -118,17 +122,19 @@
|
|||
"focus": "Конферентен фокус",
|
||||
"focusFail": "__component__ не е на раположения - следващ опит след __ms__ секунди",
|
||||
"grantedTo": "Даване на роля модератор на __to__!",
|
||||
"grantedToUnknown": "Даване на роля модератор на $t(somebody)!"
|
||||
"grantedToUnknown": "Даване на роля модератор на $t(somebody)!",
|
||||
"muted": "Започвате разговора без звук.",
|
||||
"mutedTitle": "Звукът ви е спрян!"
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "Бяхте изгонен от срещата!",
|
||||
"popupError": "Вашия браузър блокира попъп прозорците от този сайт. Моля позволете попъп прозорците от настройките на браузъра и опитайте пак.",
|
||||
"passwordError": "Тази конференция е защитена с парола. Само създателя и може да промени паролата.",
|
||||
"passwordError2": "Тази конференция не е защитена с парола. Само създателя и може да сложи парола.",
|
||||
"joinError": "Не можете да се присъедините към конференцията. Може би имате проблем с конфигурацията на сифурността. Моля обърнете се към администратора на услугата.",
|
||||
"popupError": "Навигаторът ви блокира попъите. Молим ви да премахнете забраната и да опитате отново.",
|
||||
"passwordError": "Стаята е защитена с парола. Само собственикът може да я променя или премахва.",
|
||||
"passwordError2": "Стаята ви не е защитена с парола. Собственикът би могъл да добави парола.",
|
||||
"connectError": "Опа! Нещо се обърка и не успяхме да се свържем с конференцията.",
|
||||
"connecting": "",
|
||||
"error": "",
|
||||
"connectErrorWithMsg": "Опа! Нещо се обърка и не успяхме да се свържем с конференцията: __msg__",
|
||||
"connecting": "Свързване",
|
||||
"error": "Грешка",
|
||||
"detectext": "Възникна грешка при опит да бъде намерено разширението за споделяне на екран.",
|
||||
"failtoinstall": "Неуспешна инсталация на разширението за споделяне на екрана.",
|
||||
"failedpermissions": "Неуспешен опит за получаване на права за използване на микрофон и/или камера.",
|
||||
|
@ -149,18 +155,18 @@
|
|||
"removePreziTitle": "Премахни Prezi",
|
||||
"removePreziMsg": "Сигурни ли сте, че искате да премахнете Prezi?",
|
||||
"sharePreziTitle": "Сподели Prezi",
|
||||
"sharePreziMsg": "Друг участник вече е споделил Prezi. Тази конференция позволява само да се споделя само едно Prezi.",
|
||||
"Remove": "Премахване",
|
||||
"Stop": "Спиране",
|
||||
"AuthMsg": "Нужна е идентификация, за да създадете стая:<br/><b>__room__</b></br> Може да се идентифицирате, за да създадете стая или да изчакате някой друг да го направи.",
|
||||
"Authenticate": "Идентификация",
|
||||
"sharePreziMsg": "Prezi string delete",
|
||||
"Remove": "DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE ",
|
||||
"WaitingForHost": "Чакаме домакина ...",
|
||||
"WaitForHostMsg": "<b>__room__ </b> още не е започнал. Ако вие сте домакина моля идентифицирайте се. В противен случай ще изчакаме домакина.",
|
||||
"IamHost": "Аз съм домакина",
|
||||
"Cancel": "Отказ",
|
||||
"retry": "Повторен опит",
|
||||
"logoutTitle": "Изход",
|
||||
"logoutQuestion": "Сигурни ли сте, че искате да излезете и да прекъснете конференцията?",
|
||||
"sessTerminated": "Сесията е прекъсната.",
|
||||
"hungUp": "Вие затворихте обаждането.",
|
||||
"joinAgain": "Песъединете се отново",
|
||||
"hungUp": "Затворихте",
|
||||
"joinAgain": "Присъединете се отново",
|
||||
"Share": "Споделяне",
|
||||
"preziLinkError": "Моля въведете правилен Prezi линк.",
|
||||
"Save": "Запазване",
|
||||
|
@ -183,11 +189,18 @@
|
|||
"reservationErrorMsg": "Грешка номер: __code__, съобщение: __msg__",
|
||||
"password": "парола",
|
||||
"userPassword": "потребителска парола",
|
||||
"token": "код за достъп"
|
||||
"token": "код за достъп",
|
||||
"tokenAuthFailed": "Неуспешна XMPP автентикация: невалиден тоукън",
|
||||
"displayNameRequired": "Въведете името си:",
|
||||
"extensionRequired": "Изисква се разширение: ",
|
||||
"firefoxExtensionPrompt": "За да споделите екрана си, трябва да инсталирате Firefox разширение. <a href='__url__'>свалете го тук</a> и пробвайте пак!",
|
||||
"feedbackQuestion": "Как мина разговора?",
|
||||
"thankYou": "Благодарим, че използвахте __appName__!",
|
||||
"sorryFeedback": "Много съжаляваме! Бихте ли ни казали повече?"
|
||||
},
|
||||
"email": {
|
||||
"sharedKey": [
|
||||
"Тази конференция е защитена с парола. Моля използвайте следния код за да се присъедините:",
|
||||
"Стаята е защитена с парола. Моля използвайте следния пин при влизане:",
|
||||
"",
|
||||
"",
|
||||
"__sharedKey__",
|
||||
|
@ -213,6 +226,7 @@
|
|||
"connection": {
|
||||
"ERROR": "Грешка",
|
||||
"CONNECTING": "Свързване",
|
||||
"RECONNECTING": "Появи се проблем с мрежата. Връзваме се наново...",
|
||||
"CONNFAIL": "Връзката е неуспешна",
|
||||
"AUTHENTICATING": "Идентификация",
|
||||
"AUTHFAIL": "Неуспешна идентификация",
|
||||
|
@ -220,5 +234,10 @@
|
|||
"DISCONNECTED": "Изключен",
|
||||
"DISCONNECTING": "Прекъсване на връзката",
|
||||
"ATTACHED": "Прикрепен"
|
||||
},
|
||||
"recording": {
|
||||
"toaster": "В момента записваме!",
|
||||
"pending": "Записът ви ще започне щом влезе втори участник",
|
||||
"on": "Записът започна"
|
||||
}
|
||||
}
|
|
@ -8,12 +8,12 @@
|
|||
"participant": "Teilnehmer",
|
||||
"me": "ich",
|
||||
"speaker": "Sprecher",
|
||||
"defaultNickname": "Bsp.: __name__",
|
||||
"defaultPreziLink": "Bsp.: __url__",
|
||||
"defaultNickname": "Bsp: Heidi Blau",
|
||||
"defaultLink": "Bsp.: __url__",
|
||||
"welcomepage": {
|
||||
"go": "Los",
|
||||
"roomname": "Raumnamen eingeben",
|
||||
"disable": "Diese Seite beim nächsten Betreten nicht mehr anzeigen",
|
||||
"disable": "Diesen Hinweis 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."
|
||||
|
@ -24,7 +24,7 @@
|
|||
},
|
||||
"feature3": {
|
||||
"title": "Open Source",
|
||||
"content": "__app__ steht unter der Apache Lizenz. Es steht ihnen frei __app__ gemäss dieser Lizenz herunterzuladen, zu verändern oder zu verbreiten."
|
||||
"content": "__app__ steht unter der Apache Lizenz. Es steht ihnen frei __app__ gemäß dieser Lizenz herunterzuladen, zu verändern oder zu verbreiten."
|
||||
},
|
||||
"feature4": {
|
||||
"title": "Unbegrenzte Anzahl Benutzer",
|
||||
|
@ -40,7 +40,7 @@
|
|||
},
|
||||
"feature7": {
|
||||
"title": "Freigegebene Notizen",
|
||||
"content": "__app__ verwendent Etherpad, ein Editor zur kollaborativen Bearbeitung von Texten."
|
||||
"content": "__app__ verwendet Etherpad, ein Editor zur kollaborativen Bearbeitung von Texten."
|
||||
},
|
||||
"feature8": {
|
||||
"title": "Benutzungsstatistiken",
|
||||
|
@ -51,12 +51,11 @@
|
|||
"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",
|
||||
"chat": "Chat öffnen / schließen",
|
||||
"etherpad": "Geteiltes Dokument",
|
||||
"sharedvideo": "Ein YouTube-Video teilen",
|
||||
"sharescreen": "Bildschirm freigeben",
|
||||
"fullscreen": "Vollbildmodus aktivieren / deaktivieren",
|
||||
"sip": "SIP Nummer anrufen",
|
||||
|
@ -64,12 +63,15 @@
|
|||
"hangup": "Auflegen",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"dialpad": "Tastenblock anzeigen"
|
||||
"dialpad": "Tastenblock anzeigen",
|
||||
"sharedVideoMutedPopup": "Das geteilte Video wurde stumm geschaltet damit mit <br/>den anderen Teilnehmern gesprochen werden kann.",
|
||||
"micMutedPopup": "Ihr Mikrofon wurde stumm geschaltet damit das<br/>geteilte Video genossen werden kann.",
|
||||
"unableToUnmutePopup": "Die Stummschaltung kann nicht aufgehoben werden während das geteilte Video abgespielt wird."
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "Chat öffnen / schliessen",
|
||||
"filmstrip": "Videovorschauen anzeigen / verstecken",
|
||||
"contactlist": "Kontaktliste öffnen / schliessen"
|
||||
"chat": "Chat öffnen / schließen",
|
||||
"filmstrip": "Videovorschau anzeigen / verstecken",
|
||||
"contactlist": "Kontaktliste öffnen / schließen"
|
||||
},
|
||||
"chat": {
|
||||
"nickname": {
|
||||
|
@ -83,10 +85,13 @@
|
|||
"update": "Aktualisieren",
|
||||
"name": "Name",
|
||||
"startAudioMuted": "Stumm beitreten",
|
||||
"startVideoMuted": "Ohne Video beitreten"
|
||||
"startVideoMuted": "Ohne Video beitreten",
|
||||
"selectCamera": "Kamera auswählen",
|
||||
"selectMic": "Mikrofon auswählen",
|
||||
"followMe": "Follow-me aktivieren"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"editnickname": "Klicken um den Anzeigenamen zu bearbeiten",
|
||||
"editnickname": "Klicken, um den Anzeigenamen zu bearbeiten",
|
||||
"moderator": "Besitzer dieser Konferenz",
|
||||
"videomute": "Teilnehmer hat die Kamera pausiert.",
|
||||
"mute": "Teilnehmer ist stumm geschaltet",
|
||||
|
@ -124,7 +129,7 @@
|
|||
"grantedTo": "Moderatorenrechte an __to__ vergeben.",
|
||||
"grantedToUnknown": "Moderatorenrechte an $t(somebody) vergeben.",
|
||||
"muted": "Der Konferenz wurde stumm beigetreten.",
|
||||
"mutedTitle": "Stummschaltung aktiv."
|
||||
"mutedTitle": "Stummschaltung aktiv!"
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "Oh! Sie wurden aus der Konferenz ausgeschlossen.",
|
||||
|
@ -137,8 +142,10 @@
|
|||
"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.",
|
||||
"failedpermissions": "Die Zugriffsberechtigungen auf das Mikrofon und/oder die Kamera konnten nicht eingeholt werden.",
|
||||
"bridgeUnavailable": "Die Jitsi Videobridge ist momentan nicht erreichbar. Bitte versuchen Sie es später noch einmal.",
|
||||
"jicofoUnavailable": "Jicofo ist momentan nicht erreichbar. Bitte versuchen Sie es später noch einmal.",
|
||||
"maxUsersLimitReached": "Die maximale Teilnehmerzahl dieser Konferenz ist erreicht. Die Konferenz ist voll. Bitte versuchen Sie es später noch einmal.",
|
||||
"lockTitle": "Sperren fehlgeschlagen",
|
||||
"lockMessage": "Die Konferenz konnte nicht gesperrt werden.",
|
||||
"warning": "Warnung",
|
||||
|
@ -152,34 +159,35 @@
|
|||
"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",
|
||||
"shareVideoTitle": "Video teilen",
|
||||
"shareVideoLinkError": "Bitte einen gültigen YouTube-Link angeben.",
|
||||
"removeSharedVideoTitle": "Freigegebenes Video entfernen",
|
||||
"removeSharedVideoMsg": "Sind Sie sicher dass Sie das geteilte Video entfernen möchten?",
|
||||
"alreadySharedVideoMsg": "Ein anderer Teilnehmer teilt bereits ein Video. Diese Konferenz ermöglicht nur ein freigegebenes Video auf einmal.",
|
||||
"WaitingForHost": "Warten auf den Organisator...",
|
||||
"WaitForHostMsg": "Die Konferenz <b>__room__</b> hat noch nicht begonnen. Wenn Sie der Organisator sind, melden Sie sich bitte an. Anderenfalls warten Sie bitte bis der Organisator beigetreten ist.",
|
||||
"WaitForHostMsg": "Die Konferenz <b>__room__</b> hat noch nicht begonnen. Wenn Sie der Organisator sind, melden Sie sich bitte an. Anderenfalls warten Sie bitte, bis der Organisator beigetreten ist.",
|
||||
"IamHost": "Ich bin der Organisator",
|
||||
"Cancel": "Abbrechen",
|
||||
"retry": "Wiederholen",
|
||||
"logoutTitle": "Abmelden",
|
||||
"logoutQuestion": "Sind Sie sicher dass Sie sich abmelden und die Konferenz verlassen möchten?",
|
||||
"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",
|
||||
"recording": "",
|
||||
"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",
|
||||
"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:",
|
||||
"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",
|
||||
|
@ -191,16 +199,24 @@
|
|||
"userPassword": "Benutzerpasswort",
|
||||
"token": "Token",
|
||||
"tokenAuthFailed": "Anmeldung am XMPP-Server fehlgeschlagen: ungültiges Token",
|
||||
"displayNameRequired": "Geben Sie Ihren Anzeigenamen ein:",
|
||||
"displayNameRequired": "Geben Sie Ihren Anzeigenamen ein",
|
||||
"extensionRequired": "Erweiterung erforderlich:",
|
||||
"firefoxExtensionPrompt": "Um die Bildschirmfreigabe nutzen zu können, muss eine Firefox-Erweiterung installiert werden. Bitte versuchen Sie es erneut nachdem die <a href='__url__'>Erweiterung installiert</a> wurde.",
|
||||
"feedbackQuestion": "Wie war der Anruf?",
|
||||
"thankYou": "Danke für die Verwendung von __appName__!",
|
||||
"sorryFeedback": "Tut uns leid. Möchten Sie uns mehr mitteilen?"
|
||||
"sorryFeedback": "Tut uns leid. Möchten Sie uns mehr mitteilen?",
|
||||
"liveStreaming": "",
|
||||
"streamKey": "Streamname/-schlüssel",
|
||||
"startLiveStreaming": "Live-Streaming starten",
|
||||
"stopStreamingWarning": "Sind Sie sicher dass Sie das Live-Streaming stoppen möchten?",
|
||||
"stopRecordingWarning": "Sind Sie sicher dass Sie die Aufnahme stoppen möchten?",
|
||||
"stopLiveStreaming": "Live-Streaming stoppen",
|
||||
"stopRecording": "Aufnahme stoppen"
|
||||
},
|
||||
"\u0005dialog": {},
|
||||
"email": {
|
||||
"sharedKey": [
|
||||
"Diese Konferenz ist Passwortgeschützt. Bitte verwenden Sie diese PIN zum Beitreten:",
|
||||
"Diese Konferenz ist passwortgeschützt. Bitte verwenden Sie diese PIN zum Beitreten:",
|
||||
"",
|
||||
"",
|
||||
"__sharedKey__",
|
||||
|
@ -215,7 +231,7 @@
|
|||
"Ich möchte dich zu einer eben erstellten __appName__-Konferenz einladen.",
|
||||
"",
|
||||
"",
|
||||
"Bitte klicke auf den folgenden Link um der Konferenz ebenfalls beizutreten:",
|
||||
"Bitte klicke auf den folgenden Link, um der Konferenz ebenfalls beizutreten:",
|
||||
"",
|
||||
"",
|
||||
"__roomUrl__",
|
||||
|
@ -242,8 +258,19 @@
|
|||
"ATTACHED": "Angehängt"
|
||||
},
|
||||
"recording": {
|
||||
"toaster": "Wird aufgezeichnet",
|
||||
"pending": "Die Aufzeichnung wird gestartet sobald ein weiterer Teilnehmer beitritt",
|
||||
"on": "Aufzeichnung wurde gestartet"
|
||||
"pending": "Die Aufnahme wartet auf den Beitritt eines Teilnehmers...",
|
||||
"on": "Aufnahme",
|
||||
"off": "Aufnahme gestoppt",
|
||||
"failedToStart": "Die Aufnahme konnte nicht gestartet werden",
|
||||
"buttonTooltip": "Aufnahme starten / stoppen"
|
||||
},
|
||||
"liveStreaming": {
|
||||
"pending": "Live-Stream wird gestartet...",
|
||||
"on": "Live-Streaming",
|
||||
"off": "Live-Streaming gestoppt",
|
||||
"unavailable": "Der Live-Streaming Dienst ist momentan nicht verfügbar. Bitte versuchen Sie es später noch einmal.",
|
||||
"failedToStart": "Live-Streaming konnte nicht gestartet werden",
|
||||
"buttonTooltip": "Live-Stream starten / stoppen",
|
||||
"streamIdRequired": "Bitte Stream-ID eingeben um das Live-Streaming zu starten."
|
||||
}
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
{
|
||||
"contactlist": "LISTA DE CONTACTOS",
|
||||
"connectionsettings": "Ajustes de la conexión",
|
||||
"poweredby": "impulsado por",
|
||||
"downloadlogs": "Descargar bitácora",
|
||||
"feedback": "Danos tu opinión",
|
||||
"roomUrlDefaultMsg": "Tu conferencia está siendo creada...",
|
||||
"participant": "Participante",
|
||||
"me": "yo",
|
||||
"speaker": "Orador",
|
||||
"defaultNickname": "ej. __name__",
|
||||
"defaultPreziLink": "ej. __url__",
|
||||
"welcomepage": {
|
||||
"go": "IR",
|
||||
"roomname": "Introduzca un nombre de sala:",
|
||||
"disable": "No mostrar esta página en el próximo acceso ",
|
||||
"feature1": {
|
||||
"title": "Sencillo de usar",
|
||||
"content": "No se requiere descargar nada. __app__ funciona directamente con tu navegador. Solo comparte el URL de tu conferencia con otros para comenzar."
|
||||
},
|
||||
"feature2": {
|
||||
"title": "Bajo Ancho de Banda",
|
||||
"content": "Videoconferencias con múltiples participantes con tan poco como 128 Kbps. Conferencias compartiendo pantalla y audio con mucho menos."
|
||||
},
|
||||
"feature3": {
|
||||
"title": "Código abierto",
|
||||
"content": "__app__ está licenciado bajo la licencia Apache. Eres libre de descargar, usar, modificar, y compartirlo conforme a esta licencia libre."
|
||||
},
|
||||
"feature4": {
|
||||
"title": "Usuarios ilimitados",
|
||||
"content": "No hay restricciones artificiales en el número de usuarios o participantes de la conferencia. La capacidad del servidor y ancho de banda son los únicos factores limitantes."
|
||||
},
|
||||
"feature5": {
|
||||
"title": "Compartir pantalla",
|
||||
"content": "Es fácil de compartir su pantalla con otros. __app__ es ideal para presentaciones en línea, conferencias y sesiones de soporte técnico. "
|
||||
},
|
||||
"feature6": {
|
||||
"title": "Salas seguras",
|
||||
"content": "¿Necesita un poco de privacidad? Las salas de conferencias __app__ se pueden asegurar con una contraseña con el fin de excluir a los invitados no deseados y evitar interrupciones."
|
||||
},
|
||||
"feature7": {
|
||||
"title": "Notas compartidas",
|
||||
"content": "__app__ incluye Etherpad, un editor de texto colaborativo, en tiempo real, que es genial para minutas de junta, redactar artículos, y más."
|
||||
},
|
||||
"feature8": {
|
||||
"title": "Estadísticas de uso",
|
||||
"content": "Conozca acerca de sus usuarios a través de una fácil integración con Piwik, Google Analytics, y otros sistemas de seguimiento y análisis de uso."
|
||||
}
|
||||
},
|
||||
"toolbar": {
|
||||
"mute": "Silenciar / Activar",
|
||||
"videomute": "Iniciar / detener cámara",
|
||||
"authenticate": "Autenticar",
|
||||
"record": "Grabar",
|
||||
"lock": "Bloquear / desbloquear sala",
|
||||
"invite": "Invitar a otros",
|
||||
"chat": "",
|
||||
"prezi": "Compartir Prezi",
|
||||
"etherpad": "Compartir Documento",
|
||||
"sharescreen": "Compartir pantalla",
|
||||
"fullscreen": "Entrar / Salir de Pantalla completa",
|
||||
"sip": "Llamar a un número SIP",
|
||||
"Settings": "Ajustes",
|
||||
"hangup": "Colgar",
|
||||
"login": "Inicio de sesión",
|
||||
"logout": "",
|
||||
"dialpad": "Mostrar teclado de llamada"
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "Abrir / cerrar chat",
|
||||
"filmstrip": "Mostrar / ocultar film",
|
||||
"contactlist": "Abrir / cerrar lista de contactos"
|
||||
},
|
||||
"chat": {
|
||||
"nickname": {
|
||||
"title": "Indique un nombre en la caja inferior",
|
||||
"popover": "Seleccione un nombre"
|
||||
},
|
||||
"messagebox": "Introduzca texto..."
|
||||
},
|
||||
"settings": {
|
||||
"title": "CONFIGURAR",
|
||||
"update": "Actualizar",
|
||||
"name": "Nombre",
|
||||
"startAudioMuted": "iniciar sin audio",
|
||||
"startVideoMuted": "iniciar sin video"
|
||||
},
|
||||
"videothumbnail": {
|
||||
"editnickname": "Pica para editar tu <br/>nombre",
|
||||
"moderator": "El dueño de<br/>esta conferencia",
|
||||
"videomute": "Participante ha<br/>detenido la cámara.",
|
||||
"mute": "Participante está silenciado",
|
||||
"kick": "Expulsar",
|
||||
"muted": "Silenciado",
|
||||
"domute": "Silenciar"
|
||||
},
|
||||
"connectionindicator": {
|
||||
"bitrate": "Frecuencia de bits:",
|
||||
"packetloss": "Pérdida de paquetes:",
|
||||
"resolution": "Resolución:",
|
||||
"less": "Mostrar menos",
|
||||
"more": "Ver más",
|
||||
"address": "Dirección:",
|
||||
"remoteport": "Puerto remoto:",
|
||||
"remoteport_plural": "Puertos remotos:",
|
||||
"localport": "Puerto local:",
|
||||
"localport_plural": "Puertos locales:",
|
||||
"localaddress": "Dirección local:",
|
||||
"localaddress_plural": "Direcciones locales:",
|
||||
"remoteaddress": "Dirección remota:",
|
||||
"remoteaddress_plural": "Direcciones remotas:",
|
||||
"transport": "Transporte:",
|
||||
"bandwidth": "Ancho de banda estimado:",
|
||||
"na": "Volver aquí por información de la conexión, una vez que se inicia la conferencia"
|
||||
},
|
||||
"notify": {
|
||||
"disconnected": "desconectado",
|
||||
"moderator": "¡Otorgados derechos de moderador! ",
|
||||
"connected": "conectado",
|
||||
"somebody": "Alguien",
|
||||
"me": "Yo",
|
||||
"focus": "Foco de conferencia",
|
||||
"focusFail": "__component__ not available - retry en __ms__ sec",
|
||||
"grantedTo": "¡Derechos de moderador otorgados a __to__!",
|
||||
"grantedToUnknown": "¡Derechos de moderador otorgados a $t(somebody)!",
|
||||
"muted": "Haz iniciado la conversación silenciado.",
|
||||
"mutedTitle": "¡Estás silenciado!"
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "¡Auch! ¡Haz sido expulsado de la reunión!",
|
||||
"popupError": "Tu navegador está bloqueando las ventanas emergentes de este sitio. Por favor, activa las ventanas emergentes en la configuración de seguridad de su navegador y vuelva a intentarlo.",
|
||||
"passwordError": "Esta conversación está protegido con una contraseña. Sólo el propietario de la conferencia puede establecer una contraseña.",
|
||||
"passwordError2": "Esta conversación está protegido con una contraseña. Sólo el propietario de la conferencia puede establecer una contraseña.",
|
||||
"connectError": "¡Uups! Algo salió mal y no pudimos conectarnos a la conferencia.",
|
||||
"connectErrorWithMsg": "¡Uups! Algo salió mal y no pudimos conectarnos a la conferencia: __msg__",
|
||||
"connecting": "",
|
||||
"error": "",
|
||||
"detectext": "Error al tratar de detectar la extensión de compartir escritorio.",
|
||||
"failtoinstall": "Fallo al instalar la extensión de compartir escritorio",
|
||||
"failedpermissions": "Fallo al obtener permisos para utilizar el micrófono y/o cámara de tu equipo.",
|
||||
"bridgeUnavailable": "Videobridge Jitsi no está actualmente disponible. ¡Por favor intente después!",
|
||||
"lockTitle": "Fallo al bloquear",
|
||||
"lockMessage": "No se pudo bloquear la conferencia.",
|
||||
"warning": "Advertencia",
|
||||
"passwordNotSupported": "No se soportan contraseñas para la sala. ",
|
||||
"sorry": "¡Perdón!",
|
||||
"internalError": "Error interno de la aplicación [setRemoteDescription]",
|
||||
"unableToSwitch": "No se puede activar transmisión de video",
|
||||
"SLDFailure": "¡Ups! Algo salió mal y no se logró silenciar! (Falla de SLD)",
|
||||
"SRDFailure": "¡Ups! ¡Algo salió mal y no se logró detener el video! (Falla SRD)",
|
||||
"oops": "¡Ups!",
|
||||
"defaultError": "Hubo algún tipo de error",
|
||||
"passwordRequired": "Se necesita contraseña",
|
||||
"Ok": "Aceptar",
|
||||
"removePreziTitle": "Eliminar Prezi",
|
||||
"removePreziMsg": "¿Estas seguro que deseas eliminar tu Prezi?",
|
||||
"sharePreziTitle": "Compartir un Prezi",
|
||||
"sharePreziMsg": "Otro participante ya está compartiendo un Prezi. Esta conferencia permite sólo un Prezi a la vez.",
|
||||
"Remove": "Eliminar",
|
||||
"WaitingForHost": "Esperando al anfitrión...",
|
||||
"WaitForHostMsg": "La conferencia <b>__room__ </b> aún no inicia. Si usted es el anfitrión, por favor autentíquese. De lo contrario, por favor espere a que el anfitrión llegue.",
|
||||
"IamHost": "Yo soy el anfitrión",
|
||||
"Cancel": "Cancelar",
|
||||
"retry": "Reintentar",
|
||||
"logoutTitle": "Cerrar sesión",
|
||||
"logoutQuestion": "¿Está seguro que quiere salir y detener la conferencia?",
|
||||
"sessTerminated": "Sesión finalizada",
|
||||
"hungUp": "Colgaste",
|
||||
"joinAgain": "Unirse de nuevo",
|
||||
"Share": "Compartir",
|
||||
"preziLinkError": "Por favor indique una liga Prezi correcta. ",
|
||||
"Save": "Guardar",
|
||||
"recordingToken": "Introduzca el token de grabación",
|
||||
"Dial": "Marcar",
|
||||
"sipMsg": "Introduzca número SIP",
|
||||
"passwordCheck": "¿Realmente quieres eliminar tu contraseña?",
|
||||
"passwordMsg": "Indica una contraseña para bloquear tu sala",
|
||||
"Invite": "Invitar",
|
||||
"shareLink": "Comparte este enlace con las personas que deseas invitar",
|
||||
"settings1": "Configure su conferencia",
|
||||
"settings2": "Los participantes se unieron silenciados",
|
||||
"settings3": "Solicita nombres <br/> <br/>Establecer una contraseña para bloquear la sala:",
|
||||
"yourPassword": "tu contraseña",
|
||||
"Back": "Atrás",
|
||||
"serviceUnavailable": "Servicio no disponible",
|
||||
"gracefulShutdown": "Nuestro servicio está detenido por mantenimiento. Por favor, inténtelo de nuevo más tarde.",
|
||||
"Yes": "Sí",
|
||||
"reservationError": "Error de sistema de reservación",
|
||||
"reservationErrorMsg": "Código de error: __code__, message: __msg__",
|
||||
"password": "contraseña",
|
||||
"userPassword": "contraseña de usuario",
|
||||
"token": "token",
|
||||
"tokenAuthFailed": "Error al autenticar con el servidor XMPP: token inválido",
|
||||
"displayNameRequired": "Por favor escriba su nombre",
|
||||
"extensionRequired": "Extensión requerida",
|
||||
"firefoxExtensionPrompt": "Es necesario instalar una extensión para Firefox con el fin de utilizar la pantalla compartida. Por favor, inténtelo de nuevo después de que lo obtenga de aquí <a href='__url__'> </a>!",
|
||||
"feedbackQuestion": "¿Como fue su llamada?",
|
||||
"thankYou": "Gracias por usar __appName__!",
|
||||
"sorryFeedback": " Sentimos escuchar eso. ¿Quieres decirnos algo más?"
|
||||
},
|
||||
"email": {
|
||||
"sharedKey": [
|
||||
"Esta conferencia está protegida con contraseña. Utiliza el siguiente pin cuando te unas: ",
|
||||
"",
|
||||
"",
|
||||
"__sharedKey__",
|
||||
"",
|
||||
""
|
||||
],
|
||||
"subject": "Invitación a a __appName__ (__conferenceName__)",
|
||||
"body": [
|
||||
"Ey allí, quiero invitarte a una a conferencia __appName__ que acabo de crear.",
|
||||
"",
|
||||
"",
|
||||
"Por favor pica en la liga siguiente para unirte a la conferencia.",
|
||||
"",
|
||||
"",
|
||||
"__roomUrl__",
|
||||
"",
|
||||
"",
|
||||
"__sharedKeyText__",
|
||||
"Nota que __appName__ es soportada solo por __supportedBrowsers__, por lo que debes usar uno de esos navegadores.",
|
||||
"",
|
||||
"",
|
||||
"Talk to you in a sec!"
|
||||
],
|
||||
"and": "y"
|
||||
},
|
||||
"connection": {
|
||||
"ERROR": "Error",
|
||||
"CONNECTING": "Conectando",
|
||||
"RECONNECTING": "Ocurrió un problema en la red. Reconectando ...",
|
||||
"CONNFAIL": "Conexión fallida",
|
||||
"AUTHENTICATING": "Autenticando",
|
||||
"AUTHFAIL": "Falló la autenticación",
|
||||
"CONNECTED": "Conectado",
|
||||
"DISCONNECTED": "Desconectado",
|
||||
"DISCONNECTING": "Desconectando",
|
||||
"ATTACHED": "Adjunto"
|
||||
},
|
||||
"recording": {
|
||||
"toaster": "¡Actualmente Grabando! ",
|
||||
"pending": "Tu grabación se iniciará tan pronto como otro participante se una",
|
||||
"on": "La grabación ha iniciado"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
{
|
||||
"contactlist": "",
|
||||
"connectionsettings": "",
|
||||
"poweredby": "",
|
||||
"downloadlogs": "",
|
||||
"feedback": "",
|
||||
"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": "",
|
||||
"dialpad": ""
|
||||
},
|
||||
"bottomtoolbar": {
|
||||
"chat": "",
|
||||
"filmstrip": "",
|
||||
"contactlist": ""
|
||||
},
|
||||
"chat": {
|
||||
"nickname": {
|
||||
"title": "",
|
||||
"popover": ""
|
||||
},
|
||||
"messagebox": ""
|
||||
},
|
||||
"settings": {
|
||||
"title": "",
|
||||
"update": "",
|
||||
"name": "",
|
||||
"startAudioMuted": "",
|
||||
"startVideoMuted": ""
|
||||
},
|
||||
"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": "",
|
||||
"muted": "",
|
||||
"mutedTitle": ""
|
||||
},
|
||||
"dialog": {
|
||||
"kickMessage": "",
|
||||
"popupError": "",
|
||||
"passwordError": "",
|
||||
"passwordError2": "",
|
||||
"connectError": "",
|
||||
"connectErrorWithMsg": "",
|
||||
"connecting": "",
|
||||
"error": "",
|
||||
"detectext": "",
|
||||
"failtoinstall": "",
|
||||
"failedpermissions": "",
|
||||
"bridgeUnavailable": "",
|
||||
"lockTitle": "",
|
||||
"lockMessage": "",
|
||||
"warning": "",
|
||||
"passwordNotSupported": "",
|
||||
"sorry": "",
|
||||
"internalError": "",
|
||||
"unableToSwitch": "",
|
||||
"SLDFailure": "",
|
||||
"SRDFailure": "",
|
||||
"oops": "",
|
||||
"defaultError": "",
|
||||
"passwordRequired": "",
|
||||
"Ok": "",
|
||||
"removePreziTitle": "",
|
||||
"removePreziMsg": "",
|
||||
"sharePreziTitle": "",
|
||||
"sharePreziMsg": "",
|
||||
"Remove": "",
|
||||
"WaitingForHost": "",
|
||||
"WaitForHostMsg": "",
|
||||
"IamHost": "",
|
||||
"Cancel": "",
|
||||
"retry": "",
|
||||
"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": "",
|
||||
"tokenAuthFailed": "",
|
||||
"displayNameRequired": "",
|
||||
"extensionRequired": "",
|
||||
"firefoxExtensionPrompt": "",
|
||||
"feedbackQuestion": "",
|
||||
"thankYou": "",
|
||||
"sorryFeedback": ""
|
||||
},
|
||||
"email": {
|
||||
"sharedKey": "",
|
||||
"subject": "",
|
||||
"body": "",
|
||||
"and": ""
|
||||
},
|
||||
"connection": {
|
||||
"ERROR": "",
|
||||
"CONNECTING": "",
|
||||
"RECONNECTING": "",
|
||||
"CONNFAIL": "",
|
||||
"AUTHENTICATING": "",
|
||||
"AUTHFAIL": "",
|
||||
"CONNECTED": "",
|
||||
"DISCONNECTED": "",
|
||||
"DISCONNECTING": "",
|
||||
"ATTACHED": ""
|
||||
},
|
||||
"recording": {
|
||||
"toaster": "",
|
||||
"pending": "",
|
||||
"on": ""
|
||||
}
|
||||
}
|
|
@ -130,7 +130,7 @@ function processMessage(event) {
|
|||
*/
|
||||
function isEnabled () {
|
||||
let hash = location.hash;
|
||||
return hash && hash.indexOf("external") > -1 && window.postMessage;
|
||||
return hash && hash.indexOf("external=true") > -1 && window.postMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,6 @@ var JitsiPopover = require("./util/JitsiPopover");
|
|||
var Feedback = require("./Feedback");
|
||||
|
||||
import FollowMe from "../FollowMe";
|
||||
import Recorder from "../recorder/Recorder";
|
||||
|
||||
var eventEmitter = new EventEmitter();
|
||||
UI.eventEmitter = eventEmitter;
|
||||
|
@ -242,11 +241,6 @@ UI.initConference = function () {
|
|||
//if local role changes buttons state will be again updated
|
||||
UI.updateLocalRole(false);
|
||||
|
||||
// Initialise the recorder handler. We're doing this explicitly before
|
||||
// calling showToolbar, because the recorder may want to disable all
|
||||
// toolbars.
|
||||
new Recorder(APP.conference);
|
||||
|
||||
// Once we've joined the muc show the toolbar
|
||||
ToolbarToggler.showToolbar();
|
||||
|
||||
|
@ -1122,9 +1116,9 @@ UI.updateDevicesAvailability = function (id, devices) {
|
|||
* @param {string} url video url
|
||||
* @param {string} attributes
|
||||
*/
|
||||
UI.showSharedVideo = function (id, url, attributes) {
|
||||
UI.onSharedVideoStart = function (id, url, attributes) {
|
||||
if (sharedVideoManager)
|
||||
sharedVideoManager.showSharedVideo(id, url, attributes);
|
||||
sharedVideoManager.onSharedVideoStart(id, url, attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1133,9 +1127,9 @@ UI.showSharedVideo = function (id, url, attributes) {
|
|||
* @param {string} url video url
|
||||
* @param {string} attributes
|
||||
*/
|
||||
UI.updateSharedVideo = function (id, url, attributes) {
|
||||
UI.onSharedVideoUpdate = function (id, url, attributes) {
|
||||
if (sharedVideoManager)
|
||||
sharedVideoManager.updateSharedVideo(id, url, attributes);
|
||||
sharedVideoManager.onSharedVideoUpdate(id, url, attributes);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1143,9 +1137,9 @@ UI.updateSharedVideo = function (id, url, attributes) {
|
|||
* @param {string} id the id of the sender of the command
|
||||
* @param {string} attributes
|
||||
*/
|
||||
UI.stopSharedVideo = function (id, attributes) {
|
||||
UI.onSharedVideoStop = function (id, attributes) {
|
||||
if (sharedVideoManager)
|
||||
sharedVideoManager.stopSharedVideo(id, attributes);
|
||||
sharedVideoManager.onSharedVideoStop(id, attributes);
|
||||
};
|
||||
|
||||
module.exports = UI;
|
||||
|
|
|
@ -16,6 +16,11 @@
|
|||
*/
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
import UIUtil from '../util/UIUtil';
|
||||
import VideoLayout from '../videolayout/VideoLayout';
|
||||
import Feedback from '../Feedback.js';
|
||||
import Toolbar from '../toolbars/Toolbar';
|
||||
import BottomToolbar from '../toolbars/BottomToolbar';
|
||||
|
||||
|
||||
/**
|
||||
* Indicates if the recording button should be enabled.
|
||||
|
@ -218,6 +223,17 @@ var Recording = {
|
|||
this.currentState = Status.UNAVAILABLE;
|
||||
|
||||
this.initRecordingButton(recordingType);
|
||||
|
||||
// If I am a recorder then I publish my recorder custom role to notify
|
||||
// everyone.
|
||||
if (config.iAmRecorder) {
|
||||
VideoLayout.enableDeviceAvailabilityIcons(
|
||||
APP.conference.localId, false);
|
||||
VideoLayout.setLocalVideoVisible(false);
|
||||
Feedback.enableFeedback(false);
|
||||
Toolbar.enable(false);
|
||||
BottomToolbar.enable(false);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,12 +30,18 @@ export default class SharedVideoManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Indicates if the player volume is currently on.
|
||||
* Indicates if the player volume is currently on. This will return true if
|
||||
* we have an available player, which is currently in a PLAYING state,
|
||||
* which isn't muted and has it's volume greater than 0.
|
||||
*
|
||||
* @returns {*|player|boolean}
|
||||
* @returns {boolean} indicating if the volume of the shared video is
|
||||
* currently on.
|
||||
*/
|
||||
isSharedVideoVolumeOn() {
|
||||
return (this.player && this.player.getVolume() > 0);
|
||||
return (this.player
|
||||
&& this.player.getPlayerState() === YT.PlayerState.PLAYING
|
||||
&& !this.player.isMuted()
|
||||
&& this.player.getVolume() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,13 +79,14 @@ export default class SharedVideoManager {
|
|||
}
|
||||
|
||||
/**
|
||||
* Shows the player component and starts the checking function
|
||||
* that will be sending updates, if we are the one shared the video
|
||||
* Shows the player component and starts the process that will be sending
|
||||
* updates, if we are the one shared the video.
|
||||
*
|
||||
* @param id the id of the sender of the command
|
||||
* @param url the video url
|
||||
* @param attributes
|
||||
*/
|
||||
showSharedVideo (id, url, attributes) {
|
||||
onSharedVideoStart (id, url, attributes) {
|
||||
if (this.isSharedVideoShown)
|
||||
return;
|
||||
|
||||
|
@ -91,8 +98,10 @@ export default class SharedVideoManager {
|
|||
// the owner of the video
|
||||
this.from = id;
|
||||
|
||||
this.mutedWithUserInteraction = APP.conference.isLocalAudioMuted();
|
||||
|
||||
//listen for local audio mute events
|
||||
this.localAudioMutedListener = this.localAudioMuted.bind(this);
|
||||
this.localAudioMutedListener = this.onLocalAudioMuted.bind(this);
|
||||
this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener);
|
||||
|
||||
// This code loads the IFrame Player API code asynchronously.
|
||||
|
@ -147,24 +156,30 @@ export default class SharedVideoManager {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates that a change in state has occurred for the shared video.
|
||||
* @param event the event notifying us of the change
|
||||
*/
|
||||
window.onPlayerStateChange = function(event) {
|
||||
if (event.data == YT.PlayerState.PLAYING) {
|
||||
self.playerPaused = false;
|
||||
|
||||
self.player = event.target;
|
||||
|
||||
if(self.initialAttributes)
|
||||
{
|
||||
self.processAttributes(
|
||||
self.player, self.initialAttributes, self.playerPaused);
|
||||
// If a network update has occurred already now is the
|
||||
// time to process it.
|
||||
self.processVideoUpdate(
|
||||
self.player,
|
||||
self.initialAttributes);
|
||||
|
||||
self.initialAttributes = null;
|
||||
}
|
||||
|
||||
self.updateCheck();
|
||||
self.smartAudioMute();
|
||||
} else if (event.data == YT.PlayerState.PAUSED) {
|
||||
self.playerPaused = true;
|
||||
self.updateCheck(true);
|
||||
self.smartAudioUnmute();
|
||||
}
|
||||
self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -174,7 +189,7 @@ export default class SharedVideoManager {
|
|||
window.onVideoProgress = function (event) {
|
||||
let state = event.target.getPlayerState();
|
||||
if (state == YT.PlayerState.PAUSED) {
|
||||
self.updateCheck(true);
|
||||
self.fireSharedVideoEvent(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -183,18 +198,14 @@ export default class SharedVideoManager {
|
|||
* @param event
|
||||
*/
|
||||
window.onVolumeChange = function (event) {
|
||||
self.updateCheck();
|
||||
self.fireSharedVideoEvent();
|
||||
|
||||
// let's check, if player is not muted lets mute locally
|
||||
if(event.data.volume > 0 && !event.data.muted
|
||||
&& !APP.conference.isLocalAudioMuted()) {
|
||||
self.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
|
||||
self.showMicMutedPopup(true);
|
||||
if(event.data.volume > 0 && !event.data.muted) {
|
||||
self.smartAudioMute();
|
||||
}
|
||||
else if (!self.mutedWithUserInteraction
|
||||
&& (event.data.volume <=0 || event.data.muted)
|
||||
&& APP.conference.isLocalAudioMuted()) {
|
||||
self.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
|
||||
else if (event.data.volume <=0 || event.data.muted) {
|
||||
self.smartAudioUnmute();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -226,7 +237,7 @@ export default class SharedVideoManager {
|
|||
// we need to continuously send the player current time position
|
||||
if(APP.conference.isLocalId(self.from)) {
|
||||
self.intervalId = setInterval(
|
||||
self.updateCheck.bind(self),
|
||||
self.fireSharedVideoEvent.bind(self),
|
||||
updateInterval);
|
||||
}
|
||||
};
|
||||
|
@ -242,29 +253,37 @@ export default class SharedVideoManager {
|
|||
* Process attributes, whether player needs to be paused or seek.
|
||||
* @param player the player to operate over
|
||||
* @param attributes the attributes with the player state we want
|
||||
* @param playerPaused current saved state for the player
|
||||
*/
|
||||
processAttributes (player, attributes, playerPaused)
|
||||
processVideoUpdate (player, attributes)
|
||||
{
|
||||
if(!attributes)
|
||||
return;
|
||||
|
||||
if (attributes.state == 'playing') {
|
||||
|
||||
this.processTime(player, attributes, playerPaused);
|
||||
let isPlayerPaused
|
||||
= (this.player.getPlayerState() === YT.PlayerState.PAUSED);
|
||||
|
||||
// lets check the volume
|
||||
if (attributes.volume !== undefined
|
||||
&& player.getVolume() != attributes.volume
|
||||
&& (APP.conference.isLocalAudioMuted()
|
||||
|| !this.mutedWithUserInteraction)) {
|
||||
// If our player is currently paused force the seek.
|
||||
this.processTime(player, attributes, isPlayerPaused);
|
||||
|
||||
// Process mute.
|
||||
let isAttrMuted = (attributes.muted === "true");
|
||||
if (player.isMuted() !== isAttrMuted) {
|
||||
this.smartPlayerMute(isAttrMuted, true);
|
||||
}
|
||||
|
||||
// Process volume
|
||||
if (!isAttrMuted
|
||||
&& attributes.volume !== undefined
|
||||
&& player.getVolume() != attributes.volume) {
|
||||
|
||||
player.setVolume(attributes.volume);
|
||||
console.info("Player change of volume:" + attributes.volume);
|
||||
this.showSharedVideoMutedPopup(false);
|
||||
}
|
||||
|
||||
if(playerPaused)
|
||||
if (isPlayerPaused)
|
||||
player.playVideo();
|
||||
|
||||
} else if (attributes.state == 'pause') {
|
||||
|
@ -272,8 +291,6 @@ export default class SharedVideoManager {
|
|||
player.pauseVideo();
|
||||
|
||||
this.processTime(player, attributes, true);
|
||||
} else if (attributes.state == 'stop') {
|
||||
this.stopSharedVideo(this.from);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,7 +324,7 @@ export default class SharedVideoManager {
|
|||
/**
|
||||
* Checks current state of the player and fire an event with the values.
|
||||
*/
|
||||
updateCheck(sendPauseEvent)
|
||||
fireSharedVideoEvent(sendPauseEvent)
|
||||
{
|
||||
// ignore update checks if we are not the owner of the video
|
||||
// or there is still no player defined or we are stopped
|
||||
|
@ -328,7 +345,8 @@ export default class SharedVideoManager {
|
|||
this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
|
||||
this.url, 'playing',
|
||||
this.player.getCurrentTime(),
|
||||
this.player.isMuted() ? 0 : this.player.getVolume());
|
||||
this.player.isMuted(),
|
||||
this.player.getVolume());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,21 +357,21 @@ export default class SharedVideoManager {
|
|||
* @param url the video url
|
||||
* @param attributes
|
||||
*/
|
||||
updateSharedVideo (id, url, attributes) {
|
||||
onSharedVideoUpdate (id, url, attributes) {
|
||||
// if we are sending the event ignore
|
||||
if(APP.conference.isLocalId(this.from)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.isSharedVideoShown) {
|
||||
this.showSharedVideo(id, url, attributes);
|
||||
this.onSharedVideoStart(id, url, attributes);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.player)
|
||||
this.initialAttributes = attributes;
|
||||
else {
|
||||
this.processAttributes(this.player, attributes, this.playerPaused);
|
||||
this.processVideoUpdate(this.player, attributes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -363,14 +381,14 @@ export default class SharedVideoManager {
|
|||
* left and we want to remove video if the user sharing it left).
|
||||
* @param id the id of the sender of the command
|
||||
*/
|
||||
stopSharedVideo (id, attributes) {
|
||||
onSharedVideoStop (id, attributes) {
|
||||
if (!this.isSharedVideoShown)
|
||||
return;
|
||||
|
||||
if(this.from !== id)
|
||||
return;
|
||||
|
||||
if(!this.player){
|
||||
if(!this.player) {
|
||||
// if there is no error in the player till now,
|
||||
// store the initial attributes
|
||||
if (!this.errorInPlayer) {
|
||||
|
@ -388,8 +406,6 @@ export default class SharedVideoManager {
|
|||
this.localAudioMutedListener);
|
||||
this.localAudioMutedListener = null;
|
||||
|
||||
this.showSharedVideoMutedPopup(false);
|
||||
|
||||
VideoLayout.removeParticipantContainer(this.url);
|
||||
|
||||
VideoLayout.showLargeVideoContainer(SHARED_VIDEO_CONTAINER_TYPE, false)
|
||||
|
@ -405,6 +421,7 @@ export default class SharedVideoManager {
|
|||
this.errorInPlayer.destroy();
|
||||
this.errorInPlayer = null;
|
||||
}
|
||||
this.smartAudioUnmute();
|
||||
// revert to original behavior (prevents pausing
|
||||
// for participants not sharing the video to pause it)
|
||||
$("#sharedVideo").css("pointer-events","auto");
|
||||
|
@ -421,20 +438,67 @@ export default class SharedVideoManager {
|
|||
* @param {boolean} indicates if this mute was a result of user interaction,
|
||||
* i.e. pressing the mute button or it was programatically triggerred
|
||||
*/
|
||||
localAudioMuted (muted, userInteraction) {
|
||||
onLocalAudioMuted (muted, userInteraction) {
|
||||
if(!this.player)
|
||||
return;
|
||||
|
||||
if (muted) {
|
||||
this.mutedWithUserInteraction = userInteraction;
|
||||
return;
|
||||
}
|
||||
else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) {
|
||||
this.smartPlayerMute(true, false);
|
||||
// Check if we need to update other participants
|
||||
this.fireSharedVideoEvent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutes / unmutes the player.
|
||||
* @param mute true to mute the shared video, false - otherwise.
|
||||
* @param {boolean} Indicates if this mute is a consequence of a network
|
||||
* video update or is called locally.
|
||||
*/
|
||||
smartPlayerMute(mute, isVideoUpdate) {
|
||||
if (!this.player.isMuted() && mute) {
|
||||
this.player.mute();
|
||||
|
||||
if (isVideoUpdate)
|
||||
this.smartAudioUnmute();
|
||||
}
|
||||
else if (this.player.isMuted() && !mute) {
|
||||
this.player.unMute();
|
||||
if (isVideoUpdate)
|
||||
this.smartAudioMute();
|
||||
}
|
||||
|
||||
// if we are un-muting and player is not muted, lets muted
|
||||
// to not pollute the conference
|
||||
if (this.player.getVolume() > 0 || !this.player.isMuted()) {
|
||||
this.player.setVolume(0);
|
||||
this.showSharedVideoMutedPopup(true);
|
||||
this.showSharedVideoMutedPopup(mute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart mike unmute. If the mike is currently muted and it wasn't muted
|
||||
* by the user via the mike button and the volume of the shared video is on
|
||||
* we're unmuting the mike automatically.
|
||||
*/
|
||||
smartAudioUnmute() {
|
||||
if (APP.conference.isLocalAudioMuted()
|
||||
&& !this.mutedWithUserInteraction
|
||||
&& !this.isSharedVideoVolumeOn()) {
|
||||
|
||||
this.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
|
||||
this.showMicMutedPopup(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart mike mute. If the mike isn't currently muted and the shared video
|
||||
* volume is on we mute the mike.
|
||||
*/
|
||||
smartAudioMute() {
|
||||
if (!APP.conference.isLocalAudioMuted()
|
||||
&& this.isSharedVideoVolumeOn()) {
|
||||
|
||||
this.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
|
||||
this.showMicMutedPopup(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -196,6 +196,15 @@
|
|||
() => {selector.css({opacity: 0});}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses the given cssValue as an Integer. If the value is not a number
|
||||
* we return 0 instead of NaN.
|
||||
* @param cssValue the string value we obtain when querying css properties
|
||||
*/
|
||||
parseCssInt(cssValue) {
|
||||
return parseInt(cssValue) || 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -85,20 +85,32 @@ const FilmStrip = {
|
|||
*/
|
||||
let videoAreaAvailableWidth
|
||||
= UIUtil.getAvailableVideoWidth(isSideBarVisible)
|
||||
- parseInt(this.filmStrip.css('right'), 10)
|
||||
- parseInt(this.filmStrip.css('paddingLeft'), 10)
|
||||
- parseInt(this.filmStrip.css('paddingRight'), 10)
|
||||
- parseInt(this.filmStrip.css('borderLeftWidth'), 10)
|
||||
- parseInt(this.filmStrip.css('borderRightWidth'), 10) - 5;
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('right'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingLeft'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('paddingRight'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('borderLeftWidth'), 10)
|
||||
- UIUtil.parseCssInt(this.filmStrip.css('borderRightWidth'), 10)
|
||||
- 5;
|
||||
|
||||
let availableWidth = Math.floor(
|
||||
let availableWidth = videoAreaAvailableWidth;
|
||||
|
||||
// If the number of videos is 0 or undefined we don't need to calculate
|
||||
// further.
|
||||
if (numvids)
|
||||
availableWidth = Math.floor(
|
||||
(videoAreaAvailableWidth - numvids * (
|
||||
parseInt(localVideoContainer.css('borderLeftWidth'), 10)
|
||||
+ parseInt(localVideoContainer.css('borderRightWidth'), 10)
|
||||
+ parseInt(localVideoContainer.css('paddingLeft'), 10)
|
||||
+ parseInt(localVideoContainer.css('paddingRight'), 10)
|
||||
+ parseInt(localVideoContainer.css('marginLeft'), 10)
|
||||
+ parseInt(localVideoContainer.css('marginRight'), 10)))
|
||||
UIUtil.parseCssInt(
|
||||
localVideoContainer.css('borderLeftWidth'), 10)
|
||||
+ UIUtil.parseCssInt(
|
||||
localVideoContainer.css('borderRightWidth'), 10)
|
||||
+ UIUtil.parseCssInt(
|
||||
localVideoContainer.css('paddingLeft'), 10)
|
||||
+ UIUtil.parseCssInt(
|
||||
localVideoContainer.css('paddingRight'), 10)
|
||||
+ UIUtil.parseCssInt(
|
||||
localVideoContainer.css('marginLeft'), 10)
|
||||
+ UIUtil.parseCssInt(
|
||||
localVideoContainer.css('marginRight'), 10)))
|
||||
/ numvids);
|
||||
|
||||
let maxHeight
|
||||
|
@ -155,7 +167,12 @@ const FilmStrip = {
|
|||
selector += ':visible';
|
||||
}
|
||||
|
||||
return this.filmStrip.children(selector);
|
||||
// Exclude the local video container if it has been hidden.
|
||||
if ($("#localVideoContainer").hasClass("hidden"))
|
||||
return this.filmStrip.children(selector)
|
||||
.not("#localVideoContainer");
|
||||
else
|
||||
return this.filmStrip.children(selector);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -446,7 +446,15 @@ export default class LargeVideoManager {
|
|||
|
||||
let container = this.getContainer(this.state);
|
||||
|
||||
container.hide().then(() => {
|
||||
// Include hide()/fadeOut only if we're switching between users
|
||||
let preUpdate;
|
||||
if (this.newStreamData.id != this.id) {
|
||||
preUpdate = container.hide();
|
||||
} else {
|
||||
preUpdate = Promise.resolve();
|
||||
}
|
||||
|
||||
preUpdate.then(() => {
|
||||
let {id, stream, videoType, resolve} = this.newStreamData;
|
||||
this.newStreamData = null;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* global $, interfaceConfig, APP, JitsiMeetJS */
|
||||
/* global $, config, interfaceConfig, APP, JitsiMeetJS */
|
||||
import ConnectionIndicator from "./ConnectionIndicator";
|
||||
import UIUtil from "../util/UIUtil";
|
||||
import UIEvents from "../../../service/UI/UIEvents";
|
||||
|
@ -200,4 +200,26 @@ LocalVideo.prototype.changeVideo = function (stream) {
|
|||
stream.on(TrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows or hides the local video container.
|
||||
* @param {boolean} true to make the local video container visible, false
|
||||
* otherwise
|
||||
*/
|
||||
LocalVideo.prototype.setVisible = function(visible) {
|
||||
|
||||
// We toggle the hidden class as an indication to other interested parties
|
||||
// that this container has been hidden on purpose.
|
||||
$("#localVideoContainer").toggleClass("hidden");
|
||||
|
||||
// We still show/hide it as we need to overwrite the style property if we
|
||||
// want our action to take effect. Toggling the display property through
|
||||
// the above css class didn't succeed in overwriting the style.
|
||||
if (visible) {
|
||||
$("#localVideoContainer").show();
|
||||
}
|
||||
else {
|
||||
$("#localVideoContainer").hide();
|
||||
}
|
||||
};
|
||||
|
||||
export default LocalVideo;
|
||||
|
|
|
@ -207,7 +207,7 @@ var VideoLayout = {
|
|||
if (APP.conference.isLocalId(id)) {
|
||||
video = localVideoThumbnail;
|
||||
}
|
||||
else if (remoteVideos[id]) {
|
||||
else {
|
||||
video = remoteVideos[id];
|
||||
}
|
||||
|
||||
|
@ -215,6 +215,14 @@ var VideoLayout = {
|
|||
video.enableDeviceAvailabilityIcons(enable);
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows/hides local video.
|
||||
* @param {boolean} true to make the local video visible, false - otherwise
|
||||
*/
|
||||
setLocalVideoVisible(visible) {
|
||||
localVideoThumbnail.setVisible(visible);
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if removed video is currently displayed and tries to display
|
||||
* another one instead.
|
||||
|
@ -277,7 +285,12 @@ var VideoLayout = {
|
|||
|
||||
onRemoteStreamAdded (stream) {
|
||||
let id = stream.getParticipantId();
|
||||
remoteVideos[id].addRemoteStreamElement(stream);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
|
||||
if (!remoteVideo)
|
||||
return;
|
||||
|
||||
remoteVideo.addRemoteStreamElement(stream);
|
||||
|
||||
// if track is muted make sure we reflect that
|
||||
if(stream.isMuted())
|
||||
|
@ -360,7 +373,8 @@ var VideoLayout = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Creates a remote video for participant for the given id.
|
||||
* Creates a participant container for the given id and smallVideo.
|
||||
*
|
||||
* @param id the id of the participant to add
|
||||
* @param {SmallVideo} smallVideo optional small video instance to add as a
|
||||
* remote video, if undefined RemoteVideo will be created
|
||||
|
@ -404,7 +418,11 @@ var VideoLayout = {
|
|||
this.isLargeContainerTypeVisible(VIDEO_CONTAINER_TYPE)) ||
|
||||
pinnedId === resourceJid ||
|
||||
(!pinnedId && resourceJid &&
|
||||
currentDominantSpeaker === resourceJid)) {
|
||||
currentDominantSpeaker === resourceJid) ||
|
||||
/* Playback started while we're on the stage - may need to update
|
||||
video source with the new stream */
|
||||
this.isCurrentlyOnLarge(resourceJid)) {
|
||||
|
||||
this.updateLargeVideo(resourceJid, true);
|
||||
}
|
||||
},
|
||||
|
@ -413,7 +431,9 @@ var VideoLayout = {
|
|||
* Shows the presence status message for the given video.
|
||||
*/
|
||||
setPresenceStatus (id, statusMsg) {
|
||||
remoteVideos[id].setPresenceStatus(statusMsg);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo)
|
||||
remoteVideo.setPresenceStatus(statusMsg);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -428,13 +448,17 @@ var VideoLayout = {
|
|||
|
||||
APP.conference.listMembers().forEach(function (member) {
|
||||
let id = member.getId();
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (!remoteVideo)
|
||||
return;
|
||||
|
||||
if (member.isModerator()) {
|
||||
remoteVideos[id].removeRemoteVideoMenu();
|
||||
remoteVideos[id].createModeratorIndicatorElement();
|
||||
remoteVideo.removeRemoteVideoMenu();
|
||||
remoteVideo.createModeratorIndicatorElement();
|
||||
} else if (isModerator) {
|
||||
// We are moderator, but user is not - add menu
|
||||
if ($(`#remote_popupmenu_${id}`).length <= 0) {
|
||||
remoteVideos[id].addRemoteVideoMenu();
|
||||
remoteVideo.addRemoteVideoMenu();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -482,9 +506,13 @@ var VideoLayout = {
|
|||
if (APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail.showAudioIndicator(isMuted);
|
||||
} else {
|
||||
remoteVideos[id].showAudioIndicator(isMuted);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (!remoteVideo)
|
||||
return;
|
||||
|
||||
remoteVideo.showAudioIndicator(isMuted);
|
||||
if (APP.conference.isModerator) {
|
||||
remoteVideos[id].updateRemoteVideoMenu(isMuted);
|
||||
remoteVideo.updateRemoteVideoMenu(isMuted);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -496,8 +524,9 @@ var VideoLayout = {
|
|||
if (APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail.setMutedView(value);
|
||||
} else {
|
||||
var remoteVideo = remoteVideos[id];
|
||||
remoteVideo.setMutedView(value);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo)
|
||||
remoteVideo.setMutedView(value);
|
||||
}
|
||||
|
||||
if (this.isCurrentlyOnLarge(id)) {
|
||||
|
@ -514,7 +543,9 @@ var VideoLayout = {
|
|||
APP.conference.isLocalId(id)) {
|
||||
localVideoThumbnail.setDisplayName(displayName);
|
||||
} else {
|
||||
remoteVideos[id].setDisplayName(displayName, status);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo)
|
||||
remoteVideo.setDisplayName(displayName, status);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -636,9 +667,13 @@ var VideoLayout = {
|
|||
console.error("No remote video for: " + resourceJid);
|
||||
isReceived = false;
|
||||
} else if (resourceJid &&
|
||||
//TOFIX: smallVideo may be undefined
|
||||
smallVideo.isVisible() &&
|
||||
lastNEndpoints.indexOf(resourceJid) < 0 &&
|
||||
localLastNSet.indexOf(resourceJid) >= 0) {
|
||||
|
||||
// TOFIX: if we're here we already know that the smallVideo
|
||||
// exists. Look at the previous FIX above.
|
||||
if (smallVideo)
|
||||
smallVideo.showPeerContainer('avatar');
|
||||
else if (!APP.conference.isLocalId(resourceJid))
|
||||
|
@ -739,8 +774,9 @@ var VideoLayout = {
|
|||
* @param object the stats data
|
||||
*/
|
||||
updateConnectionStats (id, percent, object) {
|
||||
if (remoteVideos[id]) {
|
||||
remoteVideos[id].updateStatsIndicator(percent, object);
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo) {
|
||||
remoteVideo.updateStatsIndicator(percent, object);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -749,15 +785,19 @@ var VideoLayout = {
|
|||
* @param id
|
||||
*/
|
||||
hideConnectionIndicator (id) {
|
||||
remoteVideos[id].hideConnectionIndicator();
|
||||
let remoteVideo = remoteVideos[id];
|
||||
if (remoteVideo)
|
||||
remoteVideo.hideConnectionIndicator();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hides all the indicators
|
||||
*/
|
||||
hideStats () {
|
||||
for(var video in remoteVideos) {
|
||||
remoteVideos[video].hideIndicator();
|
||||
for (var video in remoteVideos) {
|
||||
let remoteVideo = remoteVideos[video];
|
||||
if (remoteVideo)
|
||||
remoteVideo.hideIndicator();
|
||||
}
|
||||
localVideoThumbnail.hideIndicator();
|
||||
},
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
/* global config, APP */
|
||||
/*
|
||||
* Copyright @ 2015 Atlassian Pty Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import VideoLayout from '../UI/videolayout/VideoLayout';
|
||||
import Feedback from '../UI/Feedback.js';
|
||||
import Toolbar from '../UI/toolbars/Toolbar';
|
||||
import BottomToolbar from '../UI/toolbars/BottomToolbar';
|
||||
|
||||
const _RECORDER_CUSTOM_ROLE = "recorder-role";
|
||||
|
||||
class Recorder {
|
||||
/**
|
||||
* Initializes a new {Recorder} instance.
|
||||
*
|
||||
* @param conference the {conference} which is to transport
|
||||
* {Recorder}-related information between participants
|
||||
*/
|
||||
constructor (conference) {
|
||||
this._conference = conference;
|
||||
|
||||
// If I am a recorder then I publish my recorder custom role to notify
|
||||
// everyone.
|
||||
if (config.iAmRecorder) {
|
||||
VideoLayout.enableDeviceAvailabilityIcons(conference.localId, true);
|
||||
this._publishMyRecorderRole();
|
||||
Feedback.enableFeedback(false);
|
||||
Toolbar.enable(false);
|
||||
BottomToolbar.enable(false);
|
||||
}
|
||||
|
||||
// Listen to "CUSTOM_ROLE" commands.
|
||||
this._conference.commands.addCommandListener(
|
||||
this._conference.commands.defaults.CUSTOM_ROLE,
|
||||
this._onCustomRoleCommand.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the recorder custom role.
|
||||
* @private
|
||||
*/
|
||||
_publishMyRecorderRole () {
|
||||
var conference = this._conference;
|
||||
|
||||
var commands = conference.commands;
|
||||
|
||||
commands.removeCommand(commands.defaults.CUSTOM_ROLE);
|
||||
var self = this;
|
||||
commands.sendCommandOnce(
|
||||
commands.defaults.CUSTOM_ROLE,
|
||||
{
|
||||
attributes: {
|
||||
recorderRole: true
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies this instance about a &qout;Custom Role&qout; command (delivered
|
||||
* by the Command(s) API of {this._conference}).
|
||||
*
|
||||
* @param attributes the attributes {Object} carried by the command
|
||||
* @param id the identifier of the participant who issued the command. A
|
||||
* notable idiosyncrasy of the Command(s) API to be mindful of here is that
|
||||
* the command may be issued by the local participant.
|
||||
*/
|
||||
_onCustomRoleCommand ({ attributes }, id) {
|
||||
// We require to know who issued the command because (1) only a
|
||||
// moderator is allowed to send commands and (2) a command MUST be
|
||||
// issued by a defined commander.
|
||||
if (typeof id === 'undefined'
|
||||
|| this._conference.isLocalId(id)
|
||||
|| !attributes.recorderRole)
|
||||
return;
|
||||
|
||||
var isRecorder = (attributes.recorderRole == 'true');
|
||||
|
||||
if (isRecorder)
|
||||
VideoLayout.enableDeviceAvailabilityIcons(id, isRecorder);
|
||||
}
|
||||
}
|
||||
|
||||
export default Recorder;
|
|
@ -80,6 +80,9 @@ function provider.get_sasl_handler(session)
|
|||
-- here we check if 'room' claim exists
|
||||
local room, roomErr = token_util.get_room_name(token, appSecret);
|
||||
if room == nil then
|
||||
if roomErr == nil then
|
||||
roomErr = "'room' claim is missing";
|
||||
end
|
||||
return false, "not-allowed", roomErr;
|
||||
end
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ local function _verify_token(token, appId, appSecret, roomName)
|
|||
|
||||
local issClaim = claims["iss"];
|
||||
if issClaim == nil then
|
||||
return nil, "Issuer field is missing";
|
||||
return nil, "'iss' claim is missing";
|
||||
end
|
||||
if issClaim ~= appId then
|
||||
return nil, "Invalid application ID('iss' claim)";
|
||||
|
@ -31,7 +31,7 @@ local function _verify_token(token, appId, appSecret, roomName)
|
|||
|
||||
local roomClaim = claims["room"];
|
||||
if roomClaim == nil then
|
||||
return nil, "Room field is missing";
|
||||
return nil, "'room' claim is missing";
|
||||
end
|
||||
if roomName ~= nil and roomName ~= roomClaim then
|
||||
return nil, "Invalid room name('room' claim)";
|
||||
|
|
Loading…
Reference in New Issue