观众端 URL 拉流

更新时间不可用

了解如何在实时互动 RTC 中观众端 URL 拉流,包括适用场景、配置步骤、实现要点和注意事项。

场景概述

URL 拉流播放指通过 URL 地址从远程服务器获取并播放媒体流。声网提供的 RTE API 支持直接通过 URL 拉取并播放实时媒体流,包括 RTC 频道内的直播流、CDN 直播流。观众端无需显式调用加入频道、订阅等 API,即可观看直播,极大简化开发流程。同时,通过 ABR 功能可以根据网络状况自动切换最优视频质量,提供更好的观看体验。

在开始开发之前,你需要了解以下概念:

  • URL 拉流:一种通过 URL 地址直接获取并播放媒体流的方式。

  • 自适应码率(Adaptive Bitrate,ABR):一种根据网络状况自动调整视频清晰度的技术。当网络状况较差时,SDK 会自动降低视频清晰度以保证流畅播放;当网络恢复后,会自动提升清晰度以提供更好的观看体验。

  • 视频质量层级:在 ABR 中,可以将视频流按照不同的清晰度(分辨率、帧率、码率)划分为多个层级。观众端可以在这些预设的层级之间自动或手动切换,实现最优的观看体验。

本文介绍如何在观众端实现拉流播放,以及使用 ABR 功能来根据网络状况自动切换视频质量层级,优化观看直播流时的视频体验。

前提条件

  • 如果你需要播放 RTC 频道内的直播流,请参考实现 Token 鉴权在你的业务服务端部署 Token 生成器并生成一个 Token。
  • 如果你需要使用 ABR 功能,请联系 sales@shengwang.cn 开通。

实现拉流播放

本节介绍观众端如何通过 URL 拉流播放直播流。

1. 拼接 URL

信息

如果你要播放的是 CDN 直播流或本地媒体文件,可直接跳过本步骤,前往步骤 2。支持播放的格式见播放器支持的格式及协议。

声网支持观众端直接打开特定的 URL 观看直播。你可以参考下列步骤来拼接一个直播 URL。

  1. 对 Token 进行编码。URL 中用于鉴权的 Token 是 Base64 编码,包含了 "+" 和 "/" 字符,这些字符在 URL 中是保留字符。因此需要对 Token 进行百分号编码以避免 URL 解析时产生歧义。下列示例代码展示如何对 Token 进行编码:
C++
// 初始化 Base64 编码的 Token
std::wstring szToken = L"007eJxTYPARkBTeqC9o+oypxlXgV89XfsuE36vm/N40a0aYoMoNqVYFBpNE80Rzg6SUVItEExNTyyTLNEtzC+PEpDRzgxQjY2Mz4xl3UxsCGRmaOtYzMjJAIIjPzGBoZMzAAAB+4RzB";
std::wstring szEncodedToken;

// 定义编码后的 Token 长度和缓冲区
DWORD encodedLength = MAX_PATH;
wchar_t encodedToken[MAX_PATH] = { 0 };

// 对 Token 进行百分号编码
HRESULT result = UrlEscape(szToken.c_str(), encodedToken, &encodedLength, URL_ESCAPE_SEGMENT_ONLY);

// 检查编码结果并输出
if (result == S_OK) {
    szEncodedToken = encodedToken;
} else if (result == E_POINTER) {
    wchar_t* tempBuffer = new wchar_t[encodedLength];
    if (UrlEscape(szToken.c_str(), tempBuffer, &encodedLength, URL_ESCAPE_SEGMENT_ONLY) == S_OK) {
        szEncodedToken = tempBuffer;
    }
    delete[] tempBuffer;
}
  1. 参考下表说明来拼接一个 URL。Base URL 格式定义如下:

    rte://{appid}/{appname}/{channelname}?token={token}&uid={uid}&streamid={streamid}&abr_subscription_layer={subscription_layer}&abr_fallback_layer={fallback_layer}

    字段是否必须说明
    {appid}必须你的项目的 App ID,可在声网控制台获取。
    {appname}可选发布点。如果你配置了 CDN 回源拉流,可以设置该参数。
    {channelname}必须频道名。如果填了 appname,则频道名为 appname|channelname。频道名支持的合法字符为 a-z A-Z 0-9 '-' '_' '.' '~'。
    {token}可选用于鉴权的 Token。生成 Token 后你可以参考步骤 1 对 Token 进行编码。为确保安全性,声网推荐你使用 Token 鉴权。
    {uid}可选观众的用户 ID。
    {streamid}可选主播的用户 ID。你可以通过指定 streamid 来订阅对应主播的媒体流。
    {subscription_layer}可选指定订阅的视频质量层级,详见 RteAbrSubscriptionLayer。
    {fallback_layer}可选网络环境不佳时,指定回退视频质量层级的下限,详见 RteAbrFallbackLayer。
    is_string_uid可选用户 ID 的类型,取值说明见下方。
    表格内容超出当前宽度,可横向滚动查看更多列。

    is_string_uid 取值说明:

    • 0:数字类型。
    • 1:字符串类型。

    注意

    该字段仅适用于内测的网页播放器,如需使用,请联系技术支持。

