通过 RDT 通道收发消息

更新时间不可用

在文件传输、文件下载等业务场景中,通常需要可靠的数据传输来保证数据的完整性和有序性,从而避免因网络等问题造成的数据丢失。自 1.9.2 版本起,声网提供 RDT(Reliable Data Transmission, 可靠数据传输)功能,允许同一频道中的用户之间建立 RDT 通道并进行可靠的数据传输。

本文主要介绍如何在 RDT 通道中收发消息。

实现原理

RDT 通道是一种基于 RTC Connection 的端到端可靠数据传输通道,如下图所示,RDT 通道与音视频通道相互独立。在一个 RTC Connection 中,你可以同时发送音频数据、视频数据和 RDT 消息。

RDT 消息分为控制消息和数据消息,区别如下:

  • 控制消息 (RDT_STREAM_CMD):发送优先级高,不受拥塞控制策略影响,不会阻塞发送。每秒至多发送 100 个消息包,每个消息包的长度至多为 256 B。
  • 数据消息 (RDT_STREAM_DATA):发送优先级低,受拥塞控制策略影响。如果缓冲区已满,则消息发送失败。对发送的消息包数量没有限制,每个消息包的长度至多为 128 KB。

下图展示通过 RDT 通道收发消息的基本流程:

前提条件

开始前,请确保已完成 SDK 的初始化并创建 RTC Connection。参考 实现媒体流和信令传输。

实现发送和接收 RDT 消息

本节介绍如何实现在 RDT 通道中收发消息。

1. 加入 RTC 频道并建立 RDT 连接

信息

本节仅适用于 v1.9.2 之后、v1.9.4 之前版本的 SDK。对于 v1.9.4 及之后的版本,auto_connect_rdt 在 SDK 内部默认设置为 true,不再需要额外设置;你只需要在调用 agora_rtc_join_channel 加入 RTC 频道时,将 rtc_channel_options_t 中的 enable_rdt 设为 true 即可使用 RDT 功能。如果你不想启用该功能,则将 enable_rdt 设为 false。

加入 RTC 频道时,你可以通过 rtc_channel_options_t 中的 auto_connect_rdt 参数来设置是否主动建立 RDT 连接。SDK 会根据 on_user_joined、on_user_offline 回调和你在 auto_connect_rdt 参数中的设置来处理 RDT 连接:

  • 如果你设置 auto_connect_rdt 参数为 true,则 SDK 会在收到 on_user_joined 回调后主动与远端用户建立 RDT 连接,在收到 on_user_offline 回调后主动与远端用户断开 RDT 连接。
  • 如果你设置 auto_connect_rdt 参数为 false,则 SDK 不会主动与远端用户建立 RDT 连接,但会接受远端用户的连接邀请。

注意

只有用户角色为主播时,SDK 才会触发 on_user_joined 和 on_user_offline 回调。RTSA SDK 中默认所有用户都是主播,无需额外设置用户角色。如果你需要将 RTSA SDK 搭配其他 SDK(例如 RTC SDK)一起使用,请确保你在其他 SDK 中设置用户角色为主播。

不同场景对可靠传输的需求不同,你需要根据实际需求设置 auto_connect_rdt 参数,例如:

  • 在智能摄像头、智能门铃等 IoT 场景中,可能只需要让所有客户端和设备端收发 RDT 消息,但无需让客户端之间收发 RDT 消息。在这种情况下,你需要在设备端加入频道时设置 auto_connect_rdt 为 true,让设备端与每一个客户端都建立 RDT 连接;在客户端加入频道时设置 auto_connect_rdt 为 false,让客户端之间不建立 RDT 连接。
  • 在视频会议、实时协作等办公场景中,可能需要让所有用户之间都能收发数据。在这种情况下,你需要在所有用户加入频道时设置 auto_connect_rdt 为 true,让所有用户都相互建立 RDT 连接。
C
int ret = 0;
connection_id_t conn_id = 0;

ret = agora_rtc_create_connection(&conn_id);
if (ret != 0) {
    printf("error info: %s", agora_rtc_err_2_str(ret));
    return -1;
}

rtc_channel_options_t channel_opt = {0};
// 设置是否主动建立 RDT 连接。true:主动建立连接;false:不主动建立连接
channel_opt.auto_connect_rdt = true;
ret = agora_rtc_join_channel(conn_id, "channel-xxx", uid, token, &channel_opt);
if (ret != 0) {
    printf("error info: %s", agora_rtc_err_2_str(ret));
    return -1;
}

