@@ -63,6 +63,7 @@
"app.userList.presenter": "Ведущий",
"app.userList.you": "Вы",
"app.userList.locked": "Заблокировано",
"app.userList.byModerator": "(Модератором)",
"app.userList.label": "Список пользователей",
"app.userList.toggleCompactView.label": "Включить/выключить компактный вид",
"app.userList.guest": "Гость",
@@ -109,6 +110,9 @@
"app.userList.userOptions.enableNote": "Общие заметки теперь включены",
"app.userList.userOptions.showUserList": "Список пользователей теперь виден участникам",
"app.userList.userOptions.enableOnlyModeratorWebcam": "Теперь вы можете включить вашу вэб-камеру, и все вас увидят",
"app.userList.userOptions.savedNames.title": "Список пользователей на конференции {0} из {1}",
"app.userList.userOptions.sortedFirstName.heading": "Отсортировано по имени:",
"app.userList.userOptions.sortedLastName.heading": "Отсортировано по фамилии:",
"app.media.label": "Медиа",
"app.media.autoplayAlertDesc": "Разрешить доступ",
"app.media.screenshare.start": "Демонстрация экрана началась",
@@ -125,6 +129,10 @@
"app.meeting.meetingTimeRemaining": "До окончания конференции осталось: {0}",
"app.meeting.meetingTimeHasEnded": "Время вышло. Конференция скоро закроется.",
"app.meeting.endedMessage": "Вы будете перенаправлены назад на главный экран",
"app.meeting.alertMeetingEndsUnderMinutesSingular": "Встреча закрывается через минуту.",
"app.meeting.alertMeetingEndsUnderMinutesPlural": "Встреча закрывается через {0} минут.",
"app.meeting.alertBreakoutEndsUnderMinutesPlural": "Перерыв заканчивается через {0} минут.",
"app.meeting.alertBreakoutEndsUnderMinutesSingular": "Перерыв заканчивается через одну минуту.",
"app.presentation.hide": "Скрыть презентацию",
"app.presentation.notificationLabel": "Текущая презентация",
"app.presentation.slideContent": "Содержимое слайда",
@@ -171,7 +179,9 @@
"app.presentationUploder.rejectedError": "Загрузка выбранных файлов была отклонена. Пожалуйста проверьте тип файла (файлов)",
"app.presentationUploder.upload.progress": "Загрузка ({0}%)",
"app.presentationUploder.upload.413": "Файл слишком большой. Пожалуйста, разделите его на несколько файлов меньшего размера.",
"app.presentationUploder.upload.408": "Талон запроса на загрузку истёк.",
"app.presentationUploder.upload.404": "404: Неправильный токен загрузки",
"app.presentationUploder.upload.401": "Талон запроса на загрузку презентации истёк.",
"app.presentationUploder.conversion.conversionProcessingSlides": "Обработка страницы {0} из {1}",
"app.presentationUploder.conversion.genericConversionStatus": "Файл конвертируется...",
"app.presentationUploder.conversion.generatingThumbnail": "Создаются изображения для предварительного просмотра...",
@@ -183,8 +193,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Мы не смогли сконвертировать PDF файл. Пожалуйста, попробуйте оптимизировать его.",
"app.presentationUploder.conversion.timeout": "Ой, конвертация занимает слишком много времени...",
"app.presentationUploder.conversion.pageCountFailed": "Не удалось определить количество страниц.",
"app.presentationUploder.isDownloadableLabel": "Не разрешать скачивание презентации",
"app.presentationUploder.isNotDownloadableLabel": "Разрешить скачивание презентации",
"app.presentationUploder.removePresentationLabel": "Удалить презентацию",
"app.presentationUploder.setAsCurrentPresentation": "Сделать презентацию текущей",
"app.presentationUploder.tableHeading.filename": "Имя файла",
@@ -262,6 +270,7 @@
"app.leaveConfirmation.confirmLabel": "Выйти",
"app.leaveConfirmation.confirmDesc": "Выйти из конференции",
"app.endMeeting.title": "Закончить конференцию",
"app.endMeeting.description": "Вы уверены, что хотите завершить встречу для всех (все пользователи будут отключены)?",
"app.endMeeting.yesLabel": "Да",
"app.endMeeting.noLabel": "Нет",
"app.about.title": "О программе",
@@ -534,16 +543,25 @@
"app.recording.stopDescription": "Вы уверены, что хотите приостановить запись? Вы можете возобновить запись, повторно нажав кнопку записи.",
"app.videoPreview.cameraLabel": "Камера",
"app.videoPreview.profileLabel": "Качество",
"app.videoPreview.quality.low": "Низкое качество",
"app.videoPreview.quality.medium": "Среднее качество",
"app.videoPreview.quality.high": "Высокое качество",
"app.videoPreview.quality.hd": "Высокое разрешение",
"app.videoPreview.cancelLabel": "Отмена",
"app.videoPreview.closeLabel": "Закрыть",
"app.videoPreview.findingWebcamsLabel": "Ищем вэбкамеры",
"app.videoPreview.startSharingLabel": "Начать трансляцию с вэб-камеры",
"app.videoPreview.stopSharingLabel": "Прекратить трансляцию",
"app.videoPreview.stopSharingAllLabel": "Прекратить всё",
"app.videoPreview.sharedCameraLabel": "Камера уже транслируется",
"app.videoPreview.webcamOptionLabel": "Выбрать вэбкамеру",
"app.videoPreview.webcamPreviewLabel": "Предварительный просмотр вэбкамеры",
"app.videoPreview.webcamSettingsTitle": "Настройки вэбкамеры",
"app.videoPreview.webcamNotFoundLabel": "Вэбкамера не обнаружена",
"app.videoPreview.profileNotFoundLabel": "Не поддерживается профиль вэбкамеры",
"app.video.joinVideo": "Транслировать веб-камеру",
"app.video.connecting": "Трансляция вебкамеры запускается...",
"app.video.dataSaving": "Трансляция вебкамеры отключена в Сохранении данных",
"app.video.leaveVideo": "Прекратить транслировать вэбкамеру",
"app.video.iceCandidateError": "Ошибка добавления ICE кандидата",
"app.video.iceConnectionStateError": "Connection failure (ICE error 1107)",
@@ -561,12 +579,14 @@
"app.video.swapCam": "Заменить",
"app.video.swapCamDesc": "поменять направление веб-камер",
"app.video.videoLocked": "Вэбкамеры заблокированы",
"app.video.videoButtonDesc": "Транслировать веб-камеру",
"app.video.videoMenu": "Меню видео",
"app.video.videoMenuDisabled": "Меню видео веб-камеры отключено в настройках",
"app.video.videoMenuDesc": "Открыть выпадающее меню видео",
"app.video.chromeExtensionError": "Вы должны установить",
"app.video.chromeExtensionErrorLink": "это расширение Chrome",
"app.video.pagination.prevPage": "Посмотреть предыдущие видео",
"app.video.pagination.nextPage": "Посмотреть следующие видео",
"app.video.clientDisconnected": "Вебкамера не может быть транслирована в связи с проблемами соединения",
"app.fullscreenButton.label": "Включить {0} на полный экран",
"app.deskshare.iceConnectionStateError": "Не удалось установить соединение при совместном просмотре экрана (ICE error 1108)",
"app.sfu.mediaServerConnectionError2000": "Невозможно подключиться к медиа-серверу (error 2000)",
@@ -580,6 +600,7 @@
"app.sfu.noAvailableCodec2203": "Серверу не удалось найти подходящий кодек (error 2203)",
"app.meeting.endNotification.ok.label": "ОК",
"app.whiteboard.annotations.poll": "Результаты опроса были опубликованы",
"app.whiteboard.annotations.pollResult": "Результат опроса",
"app.whiteboard.toolbar.tools": "Инструменты",
"app.whiteboard.toolbar.tools.hand": "Панорамирование",
"app.whiteboard.toolbar.tools.pencil": "Карандаш",
@@ -179,8 +179,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Мы не смогли сконвертировать PDF файл. Пожалуйста, попробуйте оптимизировать его.",
"app.presentationUploder.conversion.timeout": "Ой, конвертация занимает слишком много времени...",
"app.presentationUploder.conversion.pageCountFailed": "Ошибка при определении количества страниц.",
"app.presentationUploder.isDownloadableLabel": "Не разрешать скачивание презентации",
"app.presentationUploder.isNotDownloadableLabel": "Разрешить скачивание презентации",
"app.presentationUploder.removePresentationLabel": "Удалить презентацию",
"app.presentationUploder.setAsCurrentPresentation": "Сделать презентацию текущей",
"app.presentationUploder.tableHeading.filename": "Имя файла",
@@ -555,7 +553,6 @@
"app.video.swapCam": "Заменить",
"app.video.swapCamDesc": "поменять направление веб-камер",
"app.video.videoLocked": "Вэбкамеры заблокированы",
"app.video.videoButtonDesc": "Транслировать веб-камеру",
"app.video.videoMenu": "Меню видео",
"app.video.videoMenuDisabled": "Меню видео веб-камеры отключено в настройках",
"app.video.videoMenuDesc": "Открыть выпадающее меню видео",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Nebolo možné skonvertovať .PDF súbor, prosím skúste ho optimalizovať",
"app.presentationUploder.conversion.timeout": "Ops, konverzia trvala príliš dlho",
"app.presentationUploder.conversion.pageCountFailed": "Nepodarilo sa zistiť počet strán.",
"app.presentationUploder.isDownloadableLabel": "Zakázať sťahovanie prezentácie",
"app.presentationUploder.isNotDownloadableLabel": "Zakázať sťahovanie prezentácie",
"app.presentationUploder.removePresentationLabel": "Odstrániť prezentáciu",
"app.presentationUploder.setAsCurrentPresentation": "Nastaviť prezentáciu ako aktívnu",
"app.presentationUploder.tableHeading.filename": "Názov súboru",
@@ -555,7 +553,6 @@
"app.video.swapCam": "Obrátiť",
"app.video.swapCamDesc": "Obrátiť smer webkamier",
"app.video.videoLocked": "Zdieľanie webkamery uzamknuté",
"app.video.videoButtonDesc": "Zdieľať webkameru",
"app.video.videoMenu": "Video menu",
"app.video.videoMenuDisabled": "Video menu webkamery je vypnuté v nastaveniach",
"app.video.videoMenuDesc": "Otvoriť video menu",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Ni mogoče pretvoriti datoteke PDF. Poskusite jo shraniti v drugi različici.",
"app.presentationUploder.conversion.timeout": "Ojoj, pretvorba je trajala malce predolgo.",
"app.presentationUploder.conversion.pageCountFailed": "Ni mogoče določiti števila strani dokumenta.",
"app.presentationUploder.isDownloadableLabel": "Ne dovoli prejema predstavitve",
"app.presentationUploder.isNotDownloadableLabel": "Dovoli prejem predstavitve",
"app.presentationUploder.removePresentationLabel": "Odstrani predstavitev",
"app.presentationUploder.setAsCurrentPresentation": "Nastavi predstavitev kot trenutno",
"app.presentationUploder.tableHeading.filename": "Ime datoteke",
@@ -569,7 +567,6 @@
"app.video.swapCam": "Zamenjaj",
"app.video.swapCamDesc": "zamenjaj smer spletnih kamer",
"app.video.videoLocked": "Uporaba spletne kamere je zaklenjena",
"app.video.videoButtonDesc": "Prikaz spletne kamere",
"app.video.videoMenu": "Meni videa",
"app.video.videoMenuDisabled": "Meni spletne kamere je med nastavitvami onemogočen",
"app.video.videoMenuDesc": "Odpre spustno polje menija videa",
@@ -174,8 +174,6 @@
"app.presentationUploder.conversion.generatingSvg": "Kreiranje SVG slika ...",
"app.presentationUploder.conversion.pdfHasBigPage": "Nismo uspeli da konvertujemo PDF fajl, probajte da ga optimizujete",
"app.presentationUploder.conversion.timeout": "Ups, konverzija traje predugo",
"app.presentationUploder.isDownloadableLabel": "Onemogućite preuzimanje prezentacije",
"app.presentationUploder.isNotDownloadableLabel": "Dozvolite preuzimanje prezentacije",
"app.presentationUploder.removePresentationLabel": "Uklonite prezentaciju",
"app.presentationUploder.setAsCurrentPresentation": "Postavite prezentaciju kao trenutno aktivnu",
"app.presentationUploder.tableHeading.filename": "Ime fajla",
@@ -540,7 +538,6 @@
"app.video.swapCam": "Zamenite",
"app.video.swapCamDesc": "Promenite smer prikaza veb kamera",
"app.video.videoLocked": "Deljenje prikaza sa veb kamera je zaključano",
"app.video.videoButtonDesc": "Podelite prikaz sa veb kamere",
"app.video.videoMenu": "Video meni",
"app.video.videoMenuDisabled": "Video meni za veb kamere je onemogućen u podešavanjima",
"app.video.videoMenuDesc": "Otvori meni za video",
@@ -168,8 +168,6 @@
"app.presentationUploder.conversion.generatedSlides": "Bildspel genererade ...",
"app.presentationUploder.conversion.generatingSvg": "Genererar SVG bilder ...",
"app.presentationUploder.conversion.timeout": "Hoppsan, konverteringen tog för lång tid",
"app.presentationUploder.isDownloadableLabel": "Tillåt inte presentationen att kunna laddas ner",
"app.presentationUploder.isNotDownloadableLabel": "Tillåt presentationen att kunna laddas ner",
"app.presentationUploder.removePresentationLabel": "Ta bort presentationen",
"app.presentationUploder.setAsCurrentPresentation": "Ange presentation som aktuell",
"app.presentationUploder.tableHeading.filename": "Filnamn",
@@ -513,7 +511,6 @@
"app.video.swapCam": "Byta",
"app.video.swapCamDesc": "byta riktning av webbkameror",
"app.video.videoLocked": "Webbkamera delning låst",
"app.video.videoButtonDesc": "Dela webbkamera",
"app.video.videoMenu": "Videomeny",
"app.video.videoMenuDisabled": "Videomenyn Webbkamera är inaktiverad i inställningarna",
"app.video.videoMenuDesc": "Öppna videomenyns rullgardin",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "మేము PDF ఫైల్‌ను మార్చలేకపోయాము, దయచేసి దాన్ని అనుగుణంగా చేయడానికి ప్రయత్నించండి",
"app.presentationUploder.conversion.timeout": "అయ్యో, మార్పిడి చాలా సమయం పట్టింది",
"app.presentationUploder.conversion.pageCountFailed": "పేజీల సంఖ్యను నిర్ణయించడంలో విఫలమైంది.",
"app.presentationUploder.isDownloadableLabel": "ప్రదర్శనను డౌన్‌లోడ్ చేయడానికి అనుమతించవద్దు",
"app.presentationUploder.isNotDownloadableLabel": "ప్రదర్శనను డౌన్‌లోడ్ చేయడానికి అనుమతించండి",
"app.presentationUploder.removePresentationLabel": "ప్రదర్శనను తొలగించండి",
"app.presentationUploder.setAsCurrentPresentation": "ప్రదర్శనను ప్రస్తుతంగా సెట్ చేయండి",
"app.presentationUploder.tableHeading.filename": "ఫైల్ పేరు",
@@ -572,7 +570,6 @@
"app.video.swapCam": "మార్పిడి",
"app.video.swapCamDesc": "వెబ్‌క్యామ్‌ల దిశను మార్చండి",
"app.video.videoLocked": "వెబ్‌క్యామ్ షేరింగ్ ,లాక్ చేయబడింది",
"app.video.videoButtonDesc": "వెబ్‌క్యామ్‌ను షేర్ చేయండి",
"app.video.videoMenu": "వీడియో మెను",
"app.video.videoMenuDisabled": "వీడియో మెను సెట్టింగ్‌లలో వెబ్‌క్యామ్ నిలిపివేయబడింది",
"app.video.videoMenuDesc": "వీడియో మెను డ్రాప్‌డౌన్ తెరవండి",
@@ -178,8 +178,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "เราไม่สามารถแปลงไฟล์ PDF ได้โปรดลองเพิ่มประสิทธิภาพ",
"app.presentationUploder.conversion.timeout": "Ops การแปลงใช้เวลานานเกินไป",
"app.presentationUploder.conversion.pageCountFailed": "ไม่สามารถระบุจำนวนหน้าได้",
"app.presentationUploder.isDownloadableLabel": "ไม่อนุญาตให้ดาวน์โหลดงานนำเสนอ",
"app.presentationUploder.isNotDownloadableLabel": "อนุญาตให้ดาวน์โหลดงานนำเสนอ",
"app.presentationUploder.removePresentationLabel": "ลบงานนำเสนอ",
"app.presentationUploder.setAsCurrentPresentation": "ตั้งค่าการนำเสนอเป็นปัจจุบัน",
"app.presentationUploder.tableHeading.filename": "ชื่อไฟล์",
@@ -542,7 +540,6 @@
"app.video.swapCam": "สลับ",
"app.video.swapCamDesc": "สลับทิศทางของเว็บแคม",
"app.video.videoLocked": "การแชร์เว็บแคมถูกล็อค",
"app.video.videoButtonDesc": "แชร์เว็บแคม",
"app.video.videoMenu": "เมนูวิดีโอ",
"app.video.videoMenuDisabled": "เมนูวิดีโอเว็บแคมถูกปิดใช้งานในการตั้งค่า",
"app.video.videoMenuDesc": "เปิดเมนูวิดีโอแบบเลื่อนลง",
@@ -174,8 +174,6 @@
"app.presentationUploder.conversion.generatingSvg": "กำลังสร้างภาพ SVG ...",
"app.presentationUploder.conversion.pdfHasBigPage": "เราไม่สามารถแปลงไฟล์ PDF ได้โปรดลองเพิ่มประสิทธิภาพ",
"app.presentationUploder.conversion.timeout": "Ops การแปลงใช้เวลานานเกินไป",
"app.presentationUploder.isDownloadableLabel": "ไม่อนุญาตให้ดาวน์โหลดงานนำเสนอ",
"app.presentationUploder.isNotDownloadableLabel": "อนุญาตให้ดาวน์โหลดงานนำเสนอ",
"app.presentationUploder.removePresentationLabel": "ลบงานนำเสนอ",
"app.presentationUploder.setAsCurrentPresentation": "ตั้งค่าการนำเสนอเป็นปัจจุบัน",
"app.presentationUploder.tableHeading.filename": "ชื่อไฟล์",
@@ -538,7 +536,6 @@
"app.video.swapCam": "สลับ",
"app.video.swapCamDesc": "สลับทิศทางของเว็บแคม",
"app.video.videoLocked": "การแชร์เว็บแคมถูกล็อค",
"app.video.videoButtonDesc": "แชร์เว็บแคม",
"app.video.videoMenu": "เมนูวิดีโอ",
"app.video.videoMenuDisabled": "เมนูวิดีโอเว็บแคมถูกปิดใช้งานในการตั้งค่า",
"app.video.videoMenuDesc": "เปิดเมนูวิดีโอแบบเลื่อนลง",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "PDF dosyası dönüştürülemedi, lütfen iyileştirmeyi deneyin",
"app.presentationUploder.conversion.timeout": "Sorun var, dönüşüm çok uzun sürdü",
"app.presentationUploder.conversion.pageCountFailed": "Sayfa sayısı belirlenemedi.",
"app.presentationUploder.isDownloadableLabel": "Sunum indirilemesin",
"app.presentationUploder.isNotDownloadableLabel": "Sunum indirilebilsin",
"app.presentationUploder.removePresentationLabel": "Sunumu kaldır",
"app.presentationUploder.setAsCurrentPresentation": "Sunumu geçerli olarak ayarla",
"app.presentationUploder.tableHeading.filename": "Dosya adı",
@@ -569,7 +567,6 @@
"app.video.swapCam": "Değiştir",
"app.video.swapCamDesc": "kameraların yönünü değiştir",
"app.video.videoLocked": "Kamera paylaşımı kilitli",
"app.video.videoButtonDesc": "Kamerayı paylaş",
"app.video.videoMenu": "Görüntü menüsü",
"app.video.videoMenuDisabled": "Video menüsü Web kamerası ayarlarında devre dışı",
"app.video.videoMenuDesc": "Görüntü menüsü listesini aç",
@@ -186,8 +186,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "PDF dosyasını dönüştüremedik, lütfen optimize etmeyi deneyin",
"app.presentationUploder.conversion.timeout": "Hata, dönüşüm çok uzun sürdü",
"app.presentationUploder.conversion.pageCountFailed": "Sayfa sayısı belirlenemiyor.",
"app.presentationUploder.isDownloadableLabel": "Sunumun indirilmesine izin verme",
"app.presentationUploder.isNotDownloadableLabel": "Sunumun indirilmesine izin ver",
"app.presentationUploder.removePresentationLabel": "Sunumu kaldır",
"app.presentationUploder.setAsCurrentPresentation": "Sunumu varsayılan olarak ayarla",
"app.presentationUploder.tableHeading.filename": "Dosya adı",
@@ -564,7 +562,6 @@
"app.video.swapCam": "Değiştir",
"app.video.swapCamDesc": "Kameraların yönünü değiştir",
"app.video.videoLocked": "Web kamerası paylaşımı kapalı",
"app.video.videoButtonDesc": "Web kamerası paylaş",
"app.video.videoMenu": "Video menüsü",
"app.video.videoMenuDisabled": "Video menüsü Web kamerası ayarlarında devre dışı",
"app.video.videoMenuDesc": "Video menüsünü liste olarak aç",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Неможливо конвертувати PDF-файл. Будь ласка, спробуйте оптимізувати його.",
"app.presentationUploder.conversion.timeout": "Ой, перетворення займає надто багато часу",
"app.presentationUploder.conversion.pageCountFailed": "Не вийшло визначити кількість сторінок.",
"app.presentationUploder.isDownloadableLabel": "Заборонити звантаження презентації",
"app.presentationUploder.isNotDownloadableLabel": "Дозволити звантажувати презентацію",
"app.presentationUploder.removePresentationLabel": "Вилучити презентацію",
"app.presentationUploder.setAsCurrentPresentation": "Встановити презентацію поточною",
"app.presentationUploder.tableHeading.filename": "Ім'я файлу",
@@ -569,7 +567,6 @@
"app.video.swapCam": "Змінити",
"app.video.swapCamDesc": "змінити фокус вебкамери",
"app.video.videoLocked": "Трансляцію вебкамери заблоковано",
"app.video.videoButtonDesc": "Увімкнути вебкамеру",
"app.video.videoMenu": "Меню відео",
"app.video.videoMenuDisabled": "Меню відео: вебкамеру вимкнено у налаштуваннях",
"app.video.videoMenuDesc": "Відкрити контекстне меню відео",
@@ -178,8 +178,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "Chúng tôi không thể chuyển thành PDF, vui lòng tối ưu hóa nó",
"app.presentationUploder.conversion.timeout": "Ops, sự thay đổi mất một khoảng thời gian",
"app.presentationUploder.conversion.pageCountFailed": "Lỗi không xác định được số trang",
"app.presentationUploder.isDownloadableLabel": "Không cho phép tải xuống phần trình bày",
"app.presentationUploder.isNotDownloadableLabel": "Cho phép tải xuống phần trình bày",
"app.presentationUploder.removePresentationLabel": "Xóa phần trình bày",
"app.presentationUploder.setAsCurrentPresentation": "Thiết lập phần trình bày hiện tại",
"app.presentationUploder.tableHeading.filename": "Tên file",
@@ -542,7 +540,6 @@
"app.video.swapCam": "Đổi",
"app.video.swapCamDesc": "Đổi vị trí các webcam",
"app.video.videoLocked": "Chia sẻ webcam đã khóa",
"app.video.videoButtonDesc": "Chia sẻ webcam",
"app.video.videoMenu": "Menu video",
"app.video.videoMenuDisabled": "menu video webcam không khả đụng trong mục cài đặt",
"app.video.videoMenuDesc": "Mở thanh menu video trượt xuống",
@@ -193,8 +193,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "无法转换PDF文件,请尝试优化它",
"app.presentationUploder.conversion.timeout": "糟糕,格式转换耗费了太长时间",
"app.presentationUploder.conversion.pageCountFailed": "无法确定页数。",
"app.presentationUploder.isDownloadableLabel": "不允许演示文件被下载",
"app.presentationUploder.isNotDownloadableLabel": "允许演示文件被下载",
"app.presentationUploder.removePresentationLabel": "删除演示文件",
"app.presentationUploder.setAsCurrentPresentation": "设置该文件为当前演示文件",
"app.presentationUploder.tableHeading.filename": "文件名",
@@ -578,7 +576,6 @@
"app.video.swapCam": "切换",
"app.video.swapCamDesc": "切换前置/后置摄像头",
"app.video.videoLocked": "摄像头分享已被锁定",
"app.video.videoButtonDesc": "分享摄像头",
"app.video.videoMenu": "视频菜单",
"app.video.videoMenuDisabled": "视频菜单摄像头在设置中被禁用 ",
"app.video.videoMenuDesc": "打开视频下拉菜单",
@@ -190,8 +190,6 @@
"app.presentationUploder.conversion.pdfHasBigPage": "我們沒法轉換這個PDF檔,請嚐試優化他。",
"app.presentationUploder.conversion.timeout": "哎呀,轉移時間花太久了。",
"app.presentationUploder.conversion.pageCountFailed": "頁數無法確認",
"app.presentationUploder.isDownloadableLabel": "不允許簡報被下載",
"app.presentationUploder.isNotDownloadableLabel": "允許簡報被下載",
"app.presentationUploder.removePresentationLabel": "移除簡報",
"app.presentationUploder.setAsCurrentPresentation": "設為當前簡報",
"app.presentationUploder.tableHeading.filename": "檔名",
@@ -573,7 +571,6 @@
"app.video.swapCam": "切換",
"app.video.swapCamDesc": "切換前置/後置鏡頭",
"app.video.videoLocked": "網路攝影機分享已被鎖定",
"app.video.videoButtonDesc": "分享網路攝影機",
"app.video.videoMenu": "視訊選單",
"app.video.videoMenuDisabled": "視訊選單網路攝影機在設定中已停用",
"app.video.videoMenuDesc": "打開視訊下拉選單",
@@ -357,6 +357,11 @@ Kurento.prototype.startResponse = function (message) {

return this.onFail(error);
}

