Callmobile 26.900.0–26.1100.0: управление участниками и реакции в звонках
В 26.900.0–26.1000.0 модератор получил управление участниками с телефона, появились реакции, индикатор качества связи и поиск по участникам, а журнал звонков перестал терять пропущенные. В 26.1100.0 в основном исправления: имена гостей, пагинация журнала и поздние ошибки, которые обрывали новый звонок. Серверная часть описана в разборе Call 26.1000.0–26.1100.0.
Новое
Управляйте звонком с телефона
В 26.900.0–26.1000.0 появилась вкладка управления звонком. Модератор может разом выключить микрофоны, камеры или демонстрацию экрана, запретить их включать и выдать участнику право говорить. Вкладка работает при jwtCallsEnabled, если нативный клиент умеет startCall, а у звонка есть sendSignalingMessage. Отключать потоки можно с правом change_settings, давать слово — с give_permissions. Клиент проверяет, доступно ли действие, но окончательно полномочия определяет медиасервер. Если связь пропала, действие предложит повторить, а переключатель вернётся к правам, которые подтвердила комната.
Для своих экранов те же действия есть в CallController: turnOffParticipantStream(), turnOffAllParticipansStream() (имя метода так и написано, с опечаткой), changeSettings() и allowSpeakPermission().
Добавить людей в идущий звонок теперь можно штатным селектором с поиском и множественным выбором, гостям эта кнопка недоступна. BitrixCallJwt.inviteUsers({ users, nonFatal }) возвращает Promise, а users — массив ID. Без флага неудачное приглашение, как и раньше, уходит в onFatalError, и звонок завершается для всех. Если приглашаете в уже идущий звонок, передавайте nonFatal: true, тогда ошибка просто отклонит Promise:
call.inviteUsers({ users: [42, 57], nonFatal: true })
.catch((error) => console.warn('Не удалось пригласить участников', error));
Реакции и качество связи
Кнопка реакций в 26.900.0–26.1000.0 появляется при reactions.enabled === true, если провайдер звонка поддерживает sendReaction. Входящие реакции видны и без флага. Отправлять можно не чаще раза в 600 мс, реакция висит 4 секунды, одновременно на экране до 6, в очереди до 100. Своему коду реакции приходят событием BX.Call.Event.onUserReaction, а конверт версии 1 собирают и разбирают CCallUtil.createReactionEnvelope() и parseReactionEnvelope().
Клиент отбрасывает неизвестные реакции, сверяет senderId с userId и не показывает собственное эхо. В plain-jwt senderId задаёт сам отправитель, поэтому от подмены автора на сервере эти проверки не защищают.
Индикатор качества на плитке участника открывает панель с метриками. Он работает, если сервер прислал callQosEnabled === true, а Application.getApiVersion() не ниже 36. Своё состояние клиент считает по статистике устройства, чужое берёт с сервера. Изменения приходят событием BX.Call.Event.onQoSStateChanged с полями { participantId, state, reason, notify }.
Гости, поиск и порядок плиток
Гость может начать групповой звонок из журнала, только если env.modulesData.call.guestOutgoingCallEnabled === true, личный — при guestOutgoingPrivateCallEnabled === true. Нет флага — нет звонка. Телефония гостям недоступна, вместо запрещённого действия откроется чат.
В списке участников появился поиск, модераторы идут первыми, остальные по имени. В сетке своя плитка всегда первая, дальше учитываются речь и камера, видео стоит перед аватарами. Короткое переподключение больше не подменяет идущее видео аватаром.
В 26.1100.0 клиент дозагружает полный профиль участника, даже если транспорт уже прислал имя. Признак extranet доходит до интерфейса, и гостя больше не подписывают сотрудником. Для счётчика участников с правильными окончаниями есть getParticipantsCountText(count, languageId = null) из call/calls/layout/participants-list.
Журнал звонков без потерь
Вкладка пропущенных в 26.900.0–26.1000.0 отмечает просмотренными именно полученные записи через call.CallLog.markAsSeen, у гостя остаётся markAllAsSeen. Счётчик приходит с сервера, и устаревший ответ не перетирает свежий. В 26.1100.0 пагинация передаёт lastId вместе с исходным statusTime, а если фильтр скрыл всю страницу, журнал сам запросит следующую. Подгрузка начинается, когда до конца остаётся меньше 10 строк. Журнал и экран синхронизации получили голосовую кнопку BitrixGPT с контекстом экрана и фильтра.
Мелочи и находки
- Отказ от входящего звонка на другом устройстве того же пользователя при
associatedEntity.isDeviceScoped === trueбольше не сбрасывает звонок на этом. После восстановления Pull клиент сверяет активные звонки и возвращает пропавшие карточки. - Мелодия звонка учитывает тихий режим. Нужно приложение iOS от 5.6.350 или Android от 5.21.0, на iOS ещё должен быть выключен
audioplayer_api_v1, иначе играет прежний звук. - Метрики и логи уходят на сервер только при
isMetricsEnabled === trueиisMetricsLogsEnabled === trueи заданном адресе. - В итогах встречи пустой анализ спикеров больше не прячет общий анализ.
- В 26.1100.0 поздняя ошибка прошлого звонка, в том числе отказ в доступе к камере или микрофону, не обрывает новый. Для этого
CallController.clearEverything(force, expectedCall = null)принимает ожидаемый звонок, вызов с одним аргументом работает как раньше. Ответcall_finishedу BitrixCallDev и Voximplant показывается как «звонок завершён», а не как внутренняя ошибка. - В 26.1100.0
PlainCallJwtпринимает видео, даже если у пользователя нет своей камеры. Горизонтальный режим учитывает системную навигацию Android, кнопка CoPilot получила область нажатия 48×48, а опущенная рука сразу пропадает с плитки. - Если ваши мобильные расширения используют
CCallUtil.getTimeInSeconds(startTime)изcall/calls/engine, учтите, что с 26.1100.0 он возвращает число0и для пустого времени (раньше строку''), и для некорректной даты (раньшеNaN).getTimeText()в таких случаях отдаёт пустую строку.