export const DEFAULT_PARTICIPANT_NAME = 'ε‚δΈŽθ€…'; export const DEFAULT_PARTICIPANT_AVATAR = '/images/p2.png'; const DEFAULT_MEDIA_STATE = Object.freeze({ audio: false, video: true, isSpeaking: false }); function createParticipantRecord(current = {}, patch = {}) { return { id: '', name: DEFAULT_PARTICIPANT_NAME, avatar: DEFAULT_PARTICIPANT_AVATAR, mediaState: { ...DEFAULT_MEDIA_STATE }, status: 'online', ...current, ...patch, mediaState: { ...DEFAULT_MEDIA_STATE, ...(current.mediaState || {}), ...(patch.mediaState || {}) } }; } export function upsertParticipant(participants, participantId, patch = {}) { if (!participantId) { return null; } participants[participantId] = createParticipantRecord(participants[participantId], patch); return participants[participantId]; } export function removeParticipant(participants, participantId) { if (!participantId || !participants[participantId]) { return false; } delete participants[participantId]; return true; } export function omitParticipant(participants, excludedParticipantId) { const filtered = {}; for (const [participantId, participant] of Object.entries(participants || {})) { if (participantId !== excludedParticipantId) { filtered[participantId] = participant; } } return filtered; } export function buildParticipantsSyncData(localUser, participants) { const memberList = { host: { id: localUser.id, name: localUser.name, avatar: localUser.avatar, mediaState: { ...localUser.mediaState }, status: 'online', role: 'host' } }; for (const [participantId, participant] of Object.entries(participants || {})) { memberList[participantId] = { ...createParticipantRecord(participant), role: 'participant' }; } return memberList; }