Пример нотификации:
{
"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)
:onScreenStream
onLocalStreamUpdate
onRemoteMediaSettings
onMuteStates
onConversation
- в массивеparticipants
SDK.getParticipants
- в массивеparticipants
onConversationParticipantListChunk
- в массиве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;