this.logger.info({
logCode: 'kurentoextension_process_answer',
}, `Answer processed with success`);

// Mark the peer as negotiated and flush the ICE queue
this.webRtcPeer.negotiated = true;
this.processIceQueue();

Large diffs are not rendered by default.

@@ -215,6 +215,16 @@ allowModsToUnmuteUsers=false
# Saves meeting events even if the meeting is not recorded
keepEvents=false

# Timeout (millis) to remove a joined user after her/his left event without a rejoin
# e.g. regular user left event
# Default 60s
usersTimeout=60000

# Timeout (millis) to remove users that called the enter API but did not join
# e.g. user's client hanged between the enter call and join event
# Default 45s
enteredUsersTimeout=45000

#----------------------------------------------------
# This URL is where the BBB client is accessible. When a user sucessfully
# enters a name and password, she is redirected here to load the client.
@@ -33,7 +33,8 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
</property>
</bean>

<bean id="registeredUserCleanupTimerTask" class="org.bigbluebutton.web.services.RegisteredUserCleanupTimerTask"/>
<bean id="userCleanupTimerTask" class="org.bigbluebutton.web.services.UserCleanupTimerTask"/>
<bean id="enteredUserCleanupTimerTask" class="org.bigbluebutton.web.services.EnteredUserCleanupTimerTask"/>