2. 监听 RDT 通道的状态

监听 on_rdt_state 回调,获取 RDT 通道的状态。你需要根据该状态判断能否收发 RDT 消息。

  • RDT_STATE_CLOSED:初始状态,未连接 RDT 通道。该状态下用户不可以收发 RDT 消息。
  • RDT_STATE_OPENED:已连接 RDT 通道。该状态下用户可以收发 RDT 消息。
  • RDT_STATE_BLOCKED:RDT 通道中的发送缓冲区已满。该状态下用户不可以发送数据消息 (RDT_STREAM_DATA),但可以发送控制消息 (RDT_STREAM_CMD)。
  • RDT_STATE_PENDING:正在重新连接 RDT 通道。
    • 如果重新连接成功,则连接状态会变为 RDT_STATE_OPENED,SDK 会保留 RDT 通道中发送和接收缓冲区中的历史数据。
    • 如果重新连接失败,则连接状态会变为 RDT_STATE_CLOSED,SDK 会清除 RDT 通道中发送和接收缓冲区中的历史数据。
  • RDT_STATE_BROKEN:与 RDT 通道的连接已损坏,SDK 会尝试重新连接。SDK 不论能否成功连接,都会清空 RDT 通道中发送和接收缓冲区中的历史数据。
C
rdt_state_e g_rdt_state_for_uid_xxx = RDT_STATE_CLOSED;

void __on_rdt_state(connection_id_t conn_id, uint32_t uid, rdt_state_e state)
{
   g_rdt_state_for_uid_xxx = state;
}

此外,你也可以调用 agora_rtc_get_rdt_status_info 方法主动获取 RDT 通道的状态。

3. 通过 RDT 通道发送消息

当 RDT 通道的状态为 RDT_STATE_OPENED 时,用户之间才真正地成功建立了 RDT 通道,你可以调用 agora_rtc_send_rdt_msg 方法在 RDT 通道中发送消息。

C
if (g_rdt_state_for_uid_xxx == RDT_STATE_OPENED || g_rdt_state_for_uid_xxx == RDT_STATE_BLOCKED) {
    uint8_t cmd[256] = {xxxxx};
    ret = agora_rtc_send_rdt_msg(conn_id, peer_id, RDT_STREAM_CMD, cmd, 256);
    if (ret != 0) {
        printf("error info: %s", agora_rtc_err_2_str(ret));
        return -1;
    }
}

如果 RDT 消息发送失败,SDK 会报告如下错误码,你可以根据错误码判断失败原因并处理:

  • RTC_ERR_RDT_USER_NOT_EXIST (-8): 频道内不存在该远端用户。
  • RTC_ERR_RDT_USER_NOT_READY (-9): 未成功与远端用户建立连接。你需要等 RDT 通道的连接状态变为 RDT_STATE_OPENED 后重新调用该方法。
  • RTC_ERR_RDT_DATA_BLOCKED (-10): 发送缓冲区已满。你需要等 RDT 通道的连接状态变为 RDT_STATE_OPENED 后重新调用该方法。
  • RTC_ERR_RDT_CMD_EXCEED_LIMIT (-11): 控制消息的数量超过限制。每秒发送的控制消息包不能超过 100 个。

4. 通过 RDT 通道接收消息

如需接收 RDT 消息,你可以监听 on_rdt_msg 回调。

C
void __on_rdt_msg(connection_id_t conn_id, uint32_t uid, rdt_stream_type_e type, const void *msg, size_t len)
{
    printf("received rdt msg from uid=%u type=%d msg len=%zu\n", uid, type, len);
}

5. 断开 RDT 连接

离开 RTC 频道后,用户在该频道内创建的 RDT 连接都会自动断开。为避免正在传输中的数据丢失,声网推荐你先调用 agora_rtc_get_rdt_status_info 方法查询发送缓冲区长度 (send_queue_size),确保远端用户已接收完 RDT 消息 (send_queue_size = 0) 后再离开 RTC 频道。

相关信息

本节提供了在实现 RDT 功能时可能需要的参考信息。

示例代码

声网在 SDK 包中提供了以下示例代码供你参考:

Shell
├── agora_rtsa_sdk  # 声网的 SDK 库文件和头文件
└── example  # 示例代码
    └── hello_rdt
        ├── hello_rdt.c  #在单个频道中使用 RDT 通道收发消息
        └── hello_rdt_multi.c  #在多频道中使用 RDT 通道收发消息

API 参考

在实现功能的过程中,你可能需要参考如下 API 文档: