本指南介绍如何在 RealtimeKit 会议中访问参与者数据、显示视频、处理事件并管理参与者权限。
参与者对象包含与特定参与者相关的所有信息,包括关于网格以及每个参与者的媒体流、姓名和状态变量的信息。它可以通过 meeting.participants 访问。
id- 参与者的participantId(又称peerId)userId- 参与者的userIdname- 参与者的姓名picture- 参与者的图片(如果有)customParticipantId- 可用于标识参与者的任意 IDisPinned- 如果参与者被置顶,则设置为truepresetName- 与参与者关联的预设名称
id- 参与者加入会议会话时生成的特定于会话的标识符(也称为peerId)userId- 将参与者添加到会议时生成的永久标识符name- 参与者的显示名称picture- 参与者显示图片的字符串 URL(如果有)customParticipantId- 客户在向会议添加参与者时可以设置的自定义标识符isHost- 该参与者是否具有主持人权限的布尔值isPinned- 该参与者当前是否在会议中被置顶presetName- 添加到会议时应用于该参与者的预设名称stageStatus- 指示参与者当前的舞台状态(仅适用于启用舞台的会议)
id- 参与者加入会议会话时生成的特定于会话的标识符(也称为peerId)userId- 将参与者添加到会议时生成的永久标识符name- 参与者的显示名称picture- 参与者显示图片的字符串 URL(如果有)customParticipantId- 客户在向会议添加参与者时可以设置的自定义标识符isHost- 该参与者是否具有主持人权限的布尔值isPinned- 该参与者当前是否在会议中被置顶presetName- 添加到会议时应用于该参与者的预设名称stageStatus- 指示参与者当前的舞台状态(仅适用于启用舞台的会议)
id- 参与者加入会议会话时生成的特定于会话的标识符(也称为peerId)userId- 将参与者添加到会议时生成的永久标识符name- 参与者的显示名称picture- 参与者显示图片的字符串 URL(如果有)isHost- 该参与者是否具有主持人权限的布尔值customParticipantId- 客户在向会议添加参与者时可以设置的自定义标识符stageStatus- 指示参与者当前的舞台状态(仅适用于启用舞台的会议)isPinned- 该参与者当前是否在会议中被置顶presetName- 添加到会议时应用于该参与者的预设名称
videoEnabled- 如果参与者的摄像头已开启,则设置为trueaudioEnabled- 如果参与者已被取消静音,则设置为truescreenShareEnabled- 如果参与者正在共享其屏幕,则设置为truevideoTrack- 参与者的视频轨道audioTrack- 参与者的音频轨道screenShareTracks- 参与者屏幕共享的视频和音频轨道
videoEnabled- 参与者当前的摄像头是否已启用audioEnabled- 参与者当前的麦克风是否已取消静音screenshareEnabled- 参与者当前是否正在共享其屏幕
// 已加入会议的参与者人数
console.log(meeting.participants.count);
// 分页模式下的可用页数
console.log(meeting.participants.pageCount);
// 处于活动状态的最大参与者数
console.log(meeting.participants.maxActiveParticipantsCount);
// 上一位发言参与者的 ParticipantId
console.log(meeting.participants.lastActiveSpeaker);使用 useRealtimeKitSelector hook 访问属性:
// 已加入会议的参与者人数
const participantCount = useRealtimeKitSelector((m) => m.participants.count);
// 分页模式下的可用页数
const pageCount = useRealtimeKitSelector((m) => m.participants.pageCount);
// 处于活动状态的最大参与者数
const maxActiveCount = useRealtimeKitSelector(
(m) => m.participants.maxActiveParticipantsCount,
);
// 上一位发言参与者的 ParticipantId
const lastActiveSpeaker = useRealtimeKitSelector(
(m) => m.participants.lastActiveSpeaker,
);// 已加入会议的参与者人数
val participantCount = meeting.participants.joined.size
// 访问分页属性
val maxNumberOnScreen = meeting.participants.maxNumberOnScreen
val currentPageNumber = meeting.participants.currentPageNumber
val pageCount = meeting.participants.pageCount
val canGoNextPage = meeting.participants.canGoNextPage
val canGoPreviousPage = meeting.participants.canGoPreviousPage// 已加入会议的参与者人数
let participantCount = meeting.participants.joined.count
// 访问分页属性
let maxNumberOnScreen = meeting.participants.maxNumberOnScreen
let currentPageNumber = meeting.participants.currentPageNumber
let pageCount = meeting.participants.pageCount
let canGoNextPage = meeting.participants.canGoNextPage
let canGoPreviousPage = meeting.participants.canGoPreviousPage// 已加入会议的参与者人数
final participantCount = meeting.participants.joined.length;
// 访问分页属性
final currentPageNumber = meeting.participants.currentPageNumber;
final pageCount = meeting.participants.pageCount;
final canGoNextPage = meeting.participants.isNextPagePossible;
final canGoPreviousPage = meeting.participants.isPreviousPagePossible;使用 useRealtimeKitSelector hook 访问属性:
// 已加入会议的参与者人数
const participantCount = useRealtimeKitSelector((m) => m.participants.count);
// 分页模式下的可用页数
const pageCount = useRealtimeKitSelector((m) => m.participants.pageCount);
// 处于活动状态的最大参与者数
const maxActiveCount = useRealtimeKitSelector(
(m) => m.participants.maxActiveParticipantsCount,
);
// 上一位发言参与者的 ParticipantId
const lastActiveSpeaker = useRealtimeKitSelector(
(m) => m.participants.lastActiveSpeaker,
);您可以从 参与者映射 中获取参与者。
const participant = meeting.participants.joined.get(participantId);
// 访问参与者属性
console.log(participant.name);
console.log(participant.videoEnabled);
console.log(participant.audioEnabled);// 获取特定参与者
const participant = useRealtimeKitSelector((m) =>
m.participants.joined.get(participantId),
);
// 访问参与者属性
const participantName = participant?.name;
const isVideoEnabled = participant?.videoEnabled;
const isAudioEnabled = participant?.audioEnabled;// 通过 peer ID 查找参与者
val participant = meeting.participants.joined.firstOrNull { it.id == participantId }
// 访问参与者属性
participant?.let {
println("Participant: ${it.name}")
println("Video: ${it.videoEnabled}")
println("Audio: ${it.audioEnabled}")
}// 通过 peer ID 查找参与者
if let participant = meeting.participants.joined.first(where: { $0.id == participantId }) {
// 访问参与者属性
print("Participant: \(participant.name)")
print("Video: \(participant.videoEnabled)")
print("Audio: \(participant.audioEnabled)")
}// 通过 peer ID 查找参与者
final participant = meeting.participants.joined
.where((p) => p.id == "<peerId>")
.firstOrNull;
// 访问参与者属性
if (participant != null) {
print('Participant: ${participant.name} (ID: ${participant.id})');
print('Audio: ${participant.audioEnabled ? "On" : "Off"}');
print('Video: ${participant.videoEnabled ? "On" : "Off"}');
}// 获取特定参与者
const participant = useRealtimeKitSelector((m) =>
m.participants.joined.get(participantId),
);
// 访问参与者属性
const participantName = participant?.name;
const isVideoEnabled = participant?.videoEnabled;
const isAudioEnabled = participant?.audioEnabled;所有参与者都存储在 meeting.participants 下。这些不包括本地用户。
meeting.participants 对象包含以下映射:
joined- 当前在会议中的所有参与者(不包括本地用户)waitlisted- 所有等待加入会议的参与者active- 已订阅其媒体的所有参与者(应在屏幕上显示的参与者)pinned- 会议中所有被置顶的参与者
如果您正在构建视频/音频网格,请使用 active 映射。要显示所有参与者的列表,请使用 joined 映射。
这些映射中的每个参与者都是 RTKParticipant 类型。
所有参与者都存储在 meeting.participants 下。这些不包括本地用户。
meeting.participants 对象包含以下列表:
joined- 当前在会议中的所有参与者(不包括本地用户)waitlisted- 所有等待加入会议的参与者active- 已订阅其媒体的所有参与者(应在屏幕上显示的参与者)pinned- 会议中所有被置顶的参与者screenShares- 所有正在共享其屏幕的参与者
如果您正在构建视频/音频网格,请使用 active 列表。要显示所有参与者的列表,请使用 joined 列表。
所有参与者都存储在 meeting.participants 下。这些不包括本地用户。
meeting.participants 对象包含以下列表:
joined- 当前在会议中的所有参与者(不包括本地用户)waitlisted- 所有等待加入会议的参与者active- 已订阅其媒体的所有参与者(应在屏幕上显示的参与者)pinned- 会议中所有被置顶的参与者
如果您正在构建视频/音频网格,请使用 active 列表。要显示所有参与者的列表,请使用 joined 列表。
这些列表中的每个参与者都是 RtkRemoteParticipant 类型。
// 获取所有已加入的参与者
const joinedParticipants = meeting.participants.joined;
// 获取活动参与者(屏幕上的参与者)
const activeParticipants = meeting.participants.active;
// 获取已置顶的参与者
const pinnedParticipants = meeting.participants.pinned;
// 获取等候名单中的参与者
const waitlistedParticipants = meeting.participants.waitlisted;使用 useRealtimeKitSelector hook 访问参与者映射:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react";
// 获取所有已加入的参与者
const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);
// 获取活动参与者(屏幕上的参与者)
const activeParticipants = useRealtimeKitSelector((m) => m.participants.active);
// 获取已置顶的参与者
const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);
// 获取等候名单中的参与者
const waitlistedParticipants = useRealtimeKitSelector(
(m) => m.participants.waitlisted,
);// 获取所有已加入的参与者
val joinedParticipants: List<RtkRemoteParticipant> = meeting.participants.joined
// 获取活动参与者(屏幕上的参与者)
val activeParticipants: List<RtkRemoteParticipant> = meeting.participants.active
// 获取已置顶的参与者
val pinnedParticipants: List<RtkRemoteParticipant> = meeting.participants.pinned
// 获取等候名单中的参与者
val waitlistedParticipants: List<RtkRemoteParticipant> = meeting.participants.waitlisted
// 获取正在共享屏幕的参与者
val screenShareParticipants: List<RtkRemoteParticipant> = meeting.participants.screenShares// 获取所有已加入的参与者
let joinedParticipants: [RtkRemoteParticipant] = meeting.participants.joined
// 获取活动参与者(屏幕上的参与者)
let activeParticipants: [RtkRemoteParticipant] = meeting.participants.active
// 获取已置顶的参与者
let pinnedParticipants: [RtkRemoteParticipant] = meeting.participants.pinned
// 获取等候名单中的参与者
let waitlistedParticipants: [RtkRemoteParticipant] = meeting.participants.waitlisted
// 获取正在共享屏幕的参与者
let screenShareParticipants: [RtkRemoteParticipant] = meeting.participants.screenShares// 获取所有已加入的参与者
final joinedParticipants = meeting.participants.joined;
// 获取活动参与者(屏幕上的参与者)
final activeParticipants = meeting.participants.active;
// 获取已置顶的参与者
final pinnedParticipants = meeting.participants.pinned;
// 获取等候名单中的参与者
final waitlistedParticipants = meeting.participants.waitlisted;使用 useRealtimeKitSelector hook 访问参与者映射:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react-native";
// 获取所有已加入的参与者
const joinedParticipants = useRealtimeKitSelector((m) => m.participants.joined);
// 获取活动参与者(屏幕上的参与者)
const activeParticipants = useRealtimeKitSelector((m) => m.participants.active);
// 获取已置顶的参与者
const pinnedParticipants = useRealtimeKitSelector((m) => m.participants.pinned);
// 获取等候名单中的参与者
const waitlistedParticipants = useRealtimeKitSelector(
(m) => m.participants.waitlisted,
);视图模式指示参与者是填充在 ACTIVE_GRID 模式还是 PAGINATED 模式。
ACTIVE_GRID模式 - 根据谁在发言或谁开启了视频,自动在meeting.participants.active中替换参与者PAGINATED模式 -meeting.participants.active中的参与者是固定的。使用setPage()更改活动参与者
// 将视图模式设置为分页
await meeting.participants.setViewMode("PAGINATED");
// 将视图模式设置为活动网格
await meeting.participants.setViewMode("ACTIVE_GRID");使用 useRealtimeKitClient hook 访问会议对象:
import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
// 将视图模式设置为分页
await meeting.participants.setViewMode("PAGINATED");
// 将视图模式设置为活动网格
await meeting.participants.setViewMode("ACTIVE_GRID");Android SDK 在第 0 页默认使用活动网格模式。如果您切换到下一页,它会自动切换到分页模式。
iOS SDK 在第 0 页默认使用活动网格模式。如果您切换到下一页,它会自动切换到分页模式。
Flutter SDK 在第 0 页默认使用活动网格模式。如果您切换到下一页,它会自动切换到分页模式。
// 将视图模式设置为分页
await meeting.participants.setViewMode("PAGINATED");
// 将视图模式设置为活动网格
await meeting.participants.setViewMode("ACTIVE_GRID");// 切换到第二页
await meeting.participants.setPage(2);import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
// 切换到第二页
await meeting.participants.setPage(2);// 切换到第一页
meeting.participants.setPage(1)// 切换到第一页
meeting.participants.setPage(1)Flutter SDK 自动管理参与者分页。
// 切换到第二页
await meeting.participants.setPage(2);const viewMode = meeting.participants.viewMode;
const currentPage = meeting.participants.currentPage;const viewMode = useRealtimeKitSelector((m) => m.participants.viewMode);
const currentPage = useRealtimeKitSelector((m) => m.participants.currentPage);该平台不支持监控视图模式。
const viewMode = useRealtimeKitSelector((m) => m.participants.viewMode);
const currentPage = useRealtimeKitSelector((m) => m.participants.currentPage);参与者对象允许主持人进行多种控制。这些控制可以在创建主持人 预设 时选择。
拥有正确的权限,主持人可以禁用远程参与者的媒体。
const participant = meeting.participants.joined.get(participantId);
// 禁用参与者的视频流
participant.disableVideo();
// 禁用参与者的音频流
participant.disableAudio();
// 将参与者移出会议
participant.kick();import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
const participant = meeting.participants.joined.get(participantId);
// 禁用参与者的视频流
participant.disableVideo();
// 禁用参与者的音频流
participant.disableAudio();
// 将参与者移出会议
participant.kick();val participant = meeting.participants.joined.firstOrNull { it.id == participantId }
participant?.let { pcpt ->
// 禁用参与者的视频流
val videoError = pcpt.disableVideo()
// 禁用参与者的音频流
val audioError = pcpt.disableAudio()
// 将参与者移出会议
val kickError = pcpt.kick()
}if let participant = meeting.participants.joined.first(where: { $0.id == participantId }) {
// 禁用参与者的视频流
let videoError: HostError? = participant.disableVideo()
// 禁用参与者的音频流
let audioError: HostError? = participant.disableAudio()
// 将参与者移出会议
let kickError: HostError? = participant.kick()
}// 禁用远程参与者的视频
participant.disableVideo(onResult: (e) {
// 或者是处理错误(如果有)
});
// 禁用远程参与者的音频
participant.disableAudio(onResult: (e) {
// 或者是处理错误(如果有)
});
// 将参与者移出会议
participant.kick();所需权限:permissions.host.canDisableVideo、permissions.host.canDisableAudio 必须为 true
const participant = meeting.participants.joined.get(participantId);
// 禁用参与者的视频流
participant.disableVideo();
// 禁用参与者的音频流
participant.disableAudio();
// 将参与者移出会议
participant.kick();等候室允许主持人控制哪些用户可以加入会议以及何时加入。他们可以选择接受或拒绝请求。
您还可以使用 预设 自动执行此流程,以便在主持人加入会议时,用户自动加入会议。
await meeting.participants.acceptWaitingRoomRequest(participantId);import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
await meeting.participants.acceptWaitingRoomRequest(participantId);meeting.participants.acceptWaitingRoomRequest(participantId)meeting.participants.acceptWaitingRoomRequest(id: participantId)final participant = meeting.participants.waitlisted[0];
meeting.participants.acceptWaitlistedParticipant(participant);await meeting.participants.acceptWaitingRoomRequest(participantId);await meeting.participants.rejectWaitingRoomRequest(participantId);import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
await meeting.participants.rejectWaitingRoomRequest(participantId);meeting.participants.rejectWaitingRoomRequest(participantId)meeting.participants.rejectWaitingRoomRequest(participantId)final participant = meeting.participants.waitlisted[0];
meeting.participants.rejectWaitlistedParticipant(participant);await meeting.participants.rejectWaitingRoomRequest(participantId);主持人可以选择将参与者置顶或取消置顶到网格。
const participant = meeting.participants.joined.get(participantId);
// 置顶参与者
await participant.pin();
// 取消置顶参与者
await participant.unpin();import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
const participant = meeting.participants.joined.get(participantId);
// 置顶参与者
await participant.pin();
// 取消置顶参与者
await participant.unpin();val participant = meeting.participants.joined.firstOrNull { it.id == participantId }
participant?.let { pcpt ->
// 置顶参与者
val pinError = pcpt.pin()
// 取消置顶参与者
val unpinError = pcpt.unpin()
}if let participant = meeting.participants.joined.first(where: { $0.id == participantId }) {
// 置顶参与者
let pinError: HostError? = participant.pin()
// 取消置顶参与者
let unpinError: HostError? = participant.unpin()
}// 置顶参与者
participant.pin();
// 取消置顶先前被置顶的参与者
participant.unpin();所需权限:permissions.host.canPinParticipant 必须为 true
const participant = meeting.participants.joined.get(participantId);
// 置顶参与者
await participant.pin();
// 取消置顶参与者
await participant.unpin();主持人可以修改参与者的权限。参与者的权限由其预设定义。
此平台不支持更新参与者权限。
首先,找到您要更新的参与者。
const participantIds = meeting.participants.joined
.toArray()
.filter((e) => e.name.startsWith("John"))
.map((p) => p.id);使用 updatePermissions 方法修改参与者的权限。
// 允许在公共聊天中上传文件的权限
const newPermissions = {
chat: {
public: {
files: true,
},
},
};
meeting.participants.updatePermissions(participantIds, newPermissions);可以修改以下权限:
interface UpdatedPermissions {
polls?: {
canCreate?: boolean;
canVote?: boolean;
};
plugins?: {
canClose?: boolean;
canStart?: boolean;
};
chat?: {
public?: {
canSend?: boolean;
text?: boolean;
files?: boolean;
};
private?: {
canSend?: boolean;
text?: boolean;
files?: boolean;
};
};
}要在 <video> 元素上播放参与者的视频轨道:
<video class="participant-video" id="participant-video"></video>// 获取视频元素
const videoElement = document.getElementById("participant-video");
// 获取参与者
const participant = meeting.participants.joined.get(participantId);
// 注册视频元素
participant.registerVideoElement(videoElement);对于本地用户预览(视频不发送给其他用户):
meeting.self.registerVideoElement(videoElement, true);当不再需要视频元素时进行清理:
participant.deregisterVideoElement(videoElement);要在 <video> 元素上播放参与者的视频轨道:
import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
const [meeting] = useRealtimeKitClient();
// 获取视频元素
const videoElement = document.getElementById("participant-video");
// 获取参与者
const participant = meeting.participants.joined.get(participantId);
// 注册视频元素
participant.registerVideoElement(videoElement);
// 当不再需要视频元素时进行清理
participant.deregisterVideoElement(videoElement);对于本地用户预览(视频不发送给其他用户):
meeting.self.registerVideoElement(videoElement, true);调用 participant.getVideoView(),它会返回一个渲染参与者视频流的 View:
// 获取给定参与者的视频视图
val videoView = participant.getVideoView()
// 获取屏幕共享视频视图
val screenShareView = participant.getScreenShareVideoView()调用 participant.getVideoView(),它会返回一个渲染参与者视频流的 UIView:
// 获取给定参与者的视频视图
let videoView = participant.getVideoView()
// 获取屏幕共享视频视图
let screenShareView = participant.getScreenShareVideoView()使用返回 Widget 的视频视图方法,您可以直接将其放置在 UI 层级中:
// 创建用于显示参与者摄像头视频的组件
final cameraView = VideoView(meetingParticipant: participant);
// 创建用于显示参与者屏幕共享的组件
final screenShareView = ScreenshareView(meetingParticipant: participant);使用 useRealtimeKitSelector 获取视频轨道并使用 RTCView 进行渲染:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react-native";
import { MediaStream, RTCView } from "@cloudflare/react-native-webrtc";
function VideoView() {
const { videoTrack } = useRealtimeKitSelector((m) =>
m.participants.active.toArray(),
)[0];
const stream = new MediaStream(undefined);
stream.addTrack(videoTrack);
return (
<RTCView
objectFit="cover"
style={{ flex: 1 }}
streamURL={stream.toURL()}
mirror={true}
zOrder={1}
/>
);
}