2. 创建并初始化引擎

你可以从下列两种方式中任选一种来创建 RTE 对象。

信息

以下示例代码和 API 均以 Windows 平台为例。如目标平台为其他平台,请参考对应平台的 API 文档。

  • 调用 Rte 来构造一个 Rte 对象实例。调用 SetConfigs 设置你的项目的 App ID,然后调用 InitMediaEngine 来创建并初始化 RTE 引擎。

    C++
    // 创建一个 Config 对象实例
    rte::Config rteConfig;
    // 设置你项目的 App ID
    rteConfig.SetAppId("The actual appid");
    // 创建一个 Rte 对象实例
    rte::Rte* rte = new rte::Rte();
    // 初始化设置,将配置对象传递给 Rte 对象
    rte->SetConfigs(&rteConfig);
    // 创建和初始化 Rte 引擎
    rte->InitMediaEngine([](rte::Error* err){
      std::cout << "Init media engine done." << std::endl;
    });
  • 如果你已经创建并初始化 RTC 引擎,可直接调用 GetFromBridge 方法从现有的 RTC 引擎中桥接出一个 Rte 对象。

    C++
    rte::Rte *rte;
    *rte = rte::Rte::GetFromBridge();

3. 创建播放器对象

调用 Player 方法创建一个播放器对象。

C++
rte::Player* player = new rte::Player(rte);

4. 渲染主播视图

  1. 调用 Canvas 创建一个画布对象。

  2. 调用 AddView 将一个视图(view)添加到画布中。

  3. 调用 SetCanvas 指定画布对象来显示视频。当视频流成功播放后,视频画面会显示在这个指定的画布上。

    C++
    // 创建 Canvas 对象
    rte::Canvas* canvas = new rte::Canvas(rte);
    RteView view = HWND;    // windows 窗口句柄
    canvas->AddView(&view, nullptr);
    player->SetCanvas(canvas);

5. 打开 URL

调用 OpenWithUrl 来打开 URL 并播放。默认情况下成功打开 URL 后会自动开始播放,如果你想关闭自动播放,可以调用 SetAutoPlay 将 auto_play 设为 false。

注意

如果你打开 URL 失败,需要调用 Stop 停止本次播放,然后再调用 OpenWithUrl 重新打开。

C++
player->OpenWithUrl("rte://{appid}/{appname}/{channelname}", 0, [](rte::Error* err){
});

6. 切换播放源

如果你播放的是 CDN URL 或本地的媒体文件,在播放过程中你可以调用 SwitchWithUrl 切换一个新的播放源。

C++
player->SwitchWithUrl("rtmp://example.com/live/stream123", true, [](rte::Error* err) {
});

声网还支持在播放过程中设置播放音量,如果你播放的是本地媒体文件,还可以从指定位置开始播放、设置播放速度、循环播放次数等,详见 API 文档。

7. 暂停/停止播放

如果需要终止播放,调用 Stop 方法,如果需要暂停当前播放,调用 Pause 方法。

C++
player->Pause();
player->Stop();

示例项目

声网在 GitHub 上提供了一个开源的示例项目供你参考,你可以前往下载或查看其中的源代码。

使用 ABR 功能

ABR(自适应码率)功能允许观众端根据网络状况来选择订阅不同分辨率的视频流。此外,声网还支持用户自定义不同层级的分辨率,观众端可以切换不同分辨率的视频流进行观看。在网络环境不稳定时,SDK 会以指定回退的最低视频质量层级为下限,在此范围内根据网络状况动态调整分辨率。在网络改善时,恢复至订阅的高质量层级。下图展示声网 ABR 功能的技术原理:

1. 主播端设置转码模板

调用 RESTful API 来创建一个转码模板并设置转码参数。

注意

发送 HTTP 请求时,你需要通过 Basic HTTP 认证,并将生成的凭证填入 HTTP 请求头部的 Authorization 字段。具体生成 Authorization 字段的方法请参考实现 HTTP 基本认证。

HTTP 请求

  • 方法:POST
  • 接入点:https://api.agora.io/v1/projects/{appid}/abr/config/layers/{layerid}

路径参数

参数名类型是否必填描述
appidstring是在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。
layeridstring是视频质量层级,取值范围 [1,7]。
表格内容超出当前宽度,可横向滚动查看更多列。

声网支持自定义视频质量层级所对应的分辨率,你可以参考下表进行设置,也可以根据实际需求自行设置:

