Get Participants
Listen for participant list changes:Report incorrect code
Copy
Ask AI
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';
CometChatCalls.addEventListener('onParticipantListChanged', (participants) => {
console.log('Participants:', participants);
});
Participant Object
Each participant contains:| Property | Type | Description |
|---|---|---|
pid | string | Participant ID (unique per session) |
uid | string | User ID |
name | string | Display name |
avatar | string | Avatar URL (optional) |
Participant Events
Subscribe to individual participant events:Report incorrect code
Copy
Ask AI
// Join/Leave
CometChatCalls.addEventListener('onParticipantJoined', (participant) => {
console.log(`${participant.name} joined`);
});
CometChatCalls.addEventListener('onParticipantLeft', (participant) => {
console.log(`${participant.name} left`);
});
// Audio state
CometChatCalls.addEventListener('onParticipantAudioMuted', (participant) => {
console.log(`${participant.name} muted`);
});
CometChatCalls.addEventListener('onParticipantAudioUnmuted', (participant) => {
console.log(`${participant.name} unmuted`);
});
// Video state
CometChatCalls.addEventListener('onParticipantVideoPaused', (participant) => {
console.log(`${participant.name} video paused`);
});
CometChatCalls.addEventListener('onParticipantVideoResumed', (participant) => {
console.log(`${participant.name} video resumed`);
});
// Hand raised
CometChatCalls.addEventListener('onParticipantHandRaised', (participant) => {
console.log(`${participant.name} raised hand`);
});
CometChatCalls.addEventListener('onParticipantHandLowered', (participant) => {
console.log(`${participant.name} lowered hand`);
});
// Screen sharing
CometChatCalls.addEventListener('onParticipantStartedScreenShare', (participant) => {
console.log(`${participant.name} started screen share`);
});
CometChatCalls.addEventListener('onParticipantStoppedScreenShare', (participant) => {
console.log(`${participant.name} stopped screen share`);
});
// Dominant speaker
CometChatCalls.addEventListener('onDominantSpeakerChanged', (participant) => {
console.log(`Dominant speaker: ${participant.name}`);
});
Participant Actions
Manage participants using these methods:Report incorrect code
Copy
Ask AI
// Pin participant
CometChatCalls.pinParticipant(participantId, 'human');
// Unpin
CometChatCalls.unpinParticipant();
// Mute participant (requires moderator)
CometChatCalls.muteParticipant(participantId);
// Pause participant video (requires moderator)
CometChatCalls.pauseParticipantVideo(participantId);
Complete Example
Report incorrect code
Copy
Ask AI
import React, { useState, useEffect } from 'react';
import {
View,
FlatList,
Text,
TouchableOpacity,
StyleSheet,
Image,
Modal,
} from 'react-native';
import { CometChatCalls } from '@cometchat/calls-sdk-react-native';
interface Participant {
pid: string;
uid: string;
name: string;
avatar?: string;
}
interface ParticipantState extends Participant {
isAudioMuted: boolean;
isVideoMuted: boolean;
isHandRaised: boolean;
isScreenSharing: boolean;
isDominantSpeaker: boolean;
}
function CustomParticipantList() {
const [participants, setParticipants] = useState<Map<string, ParticipantState>>(
new Map()
);
const [pinnedId, setPinnedId] = useState<string | null>(null);
const [isVisible, setIsVisible] = useState(false);
const [dominantSpeakerId, setDominantSpeakerId] = useState<string | null>(null);
useEffect(() => {
const unsubscribers: Array<() => void> = [];
// Participant list changes
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantListChanged',
(list: Participant[]) => {
setParticipants((prev) => {
const newMap = new Map(prev);
// Add new participants
list.forEach((p) => {
if (!newMap.has(p.pid)) {
newMap.set(p.pid, {
...p,
isAudioMuted: false,
isVideoMuted: false,
isHandRaised: false,
isScreenSharing: false,
isDominantSpeaker: false,
});
}
});
// Remove participants who left
const currentPids = new Set(list.map((p) => p.pid));
newMap.forEach((_, pid) => {
if (!currentPids.has(pid)) {
newMap.delete(pid);
}
});
return newMap;
});
}
)
);
// Audio state
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantAudioMuted',
(p: Participant) => {
updateParticipant(p.pid, { isAudioMuted: true });
}
)
);
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantAudioUnmuted',
(p: Participant) => {
updateParticipant(p.pid, { isAudioMuted: false });
}
)
);
// Video state
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantVideoPaused',
(p: Participant) => {
updateParticipant(p.pid, { isVideoMuted: true });
}
)
);
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantVideoResumed',
(p: Participant) => {
updateParticipant(p.pid, { isVideoMuted: false });
}
)
);
// Hand raised
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantHandRaised',
(p: Participant) => {
updateParticipant(p.pid, { isHandRaised: true });
}
)
);
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantHandLowered',
(p: Participant) => {
updateParticipant(p.pid, { isHandRaised: false });
}
)
);
// Screen sharing
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantStartedScreenShare',
(p: Participant) => {
updateParticipant(p.pid, { isScreenSharing: true });
}
)
);
unsubscribers.push(
CometChatCalls.addEventListener(
'onParticipantStoppedScreenShare',
(p: Participant) => {
updateParticipant(p.pid, { isScreenSharing: false });
}
)
);
// Dominant speaker
unsubscribers.push(
CometChatCalls.addEventListener(
'onDominantSpeakerChanged',
(p: Participant) => {
setDominantSpeakerId(p.pid);
}
)
);
return () => {
unsubscribers.forEach((unsub) => unsub());
};
}, []);
const updateParticipant = (pid: string, updates: Partial<ParticipantState>) => {
setParticipants((prev) => {
const newMap = new Map(prev);
const participant = newMap.get(pid);
if (participant) {
newMap.set(pid, { ...participant, ...updates });
}
return newMap;
});
};
const handlePin = (participant: ParticipantState) => {
if (pinnedId === participant.pid) {
CometChatCalls.unpinParticipant();
setPinnedId(null);
} else {
CometChatCalls.pinParticipant(participant.pid, 'human');
setPinnedId(participant.pid);
}
};
const handleMute = (participant: ParticipantState) => {
CometChatCalls.muteParticipant(participant.pid);
};
const renderParticipant = ({ item }: { item: ParticipantState }) => (
<View style={styles.participantItem}>
<View style={styles.avatarContainer}>
{item.avatar ? (
<Image source={{ uri: item.avatar }} style={styles.avatar} />
) : (
<View style={styles.avatarPlaceholder}>
<Text style={styles.avatarText}>
{item.name.charAt(0).toUpperCase()}
</Text>
</View>
)}
{dominantSpeakerId === item.pid && (
<View style={styles.speakingIndicator} />
)}
</View>
<View style={styles.participantInfo}>
<Text style={styles.participantName}>{item.name}</Text>
<View style={styles.statusIcons}>
{item.isAudioMuted && <Text style={styles.statusIcon}>🔇</Text>}
{item.isVideoMuted && <Text style={styles.statusIcon}>📷</Text>}
{item.isHandRaised && <Text style={styles.statusIcon}>✋</Text>}
{item.isScreenSharing && <Text style={styles.statusIcon}>🖥️</Text>}
{pinnedId === item.pid && <Text style={styles.statusIcon}>📌</Text>}
</View>
</View>
<View style={styles.actions}>
<TouchableOpacity
style={styles.actionButton}
onPress={() => handlePin(item)}
>
<Text style={styles.actionText}>
{pinnedId === item.pid ? 'Unpin' : 'Pin'}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.actionButton}
onPress={() => handleMute(item)}
>
<Text style={styles.actionText}>Mute</Text>
</TouchableOpacity>
</View>
</View>
);
const participantList = Array.from(participants.values());
return (
<>
<TouchableOpacity
style={styles.toggleButton}
onPress={() => setIsVisible(true)}
>
<Text style={styles.toggleButtonText}>
👥 {participantList.length}
</Text>
</TouchableOpacity>
<Modal
visible={isVisible}
transparent
animationType="slide"
onRequestClose={() => setIsVisible(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Text style={styles.modalTitle}>
Participants ({participantList.length})
</Text>
<TouchableOpacity onPress={() => setIsVisible(false)}>
<Text style={styles.closeButton}>✕</Text>
</TouchableOpacity>
</View>
<FlatList
data={participantList}
keyExtractor={(item) => item.pid}
renderItem={renderParticipant}
ListEmptyComponent={
<Text style={styles.emptyText}>No participants</Text>
}
/>
</View>
</View>
</Modal>
</>
);
}
const styles = StyleSheet.create({
toggleButton: {
position: 'absolute',
top: 60,
right: 16,
backgroundColor: 'rgba(0, 0, 0, 0.6)',
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 20,
},
toggleButtonText: {
color: '#fff',
fontSize: 16,
},
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'flex-end',
},
modalContent: {
backgroundColor: '#1a1a1a',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
maxHeight: '70%',
},
modalHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#333',
},
modalTitle: {
color: '#fff',
fontSize: 18,
fontWeight: '600',
},
closeButton: {
color: '#fff',
fontSize: 20,
padding: 4,
},
participantItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 12,
borderBottomWidth: 1,
borderBottomColor: '#333',
},
avatarContainer: {
position: 'relative',
},
avatar: {
width: 44,
height: 44,
borderRadius: 22,
},
avatarPlaceholder: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: '#6851D6',
justifyContent: 'center',
alignItems: 'center',
},
avatarText: {
color: '#fff',
fontSize: 18,
fontWeight: '600',
},
speakingIndicator: {
position: 'absolute',
bottom: 0,
right: 0,
width: 14,
height: 14,
borderRadius: 7,
backgroundColor: '#22c55e',
borderWidth: 2,
borderColor: '#1a1a1a',
},
participantInfo: {
flex: 1,
marginLeft: 12,
},
participantName: {
color: '#fff',
fontSize: 16,
fontWeight: '500',
},
statusIcons: {
flexDirection: 'row',
marginTop: 4,
gap: 4,
},
statusIcon: {
fontSize: 14,
},
actions: {
flexDirection: 'row',
gap: 8,
},
actionButton: {
backgroundColor: '#333',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 4,
},
actionText: {
color: '#fff',
fontSize: 12,
},
emptyText: {
color: '#666',
textAlign: 'center',
padding: 20,
},
});
export default CustomParticipantList;
Related Documentation
- Participant Management - Manage participants
- Events - All participant events
- Custom Control Panel - Build custom controls