Режим администратора
Важные замечания
- ряд состояний при изменении, клиенту сообщен не будет! соответвенно, какие-то из состояний участников нужно обновлять руками. имейте это ввиду, если будете искать баги;
- приходить будут все ключи нотификации, однако, в каждой нотификации будет задана только 1 логическая цепочка. как именно определять, что хочет сказать та или иная нотификация - проще всего по коду по описанным ниже стратегиям обработки нотификаций.
Пример нотификации:
json
{
"muteStates": {
"VIDEO": "MUTE_PERMANENT",
"AUDIO": "MUTE_PERMANENT"
},
"unmuteOptions": [],
"mediaOptions": [
"VIDEO",
"AUDIO"
],
"muteAll": false,
"unmute": false,
"userId": {
"deviceIdx": 0,
"id": "1000002",
"type": "USER"
},
"adminId": null,
"stateUpdated": true
}Приведу ряд примеров о том, как нужно интерпретировать нотификации
(*) помечу те поля, по которым изменения могут происходить на сервере без нотификации клиенту
userId- если это поле есть, то нотификация персональная, для этого юзера, если переданnullи при этомmuteAll = false, то это нотификация для клиента (те вас);adminId- автор нотификации, те тот, что инициировал эти изменения;muteAll- значит, что нотификация общая для звонка, а не персональная;stateUpdated- говорит о том, что в состоянии произошли какие то изменения, в большинстве сценариев, если это полеfalse, то реагировать не нужно;mediaOptions- это массив тех медиа(VIDEO|AUDIO...)по которым произошли изменения. на этот флаг нужно смотреть в совокупности с другими;muteStates (*)- это состояние конкретных медиа, напримерAUDIO: MUTE_PERMANENT, говорит о том, что на аудио наложен пермамьют. Однако, если вmediaOptionsнетAUDIO, значит изменения коснулись какой то другой медиа группы. Тут нужно быть особенно внимательным, тк бекенд будет обновлять это поле в ряде случаев без уведомления клиента. Например, при введении\снятии глобальных пермамьютов;unmuteиunmuteOptions (*)- до конца не понятно, зачем нуженunmute, а вот вunmuteOptionsбудет переченьMediaOptionпо которым есть разовая возможность включения. По идее, эта нотификация может прийти пользователю после перезахода в звонок, те тут останутся "сохраненная" информация о разовых разьмьютах. В течение звонка, разовые мьюты будут прихожить черезrequestedMedia. Так же тут могут приходить оставшиеся не использованные "разовые включения", по мере их использования, но приходить они будут не сами по себе, а наряду с другими нотификациями;requestedMedia- это медиа, по которым приходит просьба на размьют. через неё выдаются разовые пермиссии на влючение медиа в течение активного звонка (напомню, что при перезаходе, разовые пермиссии придут юзеру, скорее, вunmuteOptions);
Возможные стратегии обработки входящих нотификаций:
- во всех примерах
state= редакс стор;
- Изменение глобальных пермиссий
- На изменение каких ключей смотрим:
muteStatesсостояния мьютов;mediaOptionsпо каким медиа пришли изменения;
- Последствия:
- Если клиент = (админ \ создатель) звонка, нужно получить состояния других участников, тк приходить до этого к нему они не будут!
- На изменение каких ключей смотрим:
ts
// при входе в звонок может прилететь кеш из sdk
if (!stateUpdated) {
// стейт не обновился - пропускаем
return;
}
if (!muteAll) {
// состояние обновилось для меня - обработать позже
return;
}
// ...обновляем состояние пермиссий звонка
// если мы администратор или создатель
// то нужно получить состояния отдельно взятых участников (девайсов)
if (isAdmin(state.myUserExternalId) || isCreator(state.myUserExternalId)) {
// если нет чанков - SDK.getParticipants
// с чанками - SDK.getParticipantListChunk
}
// ...обновляем состояния участников (девайсов)- Изменение персональных пермиссий
- На изменение каких ключей смотрим:
muteStatesсостояния мьютов;mediaOptionsпо каким медиа пришли изменения;
- На изменение каких ключей смотрим:
ts
if (userId && !isSameExternalId(userId, state.externalId)) {
// нотификация не для меня, обработаем в другом месте
return;
}
if (adminId && isSameExternalId(adminId, state.externalId)) {
// я = отправитель, не обрабатываем
return;
}
if (!stateUpdated) {
// стейт не обновился - пропускаем
return;
}
if (!muteAll && !!requestedMedia) {
// признак, что в нотификации пришло "привлечение внимания" - пропускаем
return;
}
// ...выставляем персональные пермиссии- Изменение чужих персональных пермиссий
- На изменение каких ключей смотрим:
userIdюзер, для которого пришел апдейт;muteStatesсостояния мьютов;mediaOptionsпо каким медиа пришли изменения;unmuteOptionsтут могут лежать разовые пермиссии по участнику (актуально при перезаходе в звонок);
- Какие последствия:
- клиенту выдают разовые пермиссии по выбранным медиа;
- клиенту выдают состояния мьютов по выбранным медиа;
- На изменение каких ключей смотрим:
ts
if (!userId || isSameExternalId(userId, state.externalId)) {
// нотификация не относится к другому участнику - skip
return;
}
if (!stateUpdated) {
return;
}
// ...выставляем пермиссии участника- Изменение персональных разовых пермиссий
- На изменение каких ключей смотрим:
unmuteOptionsтут могут лежать разовые пермиссии по участнику
- Какие последствия:
- клиенту выдают разовые пермиссии по выбранным медиа;
- На изменение каких ключей смотрим:
ts
if (userId && !isSameExternalId(userId, state.externalId)) {
// нотификация не для меня - skip
return;
}
if (adminId && isSameExternalId(adminId, state.externalId)) {
// я = отправитель команды - skip
return;
}
if (requestedMedia?.length) {
// нотификация с привлечением внимания - skip
return;
}
if (!(stateUpdated && unmuteOptions.length)) {
// стейт не обновился или unmuteOptions пустой
return;
}
// ...выставляем персональные разовые пермиссии- Привлечение внимания
- На изменение каких ключей смотрим:
requestedMediaпо каким медиа привлечено внимание;muteAllеслиtrue- глобальное,false- персональное;
- Какие последствия применения:
- По выбранным медиа выдается разовая пермиссия;
- Если была поднята рука при получении пермиссии - она опустится;
- На изменение каких ключей смотрим:
ts
if (userId && !isSameExternalId(userId, state.externalId)) {
// нотификация не для меня - skip
return;
}
if (adminId && isSameExternalId(adminId, state.externalId)) {
// я = отправитель команды - skip
return;
}
if (!requestedMedia || !requestedMedia.length) {
// внимание не было привлечено - skip
return;
}
// ...выставляем привлечение вниманияОсобенности применения:
- при отправке
muteStatesнельзя объединять разные значение, например,MUTEиMUTE_PERMANENT, те если вам нужно выдать пермамьют и разово отключить медиа - отправляем 2 сигнала; - есть события, на которых нужно снижать разовую пермиссию по переданным
mediaSettings.(isAudioEnabled|isVideoEnabled|isScreenSharingEnabled):onScreenStreamonLocalStreamUpdateonRemoteMediaSettings
- события, в которых могут приходить состояния мьютов участников:
onMuteStatesonConversation- в массивеparticipantsSDK.getParticipants- в массивеparticipantsonConversationParticipantListChunk- в массивеchunk
Как понять, что у меня разблокировано медиа устройство?
ts
// если я создатель или админ - на меня не действуют ограничения
if (isAdmin(me) || isCreator(me)) {
return true;
}
// если на меня или на звонок выдан MUTE_PERMANENT
if (
callPermissions[mediaOption] === MuteState.MUTE_PERMANENT ||
myPermissions?.[mediaOption] === MuteState.MUTE_PERMANENT
) {
// проверяем наличие разовой пермиссии
return !!permissionsOnce?.has(mediaOption);
}
// если мы тут, значит - можно
return true;