视频质量层级分辨率
13840x2160
22560x1440
31920x1080
41280x720
5960x540
6854x480
7640x360
表格内容超出当前宽度,可横向滚动查看更多列。

注意

自定义分辨率时请务必将视频质量层级按分辨率从大到小进行排序,分辨率相同时需按帧率从大到小进行排序。

Request Body

请求体包含以下字段:

字段类型是否必填描述
enabledboolean否是否保留此模板,取值说明见下方。
videoobject是视频转码参数设置。
video.widthstring是视频帧的宽度,0 表示自适应。
video.heightstring是视频帧的高度,0 表示自适应。
video.fpsstring否帧率。不填默认与主播源视频流的帧率一致。
video.shortSideAsHeightboolean否在视频转码过程中,是否将视频的短边视为高度,取值说明见下方。
表格内容超出当前宽度,可横向滚动查看更多列。

字段取值说明:

  • enabled:
    • true:保留。
    • false:不保留。如果你无需再使用该模板,可以将其设为 false。
  • video.shortSideAsHeight:
    • true:将视频的短边视为高度。
    • false:不将视频的短边视为高度。

请求示例:

Shell
curl -X POST "https://api.agora.io/v1/projects/{appid}/abr/config/layers/6" \
-H "Authorization: Basic {base64Credentials}" \
-H "Content-Type: application/json" \
-d '{
  "enabled": true,
  "video": {
    "width": 0,
    "height": 480,
    "fps": 15,
    "shortSideAsHeight": true
  }
}'

HTTP 响应

响应包体中包含以下字段:

字段类型说明
statusstring本次请求的状态,取值说明见下方。
messagestring请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。
表格内容超出当前宽度,可横向滚动查看更多列。

status 取值说明:

  • success:请求成功。
  • error:请求失败。
  • fail:请求参数异常,检查你的参数设置。

响应示例:

JSON
// 请求成功时的响应示例
{
  "status": "success",
}

// 请求失败时的响应示例
{
  "status": "error",
  "message": "invalid argument"
}

2. 观众端自适应码率播放

方式一

在拼接 URL时,将主播推流的频道名 {channelname} 改为 {channelname_abr},然后通过 OpenWithUrl 成功打开该 URL 即可启用自适应码率功能。开始播放后,SDK 会根据当前的网络状况自动订阅不同分辨率的视频流。

方式二

此外,声网也支持手动切换到指定的视频质量层级,你可以自定义不同质量层级的视频流所对应的分辨率。SDK 会以你指定订阅的最低质量层级分辨率为下限,在此范围内根据网络状况动态调整分辨率。你可以通过下列 API 来进行设置:

  • SetAbrSubscriptionLayer:设置订阅某一质量层级的视频流。例如,如果你订阅的分辨率层级为 0,则 SDK 会订阅分辨率最高的视频流。
  • SetAbrFallbackLayer:设置订阅的视频流的回退层级。网络情况差时,SDK 会以你指定的回退层级为下限,在此范围内根据网络状况动态调整分辨率。同时,SDK 会持续监控网络质量,并在网络质量改善时恢复至你所订阅的视频流质量层级。

你可以参考下列步骤来实现:

  1. 调用 OpenWithUrl 打开 URL 并播放。

    C++
    // 频道名后拼接 _abr 表示启用自适应码率功能
    std::string url = "rte://xxxxxxxxxxxx/channel_abr?streamid=100006&abr_subscription_layer=0&abr_fallback_layer=1";
    rte::Player* player = new rte::Player(rte);
    // 打开 URL 并播放
    player->OpenWithUrl(url, 0, [](rte::Error* err) {
    });
  2. 调用 SetAbrSubscriptionLayer 设置订阅的视频质量层级。调用 SetAbrFallbackLayer 设置网络情况差时回退的视频质量层级。调用 SetConfigs 将设置应用到播放器中。

    注意

    观众设置订阅的视频分辨率不得超过主播源视频的分辨率。

    C++
    rte::Player* player = new rte::Player(rte);
    
    rte::PlayerConfig playerConfig;
    // 设置订阅的视频质量层级
    playerConfig.SetAbrSubscriptionLayer(kRteAbrSubscriptionLayer1);
    // 设置回退的视频质量层级
    playerConfig.SetAbrFallbackLayer(kRteAbrFallbackLayer6);
    // 播放器配置
    player->SetConfigs(&playerConfig);
  3. 切换不同质量层级的视频流时设置平滑切换以保证画面的连续性和流畅性。

    C++
    RteConfig rteConfig;
    // 通过私有参数开启平滑切换
    rteConfig.SetJsonParameter("{\"rtc.video.smooth_switch_stream_type\":true}");
    // Rte 对象的配置
    rte->SetConfigs(&rteConfig);

