DataChannels 是一种在客户端之间以低延迟发送任意数据(不仅是音频或视频数据)的方法。DataChannels 适用于聊天、游戏状态或任何其他不需要编码为音频或视频但仍需要实时在客户端之间发送的数据的场景。
虽然可以通过 DataChannels 发送音频和视频,但这并不是最优的,因为音频和视频传输包含 DataChannels 所不具备的特定媒体优化,例如联播(simulcast)、前向纠错、以及在整个 Cloudflare 网络中更好的缓存以进行重新传输。
graph LR
A[发布者] -->|任意数据| B[Cloudflare Realtime SFU]
B -->|任意 data| C@{ shape: procs, label: "订阅者"}
Cloudflare Realtime 上的 DataChannels 可以扩展到每个发布者拥有许多订阅者,每个发布者的订阅者数量没有限制。
- 创建两个 Realtime 会话,一个用于发布者,一个用于订阅者。
- 通过调用
/datachannels/new创建 DataChannel,其中 location 设置为"local",dataChannelName 设置为 DataChannel 的名称。 - 通过调用
/datachannels/new创建 DataChannel,其中 location 设置为"remote",sessionId 设置为发布者的 sessionId。 - 使用 DataChannel 将数据从发布者发送到订阅者。
默认情况下,订阅者在拉取远程 DataChannel 后立即开始接收消息。为避免在订阅者准备好处理它们之前丢失前几条消息,您可以为每个订阅者启用确认门。
- 当您使用 HTTPS API 创建远程 DataChannel 时,设置
waitForAck: true。在门关闭期间,SFU 不会在此 DataChannel 上向该订阅者转发任何消息。 - 订阅者的 DataChannel 打开后,让订阅者在其中发送任何消息(例如,字符串
"ack")。第一条消息将打开门,SFU 开始向该订阅者转发消息。 - 确认信息由 SFU 使用。它不会被转发给发布者或其他订阅者,因此通道保持单向。
- 确认信息必须在创建远程 DataChannel 的 15 秒内到达 SFU。如果未在此时间内到达,SFU 将销毁该门控通道且不转发任何消息;请再次创建远程 DataChannel 以重试。
waitForAck仅适用于location: "remote"的 DataChannels,并且默认值为false,因此现有行为保持不变。
通过在订阅者会话上调用 POST /apps/{appId}/sessions/{sessionId}/datachannels/new 来创建启用了确认门的远程 DataChannel:
{
"dataChannels": [
{
"location": "remote",
"sessionId": "<publisherSessionId>",
"dataChannelName": "my-channel",
"waitForAck": true
}
]
}然后,在订阅者上,一旦 DataChannel 打开就发送确认信息:
const resp = await fetch(`${API_BASE}/sessions/${subscriberId}/datachannels/new`, {
method: "POST",
headers,
body: JSON.stringify({
dataChannels: [
{
location: "remote",
sessionId: publisherId,
dataChannelName: "my-channel",
waitForAck: true,
},
],
}),
}).then((r) => r.json());
const dc = pc.createDataChannel("my-channel-subscribed", {
negotiated: true,
id: resp.dataChannels[0].id,
});
await waitForOpen(dc);
dc.send("ack"); // 第一帧将打开门;后续帧为您的应用程序数据。Cloudflare Realtime SFU DataChannels 是单向的。这意味着您只能将数据从发布者发送到订阅者。订阅者无法将数据发回给发布者。虽然常规的 MediaStream WebRTC DataChannels 是双向的,但这给 Cloudflare Realtime 带来了一个问题,因为 SFU 不知道该将数据发回给哪个会话。对于您拥有多个订阅者并且希望大规模地将数据从发布者发送到所有订阅者的场景(例如在多玩家游戏中向所有玩家分发游戏分数更新),这尤其成问题。
要以双向方式发送数据,您可以使用两个 DataChannels,一个用于将数据从发布者发送给订阅者,另一个用于向相反方向发送数据。
可以在 Realtime 示例 GitHub 仓库 ↗中找到 DataChannels 实际运行的示例。