本指南介绍如何在 Cloudflare RealtimeKit 中使用舞台管理 API 来实现网络研讨会(Webinar,即 WebRTC)使用场景。
RealtimeKit 配备了可选的托管配置,而不是传统的发布-订阅模型(用户可以发布其媒体,而其他人可以选择订阅)。在此托管配置中,可以为权限较低的用户配置默认不发布媒体的行为。然后,该用户可以请求允许发布其媒体的权限,而特权用户可以选择授予或拒绝访问。
使用 RealtimeKit 的舞台管理 API,用户可以执行以下操作:
- 离开和加入舞台
- 管理舞台请求和权限
- 踢出参与者
可以通过 meeting.stage 命名空间访问舞台模块。
console.log("Stage object:", meeting.stage);console.log("Stage object:", meeting.stage);console.log("Stage object:", meeting.stage);Log.d("Stage", "Stage object: ${meeting.stage}")print("Stage object: \(meeting.stage)")print("Stage object: ${meeting.stage}");console.log("Stage object:", meeting.stage);meeting.stage.status 属性返回本地用户的当前舞台状态。
console.log("Stage status:", meeting.stage.status);console.log("Stage status:", meeting.stage.status);console.log("Stage status:", meeting.stage.status);Log.d("Stage", "Stage status: ${meeting.stage.stageStatus}")print("Stage status: \(meeting.stage.stageStatus)")print("Stage status: ${meeting.stage.status}");console.log("Stage status:", meeting.stage.status);可能的状态值:
ON_STAGE- 用户当前在舞台上,并正在共享音频和视频。OFF_STAGE- 用户正在观看会话,但不在舞台上,且未共享音频或视频。REQUESTED_TO_JOIN_STAGE- 用户有一个等待处理的加入舞台并共享音频和视频的请求。该状态会一直保持,直到主持人接受或拒绝该请求。ACCEPTED_TO_JOIN_STAGE- 主持人已接受用户加入舞台的请求。
RealtimeKit 的舞台管理 API 允许主持人接收和管理舞台请求,以及离开和加入舞台。
此方法将用户连接到媒体室,使其能够与会议中的其他同行(peer)进行交互。
await meeting.stage.join();await meeting.stage.join();await meeting.stage.join();meeting.stage.join()meeting.stage.join()meeting.stage.join();await meeting.stage.join();使用此方法后,用户将与媒体室断开连接,随后无法与同行通信。此外,房间里的其他人也将无法看到其音频和视频。
await meeting.stage.leave();await meeting.stage.leave();await meeting.stage.leave();meeting.stage.leave()meeting.stage.leave()meeting.stage.leave();await meeting.stage.leave();特权用户可以使用 grantAccess 方法授予一组用户访问舞台的权限。
await meeting.stage.grantAccess(userIds);await meeting.stage.grantAccess(userIds);await meeting.stage.grantAccess(userIds);meeting.stage.grantAccess(userIds)meeting.stage.grantAccess(userIds: userIds)meeting.stage.grantAccess(userIds);await meeting.stage.grantAccess(userIds);参数:
userIds(string[]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(List<String>) - 要授予舞台访问权限的用户 ID 列表。您可以使用meeting.participants.map { it.userId }获取用户 ID
userIds([String]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.map { $0.userId }获取用户 ID
userIds(List<String>) - 要授予舞台访问权限的用户 ID 列表。您可以使用meeting.participants.map((p) => p.userId).toList()获取用户 ID
userIds(string[]) - 要授予舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
特权用户可以使用 denyAccess 方法拒绝一组用户访问舞台。
await meeting.stage.denyAccess(userIds);await meeting.stage.denyAccess(userIds);await meeting.stage.denyAccess(userIds);meeting.stage.denyAccess(userIds)meeting.stage.denyAccess(userIds: userIds)meeting.stage.denyAccess(userIds);await meeting.stage.denyAccess(userIds);参数:
userIds(string[]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(List<String>) - 要拒绝舞台访问权限的用户 ID 列表。您可以使用meeting.participants.map { it.userId }获取用户 ID
userIds([String]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.map { $0.userId }获取用户 ID
userIds(List<String>) - 要拒绝舞台访问权限的用户 ID 列表。您可以使用meeting.participants.map((p) => p.userId).toList()获取用户 ID
userIds(string[]) - 要拒绝舞台访问权限的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
特权用户可以使用 kick 方法将一组用户从舞台上移除。
await meeting.stage.kick(userIds);await meeting.stage.kick(userIds);await meeting.stage.kick(userIds);meeting.stage.kick(userIds)meeting.stage.kick(userIds: userIds)meeting.stage.kick(userIds);await meeting.stage.kick(userIds);参数:
userIds(string[]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(string[]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
userIds(List<String>) - 要从舞台中移除的用户 ID 列表。您可以使用meeting.participants.map { it.userId }获取用户 ID
userIds([String]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.map { $0.userId }获取用户 ID
userIds(List<String>) - 要从舞台中移除的用户 ID 列表。您可以使用meeting.participants.map((p) => p.userId).toList()获取用户 ID
userIds(string[]) - 要从舞台中移除的用户 ID 数组。您可以使用meeting.participants.toArray().map(p => p.userId)获取用户 ID
RealtimeKit 的舞台管理 API 允许参与者请求和管理舞台访问。
此方法用于创建一个新的舞台请求,该请求可由主持人批准。每个用户(观众或主持人)都必须调用此方法才能加入舞台。
当主持人调用此方法时,其状态将更新为 ACCEPTED_TO_JOIN_STAGE。
await meeting.stage.requestAccess();await meeting.stage.requestAccess();await meeting.stage.requestAccess();meeting.stage.requestAccess()meeting.stage.requestAccess()meeting.stage.requestAccess();await meeting.stage.requestAccess();您可以调用此方法来取消您的舞台请求。
await meeting.stage.cancelRequestAccess();await meeting.stage.cancelRequestAccess();await meeting.stage.cancelRequestAccess();meeting.stage.cancelRequestAccess()meeting.stage.cancelRequestAccess()meeting.stage.cancelRequestAccess();await meeting.stage.cancelRequestAccess();meeting.stage 模块会触发以下事件:
当舞台访问请求有更新时触发。
meeting.stage.on("stageAccessRequestUpdate", (data) => {
console.log("Stage access request updated:", data);
});或者,您可以使用 React hook 来监听舞台更新:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react";
// useRealtimeKitSelector hook 仅在使用了 `RealtimeKitProvider` 时才有效。
const stageStatus = useRealtimeKitSelector((m) => m.stage.status);meeting.stage.on("stageAccessRequestUpdate", (data) => {
console.log("Stage access request updated:", data);
});meeting.stage.on("stageAccessRequestUpdate", (data) => {
console.log("Stage access request updated:", data);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onStageAccessRequestsUpdated(accessRequests: List<RtkRemoteParticipant>) {
// 舞台访问请求列表已更新
Log.d("Stage", "Access requests updated: ${accessRequests.size}")
}
})extension WebinarViewModel: RtkStageEventListener {
func onStageAccessRequestsUpdated(accessRequests: [RtkRemoteParticipant]) {
// 舞台访问请求列表已更新
print("Access requests updated: \(accessRequests.count)")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onStageAccessRequestsUpdated(List<RtkRemoteParticipant> accessRequests) {
// 舞台访问请求列表已更新
print("Access requests updated: ${accessRequests.length}");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("stageAccessRequestUpdate", (data) => {
console.log("Stage access request updated:", data);
});或者,您可以使用 React hook 来监听舞台更新:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react-native";
// useRealtimeKitSelector hook 仅在使用了 `RealtimeKitProvider` 时才有效。
const stageStatus = useRealtimeKitSelector((m) => m.stage.status);当主持人接受加入舞台请求或直接邀请用户上台时触发。
meeting.stage.on("acceptPresentRequests", (data) => {
console.log("Present requests accepted:", data);
});meeting.stage.on("acceptPresentRequests", (data) => {
console.log("Present requests accepted:", data);
});meeting.stage.on("acceptPresentRequests", (data) => {
console.log("Present requests accepted:", data);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
Log.d("Stage", "Access request accepted")
}
})extension WebinarViewModel: RtkStageEventListener {
func onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
print("Access request accepted")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
print("Access request accepted");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("acceptPresentRequests", (data) => {
console.log("Present requests accepted:", data);
});当本地用户的舞台状态改变时触发。
meeting.stage.on("stageStatusUpdate", (status) => {
console.log("Stage status updated:", status);
});meeting.stage.on("stageStatusUpdate", (status) => {
console.log("Stage status updated:", status);
});meeting.stage.on("stageStatusUpdate", (status) => {
console.log("Stage status updated:", status);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onStageStatusUpdated(oldStatus: StageStatus, newStatus: StageStatus) {
// 本地用户的舞台状态已更改
Log.d("Stage", "Status updated from $oldStatus to $newStatus")
}
})extension WebinarViewModel: RtkStageEventListener {
func onStageStatusUpdated(oldStatus: StageStatus, newStatus: StageStatus) {
// 本地用户的舞台状态已更改
print("Status updated from \(oldStatus) to \(newStatus)")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onStageStatusUpdated(StageStatus oldStatus, StageStatus newStatus) {
// 本地用户的舞台状态已更改
print("Status updated from $oldStatus to $newStatus");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("stageStatusUpdate", (status) => {
console.log("Stage status updated:", status);
});当有新参与者请求加入舞台时触发。
meeting.stage.on("newStageRequest", (request) => {
console.log("New stage request:", request);
});meeting.stage.on("newStageRequest", (request) => {
console.log("New stage request:", request);
});meeting.stage.on("newStageRequest", (request) => {
console.log("New stage request:", request);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onNewStageAccessRequest(participant: RtkRemoteParticipant) {
// 新参与者请求加入舞台
Log.d("Stage", "New stage request from: ${participant.name}")
}
})extension WebinarViewModel: RtkStageEventListener {
func onNewStageAccessRequest(participant: RtkRemoteParticipant) {
// 新参与者请求加入舞台
print("New stage request from: \(participant.name)")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onNewStageAccessRequest(RtkRemoteParticipant participant) {
// 新参与者请求加入舞台
print("New stage request from: ${participant.name}");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("newStageRequest", (request) => {
console.log("New stage request:", request);
});当舞台请求获得主持人批准时触发。
meeting.stage.on("stageRequestApproved", (data) => {
console.log("Stage request approved:", data);
});meeting.stage.on("stageRequestApproved", (data) => {
console.log("Stage request approved:", data);
});meeting.stage.on("stageRequestApproved", (data) => {
console.log("Stage request approved:", data);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
Log.d("Stage", "Stage request approved")
}
})extension WebinarViewModel: RtkStageEventListener {
func onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
print("Stage request approved")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onStageAccessRequestAccepted() {
// 主持人接受了加入舞台请求,或者直接邀请了用户上台
print("Stage request approved");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("stageRequestApproved", (data) => {
console.log("Stage request approved:", data);
});当主持人拒绝舞台请求时触发。
meeting.stage.on("stageRequestRejected", (data) => {
console.log("Stage request rejected:", data);
});meeting.stage.on("stageRequestRejected", (data) => {
console.log("Stage request rejected:", data);
});meeting.stage.on("stageRequestRejected", (data) => {
console.log("Stage request rejected:", data);
});meeting.addStageEventListener(object : RtkStageEventListener {
override fun onStageAccessRequestRejected() {
// 主持人拒绝了加入舞台请求
Log.d("Stage", "Stage request rejected")
}
})extension WebinarViewModel: RtkStageEventListener {
func onStageAccessRequestRejected() {
// 主持人拒绝了加入舞台请求
print("Stage request rejected")
}
}class StageEventListener extends RtkStageEventListener {
@override
void onStageAccessRequestRejected() {
// 主持人拒绝了加入舞台请求
print("Stage request rejected");
}
}
meeting.addStageEventListener(StageEventListener());meeting.stage.on("stageRequestRejected", (data) => {
console.log("Stage request rejected:", data);
});