如果你需要删除某一自定义视频质量层级的转码参数设置,或是查询某一质量层级的转码参数,请参考删除转码模板、查询转码模板。

开发注意事项

  • URL 拉流和 ABR 功能目前仅支持在单主播场景下使用。
  • 当 ABR 频道持续 60 秒没有观众时,转码任务将自动终止。

参考信息

删除转码模板

删除指定视频质量层级的转码参数设置。

HTTP 请求

  • 方法:DELETE
  • 接入点:https://api.agora.io/v1/projects/{appid}/abr/config/layers/{layerid}

路径参数

参数名类型是否必填描述
appidstring是在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。
layeridstring是你想要删除的视频质量层级,取值范围 [1,7]。
表格内容超出当前宽度,可横向滚动查看更多列。

请求示例:

Shell
curl -X DELETE "https://api.agora.io/v1/projects/{appid}/abr/config/layers/6" \
-H "Authorization: Basic {base64Credentials}" \
-H "Content-Type: application/json"

HTTP 响应

响应包体中包含以下字段:

字段类型说明
statusstring本次请求的状态,取值说明见下方。
messagestring请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。
表格内容超出当前宽度,可横向滚动查看更多列。

status 取值说明:

  • success:请求成功。
  • error:请求失败。
  • fail:请求参数异常,检查你的参数设置。

响应示例:

JSON
// 请求成功时的响应示例
{
  "status": "success",
}

// 请求失败时的响应示例
{
  "status": "error",
  "message": "invalid layerid"
}

查询转码模板

查询全部或指定视频质量层级的转码参数设置。

HTTP 请求

  • 方法:GET
  • 接入点:https://api.agora.io/v1/projects/{appid}/abr/config/layers/{layerid}

路径参数

参数名类型是否必填描述
appidstring是在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。
layeridstring否你想要删除的视频质量层级,取值范围 [1,7]。不填表示查询全部视频质量层级的转码参数设置。
表格内容超出当前宽度,可横向滚动查看更多列。

请求示例:

Shell
curl -X GET "https://api.agora.io/v1/projects/{appid}/abr/config/layers" \
-H "Authorization: Basic {base64Credentials}" \
-H "Content-Type: application/json"

HTTP 响应

响应包体中包含以下字段:

字段类型说明
statusstring本次请求的状态,取值说明见下方。
messagestring请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。
dataobject查询到的转码参数设置。
表格内容超出当前宽度,可横向滚动查看更多列。

status 取值说明:

  • success:请求成功。
  • error:请求失败。
  • fail:请求参数异常,检查你的参数设置。

响应示例:

JSON
// 查询所有层级的响应示例
{
    "status": "success",
    "data": {
        "enabled": true,
        "layers": [
            {
                "layerid": 1,
                "enabled": true,
                "video": {
                    "width": 1280,
                    "height": 720,
                    "bitrate": 2000,
                    "fps": 30
                }
            },
            {
                "layerid": 3,
                "enabled": true,
                "video": {
                    "width": 960,
                    "height": 540,
                    "bitrate": 1200,
                    "fps": 30
                }
            },
            {
                "layerid": 7,
                "enabled": true,
                "video": {
                    "width": 640,
                    "height": 360,
                    "bitrate": 700,
                    "fps": 30
                }
            }
        ]
    }
}

// 查询特定层级的响应示例
{
    "status": "success",
    "data": {
        "layerid": 1,
        "enabled": true,
        "video": {
            "width": 1280,
            "height": 720,
            "bitrate": 2000,
            "fps": 30
        }
    }
}


// 查询失败的响应示例
{
    "status": "fail",
    "message": "layer not found"
}

HTTP 响应状态码

HTTP 响应状态码描述错误原因
200 OK请求成功,服务器成功返回请求的数据。无需处理。
400 Bad Request请求无效,可能的原因见下方。根据响应包体中的 message 信息进行响应的处理。
401 UnauthorizedRESTful API 鉴权失败。请检查 HTTP 基本认证是否符合要求。
404 Not Found传入的 layerid 不存在。请检查 layerid 字段。
405 Method Not Allowed该 App ID 未开通 ABR 功能。请联系技术支持开通 ABR 功能。
429 Too Many RequestsQPS 超过限制。QPS 默认限制为 100。请采取退避策略进行重试。例如,第一次等待 1 秒后重试,第二次等待 3 秒后重试,第三次等待 6 秒后重试。
500 Internal Server Error内部服务器错误。请重试。若重试后仍然失败,请联系技术支持。
表格内容超出当前宽度,可横向滚动查看更多列。

400 Bad Request 可能的原因包括:

  • App ID 不合法。
  • 传入的 layerid 字段不合法。
  • 创建或更新请求内 body 格式错误。