Пример нотификации:
{
"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 по каким медиа пришли изменения;// при входе в звонок может прилететь кеш из sdk
if (!stateUpdated) {
// стейт не обновился - пропускаем
return;
}
if (!muteAll) {
// состояние обновилось для меня - обработать позже
return;
}
// ...обновляем состояние пермиссий звонка
// если мы администратор или создатель
// то нужно получить состояния отдельно взятых участников (девайсов)
if (isAdmin(state.myUserExternalId) || isCreator(state.myUserExternalId)) {
// если нет чанков - SDK.getParticipants
// с чанками - SDK.getParticipantListChunk
}
// ...обновляем состояния участников (девайсов)
muteStates состояния мьютов;mediaOptions по каким медиа пришли изменения;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 тут могут лежать разовые пермиссии по участнику (актуально при перезаходе в звонок);if (!userId || isSameExternalId(userId, state.externalId)) {
// нотификация не относится к другому участнику - skip
return;
}
if (!stateUpdated) {
return;
}
// ...выставляем пермиссии участника
unmuteOptions тут могут лежать разовые пермиссии по участнику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 - персональное;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):onScreenStreamonLocalStreamUpdateonRemoteMediaSettingsonMuteStatesonConversation - в массивеparticipantsSDK.getParticipants - в массивеparticipantsonConversationParticipantListChunk - в массивеchunk// если я создатель или админ - на меня не действуют ограничения
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;