<bean id="keepAliveService" class="org.bigbluebutton.web.services.KeepAliveService"
init-method="start" destroy-method="stop">
@@ -47,10 +48,13 @@ with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
<property name="presDownloadService" ref="presDownloadService"/>
<property name="paramsProcessorUtil" ref="paramsProcessorUtil"/>
<property name="stunTurnService" ref="stunTurnService"/>
<property name="registeredUserCleanupTimerTask" ref="registeredUserCleanupTimerTask"/>
<property name="userCleanupTimerTask" ref="userCleanupTimerTask"/>
<property name="enteredUserCleanupTimerTask" ref="enteredUserCleanupTimerTask"/>
<property name="gw" ref="bbbWebApiGWApp"/>
<property name="callbackUrlService" ref="callbackUrlService"/>
<property name="keepEvents" value="${keepEvents}"/>
<property name="usersTimeout" value="${usersTimeout}"/>
<property name="enteredUsersTimeout" value="${enteredUsersTimeout}"/>
</bean>

<bean id="oldMessageReceivedGW" class="org.bigbluebutton.api2.bus.OldMessageReceivedGW">
@@ -431,14 +431,9 @@ class ApiController {
us.avatarURL = meeting.defaultAvatarURL
}

// Register user into the meeting.
meetingService.registerUser(us.meetingID, us.internalUserId, us.fullname, us.role, us.externUserID,
us.authToken, us.avatarURL, us.guest, us.authed, guestStatusVal)
String meetingId = meeting.getInternalId()

