From 73b4ad5a63f38074f8bc859b7e807e8582a3113f Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 18 Apr 2016 17:02:34 -0500 Subject: [PATCH 01/27] Added JitsiConference.leave() when the hangup button is pressed --- conference.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/conference.js b/conference.js index 618b230a2..c20bb505d 100644 --- a/conference.js +++ b/conference.js @@ -123,15 +123,15 @@ 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(); + let promise = Promise.resolve(); + if (requestFeedback) { + promise = APP.UI.requestFeedback(); + } + return promise; + }).then(function () { if (!config.enableWelcomePage) { return; } From 7c7ce66ae44eb2194b9b2a4ca53c10ffbc94d75d Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Tue, 19 Apr 2016 12:15:04 -0500 Subject: [PATCH 02/27] Prettifying the code related to showing the feedback dialog --- conference.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/conference.js b/conference.js index c20bb505d..2e399827a 100644 --- a/conference.js +++ b/conference.js @@ -125,12 +125,11 @@ function muteLocalVideo (muted) { function hangup (requestFeedback = false) { APP.conference._room.leave().then(() => { connection.disconnect(); - let promise = Promise.resolve(); - if (requestFeedback) { - promise = APP.UI.requestFeedback(); + return APP.UI.requestFeedback(); + } else { + return Promise.resolve(); } - return promise; }).then(function () { if (!config.enableWelcomePage) { return; From 340873769399ba611e955a662249ab43e81ed049 Mon Sep 17 00:00:00 2001 From: yanas Date: Wed, 20 Apr 2016 14:02:16 -0500 Subject: [PATCH 03/27] Adds id and password initial login --- connection.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/connection.js b/connection.js index aa0ca0f7c..3101ade40 100644 --- a/connection.js +++ b/connection.js @@ -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; @@ -131,6 +131,20 @@ function requestAuth() { * @returns {Promise} */ export function openConnection({id, password, retry, roomName}) { + + let predefinedLogin = window.localStorage.getItem("xmpp_login"); + let predefinedPassword = window.localStorage.getItem("xmpp_password"); + + if (!id && predefinedLogin && predefinedLogin.length > 0) { + id = predefinedLogin; + window.localStorage.removeItem("xmpp_login"); + } + + if (!password && predefinedPassword && predefinedPassword.length > 0) { + password = predefinedPassword; + window.localStorage.removeItem("xmpp_password"); + } + return connect(id, password, roomName).catch(function (err) { if (!retry) { throw err; From 1c9903642b6aa0026f3eb560dc8dccd32d2f043b Mon Sep 17 00:00:00 2001 From: yanas Date: Wed, 20 Apr 2016 14:41:29 -0500 Subject: [PATCH 04/27] Do not remove the login params after read --- connection.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/connection.js b/connection.js index 3101ade40..7764dfe92 100644 --- a/connection.js +++ b/connection.js @@ -137,12 +137,10 @@ export function openConnection({id, password, retry, roomName}) { if (!id && predefinedLogin && predefinedLogin.length > 0) { id = predefinedLogin; - window.localStorage.removeItem("xmpp_login"); } if (!password && predefinedPassword && predefinedPassword.length > 0) { password = predefinedPassword; - window.localStorage.removeItem("xmpp_password"); } return connect(id, password, roomName).catch(function (err) { From 5a95edbdcd7715aadaab9677ad717ea6f9db937c Mon Sep 17 00:00:00 2001 From: paweldomas Date: Wed, 20 Apr 2016 16:37:36 -0500 Subject: [PATCH 05/27] Improve token error reporting in Prosody JWT plugin --- prosody-plugins/mod_auth_token.lua | 3 +++ prosody-plugins/token/util.lib.lua | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/prosody-plugins/mod_auth_token.lua b/prosody-plugins/mod_auth_token.lua index 1b24e94c2..9a9befe77 100644 --- a/prosody-plugins/mod_auth_token.lua +++ b/prosody-plugins/mod_auth_token.lua @@ -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 diff --git a/prosody-plugins/token/util.lib.lua b/prosody-plugins/token/util.lib.lua index c281c3d95..0f7c55364 100644 --- a/prosody-plugins/token/util.lib.lua +++ b/prosody-plugins/token/util.lib.lua @@ -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)"; From faa519cbeb6b02f50350463c1d29969221b16eab Mon Sep 17 00:00:00 2001 From: jitsi-pootle Date: Wed, 20 Apr 2016 22:34:59 +0000 Subject: [PATCH 06/27] New files added from translate.jitsi.org based on templates --- lang/languages-es.json | 10 ++ lang/main-es.json | 224 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 lang/languages-es.json create mode 100644 lang/main-es.json diff --git a/lang/languages-es.json b/lang/languages-es.json new file mode 100644 index 000000000..246316787 --- /dev/null +++ b/lang/languages-es.json @@ -0,0 +1,10 @@ +{ + "en": "", + "bg": "", + "de": "", + "tr": "", + "it": "", + "fr": "", + "sl": "", + "sk": "" +} \ No newline at end of file diff --git a/lang/main-es.json b/lang/main-es.json new file mode 100644 index 000000000..17b612828 --- /dev/null +++ b/lang/main-es.json @@ -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": "" + } +} \ No newline at end of file From 1feb5d00feba7edfaad6e83acca93e641839766d Mon Sep 17 00:00:00 2001 From: emcho Date: Wed, 20 Apr 2016 23:06:12 +0000 Subject: [PATCH 07/27] Commit from translate.jitsi.org by user emcho.: 180 of 180 strings translated (0 fuzzy). --- lang/languages-bg.json | 5 ++- lang/main-bg.json | 75 ++++++++++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 29 deletions(-) diff --git a/lang/languages-bg.json b/lang/languages-bg.json index cff4ab662..a3963766e 100644 --- a/lang/languages-bg.json +++ b/lang/languages-bg.json @@ -3,5 +3,8 @@ "bg": "Български", "de": "Немски", "tr": "Турски", - "it": "Италиански" + "it": "Италиански", + "fr": "Френски", + "sl": "Словенски", + "sk": "Словашки" } \ No newline at end of file diff --git a/lang/main-bg.json b/lang/main-bg.json index da2cfebab..2c71c48cd 100644 --- a/lang/main-bg.json +++ b/lang/main-bg.json @@ -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": "Натиснете за да
промените името", @@ -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": "Нужна е идентификация, за да създадете стая:
__room__
Може да се идентифицирате, за да създадете стая или да изчакате някой друг да го направи.", - "Authenticate": "Идентификация", + "sharePreziMsg": "Prezi string delete", + "Remove": "DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE ", + "WaitingForHost": "Чакаме домакина ...", + "WaitForHostMsg": "__room__ още не е започнал. Ако вие сте домакина моля идентифицирайте се. В противен случай ще изчакаме домакина.", + "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 разширение. свалете го тук и пробвайте пак!", + "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": "Записът започна" } } \ No newline at end of file From fb7c2082e6e8c2bdeafe067614aabbea6da47217 Mon Sep 17 00:00:00 2001 From: Boris Grozev Date: Thu, 21 Apr 2016 17:48:30 -0500 Subject: [PATCH 08/27] Exposes the number of participants with tracks. --- conference.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/conference.js b/conference.js index ac89e1f5e..f046e0191 100644 --- a/conference.js +++ b/conference.js @@ -474,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. From af46e28fcc24c5fb83e537833f1b596c81e4f8b9 Mon Sep 17 00:00:00 2001 From: jitsi-pootle Date: Mon, 25 Apr 2016 17:14:01 +0000 Subject: [PATCH 09/27] New files added from translate.jitsi.org based on templates --- lang/languages-oc.json | 10 ++ lang/main-oc.json | 224 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 lang/languages-oc.json create mode 100644 lang/main-oc.json diff --git a/lang/languages-oc.json b/lang/languages-oc.json new file mode 100644 index 000000000..246316787 --- /dev/null +++ b/lang/languages-oc.json @@ -0,0 +1,10 @@ +{ + "en": "", + "bg": "", + "de": "", + "tr": "", + "it": "", + "fr": "", + "sl": "", + "sk": "" +} \ No newline at end of file diff --git a/lang/main-oc.json b/lang/main-oc.json new file mode 100644 index 000000000..17b612828 --- /dev/null +++ b/lang/main-oc.json @@ -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": "" + } +} \ No newline at end of file From 6a74296d3e11dc9d9366ca00cb8769dfe7fb3ba2 Mon Sep 17 00:00:00 2001 From: emcho Date: Mon, 25 Apr 2016 19:29:18 +0000 Subject: [PATCH 10/27] Commit from translate.jitsi.org by user emcho.: 180 of 180 strings translated (0 fuzzy). --- lang/languages-es.json | 16 +- lang/main-es.json | 374 ++++++++++++++++++++++------------------- 2 files changed, 206 insertions(+), 184 deletions(-) diff --git a/lang/languages-es.json b/lang/languages-es.json index 246316787..560da664f 100644 --- a/lang/languages-es.json +++ b/lang/languages-es.json @@ -1,10 +1,10 @@ { - "en": "", - "bg": "", - "de": "", - "tr": "", - "it": "", - "fr": "", - "sl": "", - "sk": "" + "en": "Inglés", + "bg": "Búlgaro", + "de": "Alemán", + "tr": "Turco", + "it": "Italiano", + "fr": "Francés", + "sl": "Esloveno", + "sk": "Eslovaco" } \ No newline at end of file diff --git a/lang/main-es.json b/lang/main-es.json index 17b612828..bff3334ce 100644 --- a/lang/main-es.json +++ b/lang/main-es.json @@ -1,224 +1,246 @@ { - "contactlist": "", - "connectionsettings": "", - "poweredby": "", - "downloadlogs": "", - "feedback": "", - "roomUrlDefaultMsg": "", - "participant": "", - "me": "", - "speaker": "", - "defaultNickname": "", - "defaultPreziLink": "", + "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": "", - "roomname": "", - "disable": "", + "go": "IR", + "roomname": "Introduzca un nombre de sala:", + "disable": "No mostrar esta página en el próximo acceso ", "feature1": { - "title": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "content": "" + "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": "", - "videomute": "", - "authenticate": "", - "record": "", - "lock": "", - "invite": "", + "mute": "Silenciar / Activar", + "videomute": "Iniciar / detener cámara", + "authenticate": "Autenticar", + "record": "Grabar", + "lock": "Bloquear / desbloquear sala", + "invite": "Invitar a otros", "chat": "", - "prezi": "", - "etherpad": "", - "sharescreen": "", - "fullscreen": "", - "sip": "", - "Settings": "", - "hangup": "", - "login": "", + "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": "" + "dialpad": "Mostrar teclado de llamada" }, "bottomtoolbar": { - "chat": "", - "filmstrip": "", - "contactlist": "" + "chat": "Abrir / cerrar chat", + "filmstrip": "Mostrar / ocultar film", + "contactlist": "Abrir / cerrar lista de contactos" }, "chat": { "nickname": { - "title": "", - "popover": "" + "title": "Indique un nombre en la caja inferior", + "popover": "Seleccione un nombre" }, - "messagebox": "" + "messagebox": "Introduzca texto..." }, "settings": { - "title": "", - "update": "", - "name": "", - "startAudioMuted": "", - "startVideoMuted": "" + "title": "CONFIGURAR", + "update": "Actualizar", + "name": "Nombre", + "startAudioMuted": "iniciar sin audio", + "startVideoMuted": "iniciar sin video" }, "videothumbnail": { - "editnickname": "", - "moderator": "", - "videomute": "", - "mute": "", - "kick": "", - "muted": "", - "domute": "" + "editnickname": "Pica para editar tu
nombre", + "moderator": "El dueño de
esta conferencia", + "videomute": "Participante ha
detenido la cámara.", + "mute": "Participante está silenciado", + "kick": "Expulsar", + "muted": "Silenciado", + "domute": "Silenciar" }, "connectionindicator": { - "bitrate": "", - "packetloss": "", - "resolution": "", - "less": "", - "more": "", - "address": "", - "remoteport": "", - "remoteport_plural": "", - "localport": "", - "localport_plural": "", - "localaddress": "", - "localaddress_plural": "", - "remoteaddress": "", - "remoteaddress_plural": "", - "transport": "", - "bandwidth": "", - "na": "" + "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": "", - "moderator": "", - "connected": "", - "somebody": "", - "me": "", - "focus": "", - "focusFail": "", - "grantedTo": "", - "grantedToUnknown": "", - "muted": "", - "mutedTitle": "" + "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": "", - "popupError": "", - "passwordError": "", - "passwordError2": "", - "connectError": "", - "connectErrorWithMsg": "", + "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": "", - "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": "" + "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 __room__ 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

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í !", + "feedbackQuestion": "¿Como fue su llamada?", + "thankYou": "Gracias por usar __appName__!", + "sorryFeedback": " Sentimos escuchar eso. ¿Quieres decirnos algo más?" }, "email": { - "sharedKey": "", - "subject": "", - "body": "", - "and": "" + "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": "", - "CONNECTING": "", - "RECONNECTING": "", - "CONNFAIL": "", - "AUTHENTICATING": "", - "AUTHFAIL": "", - "CONNECTED": "", - "DISCONNECTED": "", - "DISCONNECTING": "", - "ATTACHED": "" + "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": "", - "pending": "", - "on": "" + "toaster": "¡Actualmente Grabando! ", + "pending": "Tu grabación se iniciará tan pronto como otro participante se una", + "on": "La grabación ha iniciado" } } \ No newline at end of file From 3a9d743d477fac36cbd6a363b97e679d38336d7d Mon Sep 17 00:00:00 2001 From: yanas Date: Mon, 25 Apr 2016 15:39:31 -0500 Subject: [PATCH 11/27] Add shared video smart mike mutes unmutes --- conference.js | 18 +++- modules/UI/shared_video/SharedVideo.js | 123 ++++++++++++++++++------- 2 files changed, 107 insertions(+), 34 deletions(-) diff --git a/conference.js b/conference.js index 75333fcc3..66b26a711 100644 --- a/conference.js +++ b/conference.js @@ -1098,7 +1098,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 +1108,7 @@ export default { attributes: { state: state, time: time, + muted: isMuted, volume: volume } }); @@ -1121,6 +1122,7 @@ export default { attributes: { state: state, time: time, + muted: isMuted, volume: volume } }); @@ -1131,12 +1133,22 @@ export default { if (attributes.state === 'stop') { APP.UI.stopSharedVideo(id, attributes); - } else if (attributes.state === 'start') { + } + else if (attributes.state === 'start') { APP.UI.showSharedVideo(id, value, attributes); - } else if (attributes.state === 'playing' + } + else if (attributes.state === 'playing' || attributes.state === 'pause') { APP.UI.updateSharedVideo(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); } }; diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index aa9af4deb..ab1f06b31 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -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); } /** @@ -92,7 +98,7 @@ export default class SharedVideoManager { this.from = id; //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. @@ -156,13 +162,17 @@ export default class SharedVideoManager { if(self.initialAttributes) { self.processAttributes( - self.player, self.initialAttributes, self.playerPaused); + self.player, + self.initialAttributes, + self.playerPaused); + self.initialAttributes = null; } - + self.smartMute(); self.updateCheck(); } else if (event.data == YT.PlayerState.PAUSED) { self.playerPaused = true; + self.smartUnmute(); self.updateCheck(true); } }; @@ -186,15 +196,11 @@ export default class SharedVideoManager { self.updateCheck(); // 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.smartMute(); } - 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.smartUnmute(); } }; @@ -253,18 +259,30 @@ export default class SharedVideoManager { this.processTime(player, attributes, playerPaused); - // lets check the volume - if (attributes.volume !== undefined - && player.getVolume() != attributes.volume - && (APP.conference.isLocalAudioMuted() - || !this.mutedWithUserInteraction)) { + let isAttrMuted = (attributes.muted === "true"); + + // Process player unmute + if (player.isMuted() && !isAttrMuted) { + console.log("Process player unmute and smart mike mute."); + this.mutePlayer(false); + } + // Process player mute + else if (!player.isMuted() && isAttrMuted) { + console.log("Process player mute and smart mike unmute."); + this.mutePlayer(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 (playerPaused) player.playVideo(); } else if (attributes.state == 'pause') { @@ -328,7 +346,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()); } } @@ -370,7 +389,7 @@ export default class SharedVideoManager { 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 +407,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 +422,7 @@ export default class SharedVideoManager { this.errorInPlayer.destroy(); this.errorInPlayer = null; } + this.smartUnmute(); // revert to original behavior (prevents pausing // for participants not sharing the video to pause it) $("#sharedVideo").css("pointer-events","auto"); @@ -421,20 +439,63 @@ 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.playerPaused) { + this.mutePlayer(true); + } + } + + /** + * Mutes / unmutes the player. + * @param mute true to mute the shared video, false - otherwise. + */ + mutePlayer(mute) { + if (!this.player.isMuted() && mute) { + this.player.mute(); + this.smartUnmute(); + } + else if (this.player.isMuted() && !mute) { + this.player.unMute(); + this.smartMute(); } - // 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); + // Check if we need to update other participants + this.updateCheck(); + + 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. + */ + smartUnmute() { + 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. + */ + smartMute() { + if (!APP.conference.isLocalAudioMuted() + && this.isSharedVideoVolumeOn()) { + + this.emitter.emit(UIEvents.AUDIO_MUTED, true, false); + this.showMicMutedPopup(true); } } From 2442f0dfd307c588a813beabb9fe8379bb8d4748 Mon Sep 17 00:00:00 2001 From: damencho Date: Tue, 26 Apr 2016 10:22:12 +0300 Subject: [PATCH 12/27] Removes playerPaused variable and just use player to get its state. --- modules/UI/shared_video/SharedVideo.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index ab1f06b31..f522d29a3 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -155,7 +155,6 @@ export default class SharedVideoManager { window.onPlayerStateChange = function(event) { if (event.data == YT.PlayerState.PLAYING) { - self.playerPaused = false; self.player = event.target; @@ -164,14 +163,13 @@ export default class SharedVideoManager { self.processAttributes( self.player, self.initialAttributes, - self.playerPaused); + false); self.initialAttributes = null; } self.smartMute(); self.updateCheck(); } else if (event.data == YT.PlayerState.PAUSED) { - self.playerPaused = true; self.smartUnmute(); self.updateCheck(true); } @@ -372,7 +370,8 @@ export default class SharedVideoManager { if(!this.player) this.initialAttributes = attributes; else { - this.processAttributes(this.player, attributes, this.playerPaused); + this.processAttributes(this.player, attributes, + (this.player.getPlayerState() === YT.PlayerState.PAUSED)); } } @@ -446,7 +445,7 @@ export default class SharedVideoManager { if (muted) { this.mutedWithUserInteraction = userInteraction; } - else if (!this.playerPaused) { + else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) { this.mutePlayer(true); } } From ca31bb935b6509d44079c4596f24221295f7f85d Mon Sep 17 00:00:00 2001 From: Etienne CHAMPETIER Date: Tue, 26 Apr 2016 13:50:28 +0200 Subject: [PATCH 13/27] Fix "make source-package" Signed-off-by: Etienne CHAMPETIER --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index afd026632..617a110ca 100644 --- a/Makefile +++ b/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) && \ From 13a55089a56af379866ea0b6731f3282eb17490f Mon Sep 17 00:00:00 2001 From: ibauersachs Date: Tue, 26 Apr 2016 17:13:55 +0000 Subject: [PATCH 14/27] Commit from translate.jitsi.org by user ibauersachs.: 203 of 203 strings translated (0 fuzzy). --- lang/languages-de.json | 3 +- lang/main-de.json | 93 +++++++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/lang/languages-de.json b/lang/languages-de.json index f198c9c6a..0fbfc83f0 100644 --- a/lang/languages-de.json +++ b/lang/languages-de.json @@ -6,5 +6,6 @@ "it": "Italienisch", "fr": "Französisch", "sl": "Slowenisch", - "sk": "Slowakisch" + "sk": "Slowakisch", + "sv": "Schwedisch" } \ No newline at end of file diff --git a/lang/main-de.json b/lang/main-de.json index 4f2ff7da0..4b1b7a538 100644 --- a/lang/main-de.json +++ b/lang/main-de.json @@ -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
den anderen Teilnehmern gesprochen werden kann.", + "micMutedPopup": "Ihr Mikrofon wurde stumm geschaltet damit das
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 __room__ 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 __room__ 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

Setzen Sie ein Passwort um den Raum zu schützen:", + "settings3": "Nickname erforderlich

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 Erweiterung installiert 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." } } \ No newline at end of file From 0116f547ed8dcf033c29d4db8cb6e4b583470a08 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Tue, 26 Apr 2016 15:40:57 -0500 Subject: [PATCH 15/27] Log an error when not an audio nor a video track is added --- conference.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conference.js b/conference.js index f046e0191..85036ddb0 100644 --- a/conference.js +++ b/conference.js @@ -557,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); From f2c9b8b7a5dcfc7affcb8fbe225e1981f44051a6 Mon Sep 17 00:00:00 2001 From: paweldomas Date: Tue, 26 Apr 2016 15:42:18 -0500 Subject: [PATCH 16/27] Fix issue updating large video 'src' while on stage --- modules/UI/videolayout/LargeVideo.js | 10 +++++++++- modules/UI/videolayout/VideoLayout.js | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/UI/videolayout/LargeVideo.js b/modules/UI/videolayout/LargeVideo.js index dc4ed19cf..351a2b0f3 100644 --- a/modules/UI/videolayout/LargeVideo.js +++ b/modules/UI/videolayout/LargeVideo.js @@ -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; diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 7c94da9db..d31674e6f 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -404,7 +404,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); } }, From c881e7b64074c26738c2b1f78ef4aba5883baf9a Mon Sep 17 00:00:00 2001 From: yanas Date: Tue, 26 Apr 2016 16:38:07 -0500 Subject: [PATCH 17/27] Add hidden participant support --- conference.js | 5 +- connection.js | 14 ++-- modules/UI/UI.js | 6 -- modules/UI/recording/Recording.js | 15 +++++ modules/UI/videolayout/VideoLayout.js | 10 ++- modules/recorder/Recorder.js | 95 --------------------------- 6 files changed, 35 insertions(+), 110 deletions(-) delete mode 100644 modules/recorder/Recorder.js diff --git a/conference.js b/conference.js index 75333fcc3..c0dff5043 100644 --- a/conference.js +++ b/conference.js @@ -753,11 +753,14 @@ 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) => { diff --git a/connection.js b/connection.js index 7764dfe92..d66dd24f3 100644 --- a/connection.js +++ b/connection.js @@ -132,15 +132,17 @@ function requestAuth() { */ export function openConnection({id, password, retry, roomName}) { - let predefinedLogin = window.localStorage.getItem("xmpp_login"); - let predefinedPassword = window.localStorage.getItem("xmpp_password"); + let usernameOverride + = window.localStorage.getItem("xmpp_username_override"); + let passwordOverride + = window.localStorage.getItem("xmpp_password_override"); - if (!id && predefinedLogin && predefinedLogin.length > 0) { - id = predefinedLogin; + if (usernameOverride && usernameOverride.length > 0) { + id = usernameOverride; } - if (!password && predefinedPassword && predefinedPassword.length > 0) { - password = predefinedPassword; + if (passwordOverride && passwordOverride.length > 0) { + password = passwordOverride; } return connect(id, password, roomName).catch(function (err) { diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 8a2e2fa98..362979b66 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -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(); diff --git a/modules/UI/recording/Recording.js b/modules/UI/recording/Recording.js index 23a660b29..fdf92f073 100644 --- a/modules/UI/recording/Recording.js +++ b/modules/UI/recording/Recording.js @@ -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,16 @@ 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, true); + Feedback.enableFeedback(false); + Toolbar.enable(false); + BottomToolbar.enable(false); + } }, /** diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 7c94da9db..5460633e6 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -277,7 +277,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 +365,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 diff --git a/modules/recorder/Recorder.js b/modules/recorder/Recorder.js deleted file mode 100644 index ca156f264..000000000 --- a/modules/recorder/Recorder.js +++ /dev/null @@ -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; From aeabad48917e3bb15b7590b445f77c06aa5bea8a Mon Sep 17 00:00:00 2001 From: yanas Date: Wed, 27 Apr 2016 15:52:07 -0500 Subject: [PATCH 18/27] Fix missing remote video exception --- modules/UI/videolayout/VideoLayout.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 7c94da9db..0fbf5a579 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -428,13 +428,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(); } } }); From 4a4e25de28c104b48d8f52daecaead312ddf3d13 Mon Sep 17 00:00:00 2001 From: yanas Date: Thu, 28 Apr 2016 14:32:02 -0500 Subject: [PATCH 19/27] Add support for connection optimisation URL param --- connection_optimization/do_external_connect.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/connection_optimization/do_external_connect.js b/connection_optimization/do_external_connect.js index b4b9fbc58..bcd632584 100644 --- a/connection_optimization/do_external_connect.js +++ b/connection_optimization/do_external_connect.js @@ -12,23 +12,13 @@ * 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 url = config.externalConnectUrl; + var params = getConfigParamsFromUrl(); + + var url = params["config.externalConnectUrl"] || config.externalConnectUrl; /** * Check if connect from connection.js was executed and executes the handler @@ -64,7 +54,7 @@ function buildToken(){ url += "?room=" + room_name; - var token = buildToken(); + var token = params["config.token"] || config.token; if(token) url += "&token=" + token; From c2f46a5cfe4f5354dcfb747b2843b6dac4dbf014 Mon Sep 17 00:00:00 2001 From: yanas Date: Thu, 28 Apr 2016 11:54:10 -0500 Subject: [PATCH 20/27] Refactor shared video manager --- conference.js | 8 +-- modules/UI/UI.js | 12 ++-- modules/UI/shared_video/SharedVideo.js | 97 +++++++++++++------------- 3 files changed, 60 insertions(+), 57 deletions(-) diff --git a/conference.js b/conference.js index 2c192c6a0..b6b33d491 100644 --- a/conference.js +++ b/conference.js @@ -762,7 +762,7 @@ export default { 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); }); @@ -1130,14 +1130,14 @@ export default { this.commands.defaults.SHARED_VIDEO, ({value, attributes}, id) => { if (attributes.state === 'stop') { - APP.UI.stopSharedVideo(id, attributes); + APP.UI.onSharedVideoStop(id, attributes); } else if (attributes.state === 'start') { - APP.UI.showSharedVideo(id, value, attributes); + 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); } }); }, diff --git a/modules/UI/UI.js b/modules/UI/UI.js index 362979b66..3b3a88c98 100644 --- a/modules/UI/UI.js +++ b/modules/UI/UI.js @@ -1116,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); }; /** @@ -1127,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); }; /** @@ -1137,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; diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index f522d29a3..631735d9d 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -79,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; @@ -153,6 +154,10 @@ 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) { @@ -160,19 +165,19 @@ export default class SharedVideoManager { if(self.initialAttributes) { - self.processAttributes( + // If a network update has occurred already now is the + // time to process it. + self.processVideoUpdate( self.player, - self.initialAttributes, - false); + self.initialAttributes); self.initialAttributes = null; } - self.smartMute(); - self.updateCheck(); + self.smartAudioMute(); } else if (event.data == YT.PlayerState.PAUSED) { - self.smartUnmute(); - self.updateCheck(true); + self.smartAudioUnmute(); } + self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED); }; /** @@ -182,7 +187,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); } }; @@ -191,14 +196,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) { - self.smartMute(); + self.smartAudioMute(); } else if (event.data.volume <=0 || event.data.muted) { - self.smartUnmute(); + self.smartAudioUnmute(); } }; @@ -230,7 +235,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); } }; @@ -246,28 +251,24 @@ 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); + // If our player is currently paused force the seek. + this.processTime(player, attributes, isPlayerPaused); + + // Process mute. let isAttrMuted = (attributes.muted === "true"); - - // Process player unmute - if (player.isMuted() && !isAttrMuted) { - console.log("Process player unmute and smart mike mute."); - this.mutePlayer(false); - } - // Process player mute - else if (!player.isMuted() && isAttrMuted) { - console.log("Process player mute and smart mike unmute."); - this.mutePlayer(true); + if (player.isMuted() !== isAttrMuted) { + this.smartPlayerMute(isAttrMuted, true); } // Process volume @@ -280,7 +281,7 @@ export default class SharedVideoManager { this.showSharedVideoMutedPopup(false); } - if (playerPaused) + if (isPlayerPaused) player.playVideo(); } else if (attributes.state == 'pause') { @@ -288,8 +289,6 @@ export default class SharedVideoManager { player.pauseVideo(); this.processTime(player, attributes, true); - } else if (attributes.state == 'stop') { - this.stopSharedVideo(this.from); } } @@ -323,7 +322,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 @@ -356,22 +355,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.player.getPlayerState() === YT.PlayerState.PAUSED)); + this.processVideoUpdate(this.player, attributes); } } @@ -381,7 +379,7 @@ 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; @@ -421,7 +419,7 @@ export default class SharedVideoManager { this.errorInPlayer.destroy(); this.errorInPlayer = null; } - this.smartUnmute(); + this.smartAudioUnmute(); // revert to original behavior (prevents pausing // for participants not sharing the video to pause it) $("#sharedVideo").css("pointer-events","auto"); @@ -446,27 +444,32 @@ export default class SharedVideoManager { this.mutedWithUserInteraction = userInteraction; } else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) { - this.mutePlayer(true); + 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. */ - mutePlayer(mute) { + smartPlayerMute(mute, isVideoUpdate) { if (!this.player.isMuted() && mute) { this.player.mute(); - this.smartUnmute(); + + if (isVideoUpdate) + this.smartAudioUnmute(); } else if (this.player.isMuted() && !mute) { this.player.unMute(); - this.smartMute(); + if (isVideoUpdate) + this.smartAudioMute(); } - // Check if we need to update other participants - this.updateCheck(); - this.showSharedVideoMutedPopup(mute); } @@ -475,7 +478,7 @@ export default class SharedVideoManager { * by the user via the mike button and the volume of the shared video is on * we're unmuting the mike automatically. */ - smartUnmute() { + smartAudioUnmute() { if (APP.conference.isLocalAudioMuted() && !this.mutedWithUserInteraction && !this.isSharedVideoVolumeOn()) { @@ -489,7 +492,7 @@ export default class SharedVideoManager { * Smart mike mute. If the mike isn't currently muted and the shared video * volume is on we mute the mike. */ - smartMute() { + smartAudioMute() { if (!APP.conference.isLocalAudioMuted() && this.isSharedVideoVolumeOn()) { From d95b2b034b078c9eb7bf38303a5bc09cf02e206a Mon Sep 17 00:00:00 2001 From: yanas Date: Thu, 28 Apr 2016 17:42:52 -0500 Subject: [PATCH 21/27] Fix initial state of user interaction mute --- modules/UI/shared_video/SharedVideo.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js index 631735d9d..ad4984ecc 100644 --- a/modules/UI/shared_video/SharedVideo.js +++ b/modules/UI/shared_video/SharedVideo.js @@ -98,6 +98,8 @@ 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.onLocalAudioMuted.bind(this); this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener); @@ -447,7 +449,6 @@ export default class SharedVideoManager { this.smartPlayerMute(true, false); // Check if we need to update other participants this.fireSharedVideoEvent(); - } } From edf2f8114b813bd1ed3c330e4cc5a722585d1168 Mon Sep 17 00:00:00 2001 From: yanas Date: Thu, 28 Apr 2016 17:50:28 -0500 Subject: [PATCH 22/27] Make sure remote video exist before we use it --- modules/UI/videolayout/VideoLayout.js | 42 +++++++++++++++++++-------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index dc21fdcd0..4058de5aa 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -207,7 +207,7 @@ var VideoLayout = { if (APP.conference.isLocalId(id)) { video = localVideoThumbnail; } - else if (remoteVideos[id]) { + else { video = remoteVideos[id]; } @@ -423,7 +423,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); }, /** @@ -496,9 +498,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); } } }, @@ -510,8 +516,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)) { @@ -528,7 +535,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); } }, @@ -650,9 +659,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)) @@ -753,8 +766,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); } }, @@ -763,15 +777,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(); }, From d53576564830e61477e59958cdd65359d752a059 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 29 Apr 2016 11:46:24 -0500 Subject: [PATCH 23/27] Fixes issue with externalConnectUrl hash param when the value is null --- connection_optimization/do_external_connect.js | 7 +++++-- modules/API/API.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/connection_optimization/do_external_connect.js b/connection_optimization/do_external_connect.js index bcd632584..98014eafb 100644 --- a/connection_optimization/do_external_connect.js +++ b/connection_optimization/do_external_connect.js @@ -17,8 +17,11 @@ */ (function () { var params = getConfigParamsFromUrl(); - - var url = params["config.externalConnectUrl"] || config.externalConnectUrl; + + //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 diff --git a/modules/API/API.js b/modules/API/API.js index 28236e124..f15de8bb5 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -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; } /** From ab67b42eb93ddaf40751443e5ccf37831f0c6113 Mon Sep 17 00:00:00 2001 From: yanas Date: Sun, 1 May 2016 13:35:18 -0500 Subject: [PATCH 24/27] Hide recorder local thumbnail --- css/videolayout_default.css | 3 ++ modules/UI/recording/Recording.js | 3 +- modules/UI/util/UIUtil.js | 9 ++++++ modules/UI/videolayout/FilmStrip.js | 43 +++++++++++++++++++-------- modules/UI/videolayout/LocalVideo.js | 24 ++++++++++++++- modules/UI/videolayout/VideoLayout.js | 8 +++++ 6 files changed, 75 insertions(+), 15 deletions(-) diff --git a/css/videolayout_default.css b/css/videolayout_default.css index 0fdde1424..4767ec059 100644 --- a/css/videolayout_default.css +++ b/css/videolayout_default.css @@ -519,4 +519,7 @@ margin-left: auto; background: rgba(0,0,0,.3); color: rgba(255,255,255,.5); +} + +.hidden { } \ No newline at end of file diff --git a/modules/UI/recording/Recording.js b/modules/UI/recording/Recording.js index fdf92f073..53e9ac949 100644 --- a/modules/UI/recording/Recording.js +++ b/modules/UI/recording/Recording.js @@ -228,7 +228,8 @@ var Recording = { // everyone. if (config.iAmRecorder) { VideoLayout.enableDeviceAvailabilityIcons( - APP.conference.localId, true); + APP.conference.localId, false); + VideoLayout.setLocalVideoVisible(false); Feedback.enableFeedback(false); Toolbar.enable(false); BottomToolbar.enable(false); diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js index 0e37b5b11..18c78e717 100644 --- a/modules/UI/util/UIUtil.js +++ b/modules/UI/util/UIUtil.js @@ -199,6 +199,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; } }; diff --git a/modules/UI/videolayout/FilmStrip.js b/modules/UI/videolayout/FilmStrip.js index 7bdb9245b..27c3b4875 100644 --- a/modules/UI/videolayout/FilmStrip.js +++ b/modules/UI/videolayout/FilmStrip.js @@ -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); } }; diff --git a/modules/UI/videolayout/LocalVideo.js b/modules/UI/videolayout/LocalVideo.js index 09eeaa7f2..09b10184e 100644 --- a/modules/UI/videolayout/LocalVideo.js +++ b/modules/UI/videolayout/LocalVideo.js @@ -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; diff --git a/modules/UI/videolayout/VideoLayout.js b/modules/UI/videolayout/VideoLayout.js index 4058de5aa..3bb02ca9d 100644 --- a/modules/UI/videolayout/VideoLayout.js +++ b/modules/UI/videolayout/VideoLayout.js @@ -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. From 0970fdd7e7dadc6ec754c83ff448a0e0dca8d83a Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 2 May 2016 14:09:57 -0500 Subject: [PATCH 25/27] Clears external connect data after using it --- connection.js | 1 + 1 file changed, 1 insertion(+) diff --git a/connection.js b/connection.js index d66dd24f3..97fa602d8 100644 --- a/connection.js +++ b/connection.js @@ -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}); } From 6b5f6ec7044ae7fc1584b757ce08ecc072eac8c0 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 2 May 2016 14:22:02 -0500 Subject: [PATCH 26/27] Fixes issue with multiple room query parameters added to bosh url --- connection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/connection.js b/connection.js index 97fa602d8..d5f405448 100644 --- a/connection.js +++ b/connection.js @@ -52,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( From d6ef36b4b4322f4bd0f1dcba00e24b53afe24baa Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 2 May 2016 14:47:40 -0500 Subject: [PATCH 27/27] Passes the room name to connect when using authentication --- connection.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/connection.js b/connection.js index d5f405448..5add17e48 100644 --- a/connection.js +++ b/connection.js @@ -96,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} */ -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) { @@ -156,7 +157,7 @@ export function openConnection({id, password, retry, roomName}) { if (config.token) { throw err; } else { - return requestAuth(); + return requestAuth(roomName); } } else { throw err;