import type { Participant } from '@cc-livekit/livekit-client'; import { LocalParticipant } from '@cc-livekit/livekit-client'; import { sortParticipantsByIsSpeaking, sortParticipantsByJoinedAt, sortParticipantsByLastSpokenAT, } from './base-sort-functions'; /** * Default sort for participants, it'll order participants by: * 1. local participant * 2. dominant speaker (speaker with the loudest audio level) * 3. other speakers that are recently active * 4. participants with video on * 5. by joinedAt */ export function sortParticipants(participants: Participant[]): Participant[] { const sortedParticipants = [...participants]; sortedParticipants.sort((a, b) => { // loudest speaker first // if (a.isSpeaking && b.isSpeaking) { // return sortParticipantsByAudioLevel(a, b); // } const aScreenShareTrack = a.isScreenShareEnabled; const bScreenShareTrack = b.isScreenShareEnabled; if (aScreenShareTrack !== bScreenShareTrack) { if (aScreenShareTrack) { return -1; } else { return 1; } } // speaker goes first if (a.isSpeaking !== b.isSpeaking) { return sortParticipantsByIsSpeaking(a, b); } // video on const aVideo = a.videoTrackPublications.size > 0; const bVideo = b.videoTrackPublications.size > 0; if (aVideo !== bVideo) { if (aVideo) { return -1; } else { return 1; } } // microphone on const aAudio = a.isMicrophoneEnabled; const bAudio = b.isMicrophoneEnabled; if (aAudio !== bAudio) { if (aAudio) { return -1; } else { return 1; } } // last active speaker first if (a.lastSpokeAt !== b.lastSpokeAt) { return sortParticipantsByLastSpokenAT(a, b); } // joinedAt return sortParticipantsByJoinedAt(a, b); }); const localParticipant = sortedParticipants.find((p) => p.isLocal) as LocalParticipant; if (localParticipant) { const localIdx = sortedParticipants.indexOf(localParticipant); if (localIdx >= 0) { sortedParticipants.splice(localIdx, 1); if (sortedParticipants.length > 0) { sortedParticipants.splice(0, 0, localParticipant); } else { sortedParticipants.push(localParticipant); } } } return sortedParticipants; }