// Validate if the maxParticipants limit has been reached based on registeredUsers. If so, complain.
// when maxUsers is set to 0, the validation is ignored
int maxUsers = meeting.getMaxUsers();
if (maxUsers > 0 && meeting.getRegisteredUsers().size() >= maxUsers) {
if (hasReachedMaxParticipants(meeting, us)) {
// BEGIN - backward compatibility
invalid("maxParticipantsReached", "The number of participants allowed for this meeting has been reached.", REDIRECT_RESPONSE);
return
@@ -449,6 +444,20 @@ class ApiController {
return;
}

// Register user into the meeting.
meetingService.registerUser(
us.meetingID,
us.internalUserId,
us.fullname,
us.role,
us.externUserID,
us.authToken,
us.avatarURL,
us.guest,
us.authed,
guestStatusVal
)

//Identify which of these to logs should be used. sessionToken or user-token
log.info("Session sessionToken for " + us.fullname + " [" + session[sessionToken] + "]")
log.info("Session user-token for " + us.fullname + " [" + session['user-token'] + "]")
@@ -1170,31 +1179,16 @@ class ApiController {

String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()
boolean reject = false
String sessionToken = null
UserSession us = null

if (StringUtils.isEmpty(params.sessionToken)) {
log.info("No session for user in conference.")
reject = true
} else {
sessionToken = StringUtils.strip(params.sessionToken)
log.info("Getting ConfigXml for SessionToken = " + sessionToken)
if (!session[sessionToken]) {
reject = true
} else {
us = meetingService.getUserSessionWithAuthToken(sessionToken);
if (us == null) reject = true
}
}

if (reject) {
String sessionToken = sanitizeSessionToken(params.sessionToken)
if (!hasValidSession(sessionToken)) {
response.addHeader("Cache-Control", "no-cache")
withFormat {
xml {
render(text: responseBuilder.buildConfgXmlReject("Could not find conference.", logoutUrl, RESP_CODE_FAILED), contentType: "text/xml")
}
}
} else {
UserSession us = getUserSession(sessionToken)
if (StringUtils.isEmpty(us.configXML)) {
// BEGIN - backward compatibility
invalid("noConfigFound", "We could not find a config for this request.", REDIRECT_RESPONSE);
@@ -1232,44 +1226,26 @@ class ApiController {
log.debug CONTROLLER_NAME + "#${API_CALL}"
ApiErrors errors = new ApiErrors()
boolean reject = false;
String sessionToken = sanitizeSessionToken(params.sessionToken)

if (StringUtils.isEmpty(params.sessionToken)) {
log.debug("SessionToken is missing.")
}

String sessionToken = StringUtils.strip(params.sessionToken)

UserSession us = null;
UserSession us = getUserSession(sessionToken);
Meeting meeting = null;
UserSession userSession = null;

if (sessionToken == null || meetingService.getUserSessionWithAuthToken(sessionToken) == null) {
if (us == null) {
log.debug("No user with session token.")
reject = true;
} else {
us = meetingService.getUserSessionWithAuthToken(sessionToken);
meeting = meetingService.getMeeting(us.meetingID);
if (meeting == null || meeting.isForciblyEnded()) {
log.debug("Meeting not found.")
reject = true
}
userSession = meetingService.getUserSessionWithAuthToken(sessionToken)
if (userSession == null) {
log.debug("Session with user not found.")
reject = true
}

}

// Determine the logout url so we can send the user there.
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()

if (us != null) {
logoutUrl = us.logoutUrl
}
String logoutUrl = us != null ? us.logoutUrl : paramsProcessorUtil.getDefaultLogoutUrl()

if (reject) {
log.info("No session for user in conference.")
response.addHeader("Cache-Control", "no-cache")
withFormat {
json {
@@ -1305,7 +1281,7 @@ class ApiController {
clientURL = params.clientURL;
}

String guestWaitStatus = userSession.guestStatus
String guestWaitStatus = us.guestStatus

log.debug("GuestWaitStatus = " + guestWaitStatus)

@@ -1393,48 +1369,34 @@ class ApiController {
def enter = {
boolean reject = false;

if (StringUtils.isEmpty(params.sessionToken)) {
println("SessionToken is missing.")
}

String sessionToken = StringUtils.strip(params.sessionToken)

UserSession us = null;
String sessionToken = sanitizeSessionToken(params.sessionToken)
UserSession us = getUserSession(sessionToken);
Meeting meeting = null;
UserSession userSession = null;

Boolean allowEnterWithoutSession = false;
// Depending on configuration, allow ENTER requests to proceed without session
if (paramsProcessorUtil.getAllowRequestsWithoutSession()) {
allowEnterWithoutSession = paramsProcessorUtil.getAllowRequestsWithoutSession();
}

String respMessage = "Session " + sessionToken + " not found."

if (!sessionToken || meetingService.getUserSessionWithAuthToken(sessionToken) == null || (!allowEnterWithoutSession && !session[sessionToken])) {
if (!hasValidSession(sessionToken)) {
reject = true;
respMessage = "Session " + sessionToken + " not found."
} else {
us = meetingService.getUserSessionWithAuthToken(sessionToken);
if (us == null) {
respMessage = "Session " + sessionToken + " not found."
meeting = meetingService.getMeeting(us.meetingID);
if (meeting == null || meeting.isForciblyEnded()) {
reject = true
respMessage = "Meeting not found or ended for session " + sessionToken + "."
} else {
meeting = meetingService.getMeeting(us.meetingID);
if (meeting == null || meeting.isForciblyEnded()) {
reject = true
respMessage = "Meeting not found or ended for session " + sessionToken + "."
}
if (us.guestStatus.equals(GuestPolicy.DENY)) {
respMessage = "User denied for user with session " + sessionToken + "."
reject = true
if (hasReachedMaxParticipants(meeting, us)) {
reject = true;
respMessage = "The number of participants allowed for this meeting has been reached.";
} else {
meeting.userEntered(us.internalUserId);
}
}
if (us.guestStatus.equals(GuestPolicy.DENY)) {
respMessage = "User denied for user with session " + sessionToken + "."
reject = true
}
}

if (reject) {
log.info("No session for user in conference.")

// Determine the logout url so we can send the user there.
String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()

@@ -1549,34 +1511,20 @@ class ApiController {
def stuns = {
boolean reject = false;

UserSession us = null;
String sessionToken = sanitizeSessionToken(params.sessionToken)
UserSession us = getUserSession(sessionToken);
Meeting meeting = null;
String sessionToken = null

if (!StringUtils.isEmpty(params.sessionToken)) {
sessionToken = StringUtils.strip(params.sessionToken)
println("Session token = [" + sessionToken + "]")
}

Boolean allowStunsWithoutSession = false;
// Depending on configuration, allow STUNS requests to proceed without session
if (paramsProcessorUtil.getAllowRequestsWithoutSession()) {
allowStunsWithoutSession = paramsProcessorUtil.getAllowRequestsWithoutSession();
}

if (sessionToken == null || meetingService.getUserSessionWithAuthToken(sessionToken) == null || (!allowStunsWithoutSession && !session[sessionToken])) {
if (!hasValidSession(sessionToken)) {
reject = true;
} else {
us = meetingService.getUserSessionWithAuthToken(sessionToken);
meeting = meetingService.getMeeting(us.meetingID);
if (meeting == null || meeting.isForciblyEnded()) {
reject = true
}
}

if (reject) {
log.info("No session for user in conference.")

String logoutUrl = paramsProcessorUtil.getDefaultLogoutUrl()

response.addHeader("Cache-Control", "no-cache")
@@ -1633,12 +1581,7 @@ class ApiController {
*************************************************/
def signOut = {

String sessionToken = null

if (!StringUtils.isEmpty(params.sessionToken)) {
sessionToken = StringUtils.strip(params.sessionToken)
println("SessionToken = " + sessionToken)
}
String sessionToken = sanitizeSessionToken(params.sessionToken)

Meeting meeting = null;

@@ -2155,6 +2098,76 @@ class ApiController {
}
}

def getUserSession(token) {
if (token == null) {
return null
}

UserSession us = meetingService.getUserSessionWithAuthToken(token)
if (us == null) {
log.info("Cannot find UserSession for token ${token}")
}

return us
}

def sanitizeSessionToken(param) {
if (param == null) {
log.info("sanitizeSessionToken: token is null")
return null
}

if (StringUtils.isEmpty(param)) {
log.info("sanitizeSessionToken: token is empty")
return null
}

return StringUtils.strip(param)
}

private Boolean hasValidSession(token) {
UserSession us = getUserSession(token)
if (us == null) {
return false
}

if (!session[token]) {
log.info("Session for token ${token} not found")

Boolean allowRequestsWithoutSession = paramsProcessorUtil.getAllowRequestsWithoutSession()
if (!allowRequestsWithoutSession) {
log.info("Meeting related to ${token} doesn't allow requests without session")
return false
}
}

log.info("Token ${token} is valid")
return true
}

// Validate maxParticipants constraint
private Boolean hasReachedMaxParticipants(meeting, us) {
// Meeting object calls it maxUsers to build up the drama
int maxParticipants = meeting.getMaxUsers();
// When is set to 0, the validation is ignored
Boolean enabled = maxParticipants > 0;
// Users refreshing page or reconnecting must be identified
Boolean rejoin = meeting.getUserById(us.internalUserId) != null;
// Users that passed enter once, still not joined but somehow re-entered
Boolean reenter = meeting.getEnteredUserById(us.internalUserId) != null;
// Users that already joined the meeting
int joinedUsers = meeting.getUsers().size()
// Users that are entering the meeting
int enteredUsers = meeting.getEnteredUsers().size()

Boolean reachedMax = (joinedUsers + enteredUsers) >= maxParticipants;
if (enabled && !rejoin && !reenter && reachedMax) {
return true;
}

return false;
}

private void respondWithErrors(errorList, redirectResponse = false) {
log.debug CONTROLLER_NAME + "#invalid"
if (redirectResponse) {
@@ -649,11 +649,15 @@ def events_parse_shape(shapes, event, current_presentation, current_slide, times
shape[:type] == 'ellipse' or shape[:type] == 'triangle' or
shape[:type] == 'line'
shape[:color] = color_to_hex(event.at_xpath('color').text)
thickness = event.at_xpath('thickness').text
thickness = event.at_xpath('thickness')
unless thickness
BigBlueButton.logger.warn("Draw #{shape[:shape_id]} Shape #{shape[:shape_unique_id]} ID #{shape[:id]} is missing thickness")
return
end
if $version_atleast_2_0_0
shape[:thickness_percent] = thickness.to_f
shape[:thickness_percent] = thickness.text.to_f
else
shape[:thickness] = thickness.to_i
shape[:thickness] = thickness.text.to_i
end
end
if shape[:type] == 'rectangle'