观众端 URL 拉流
场景概述
URL 拉流播放指通过 URL 地址从远程服务器获取并播放媒体流。以下是一些典型的适用场景:
- 观众观看直播流:观众可以通过 URL 直接观看直播流。无需实现加入频道、订阅等操作。
- 直播列表预加载:对直播列表可视范围内的不同直播流进行预加载,可以显著减少观众端打开直播流的时间,并可以在不同直播流之间快速切换。
声网提供的 RTE API 支持直接通过 URL 拉取并播放实时媒体流,观众端无需显示调用加入频道、订阅等 API,极大简化了开发流程。同时,通过 ABR 功能可以根据网络状况自动切换最优视频质量,提供更好的观看体验。
在开始开发之前,你需要了解以下概念:
-
URL 拉流:一种通过 URL 地址直接获取并播放媒体流的方式。
-
自适应码率(Adaptive Bitrate,ABR):一种根据网络状况自动调整视频清晰度的技术。当网络状况较差时,SDK 会自动降低视频清晰度以保证流畅播放;当网络恢复后,会自动提升清晰度以提供更好的观看体验。
-
视频质量层级:在 ABR 中,可以将视频流按照不同的清晰度(分辨率、帧率、码率)划分为多个层级。观众端可以在这些预设的层级之间自动或手动切换,实现最优的观看体验。
本文介绍如何在观众端实现拉流播放,以及使用 ABR 功能来根据网络状况自动切换视频质量层级,优化观看直播流时的视频体验。
前提条件
- 参考实现 Token 鉴权在你的业务服务端部署 Token 生成器并生成一个 Token。
- 如果你需要使用 ABR 功能,请联系 sales@shengwang.cn 开通。
实现拉流播放
本节介绍观众端如何通过 URL 拉流播放直播流。
1. 拼接 URL
声网支持观众端直接打开特定的 URL 观看直播。你可以参考下列步骤来拼接一个直播 URL。
-
对 Token 进行编码。URL 中用于鉴权的 Token 是 Base64 编码,包含了 "+" 和 "/" 字符,这些字符在 URL 中是保留字符。因此需要对 Token 进行百分号编码以避免 URL 解析时产生歧义。下列示例代码展示如何对 Token 进行编码:
- Windows
- Objective-C
- Java
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;
}Objective-C// 初始化包含 Base64 编码 Token 的字符串
NSString* token = [[NSString alloc] initWithString:@"007eJxTYPARkBTeqC9o+oypxlXgV89XfsuE36vm/N40a0aYoMoNqVYFBpNE80Rzg6SUVItEExNTyyTLNEtzC+PEpDRzgxQjY2Mz4xl3UxsCGRmaOtYzMjJAIIjPzGBoZMzAAAB+4RzB"];
// 创建 URL 允许字符集,并移除"+"和"/"
NSCharacterSet *allowCharacters = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[(NSMutableCharacterSet*)allowCharacters removeCharactersInString:@"+/"];
// 对 Token 进行百分号编码
NSString* encodedString = [token stringByAddingPercentEncodingWithAllowedCharacters:allowCharacters];
// 输出编码后的 Token
NSLog(@"encoded token: %@", encodedString);JavaString token= "007eJxTYPARkBTeqC9o+oypxlXgV89XfsuE36vm/N40a0aYoMoNqVYFBpNE80Rzg6SUVItEExNTyyTLNEtzC+PEpDRzgxQjY2Mz4xl3UxsCGRmaOtYzMjJAIIjPzGBoZMzAAAB+4RzB";
// 对 Token 进行编码
String encodedToken = Uri.encode(token); -
参考下表说明来拼接一个 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。
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
方法创建一个播放器对象。
rte::Player* player = new rte::Player(rte);
4. 渲染主播视图
-
调用
Canvas
创建一个画布对象。 -
调用
AddView
将一个视图(view)添加到画布中。 -
调用
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
重新打开。
player->OpenWithUrl("rte://{appid}/{appname}/{channelname}", 0, [](rte::Error* err){
});
6. 暂停/停止播放
如果需要终止播放,调用 Stop
方法,如果需要暂停当前播放,调用 Pause
方法。
player->Pause();
player->Stop();
示例项目
声网在 GitHub 上提供了一个开源的示例项目供你参考,你可以前往下载或查看其中的源代码。
- Windows
- Android
- iOS
- macOS
使用 ABR 功能
ABR(自适应码率)功能允许观众端根据网络状况来选择订阅不同分辨率的视频流。此外,声网还支持用户自定义不同层级的分辨率,观众端可以切换不同分辨率的视频流进行观看。在网络环境不稳定时,SDK 会以指定回退的最低视频质量层级为下限,在此范围内根据网络状况动态调整分辨率。在网络改善时,恢复至订阅的高质量层级。下图展示声网 ABR 功能的技术原理:
1. 主播端设置转码模板
调用 RESTful API 来创建一个转码模板并设置转码参数。
发送 HTTP 请求时,你需要通过 Basic HTTP 认证,并将生成的凭证填入 HTTP 请求头部的 Authorization
字段。具体生成 Authorization
字段的方法请参考实现 HTTP 基本认证。
HTTP 请求
路径参数
参数名 | 类型 | 是否必填 | 描述 |
---|---|---|---|
appid | string | 是 | 在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。 |
layerid | string | 是 | 视频质量层级,取值范围 [1,7]。 |
声网支持自定义视频质量层级所对应的分辨率,你可以参考下表进行设置,也可以根据实际需求自行设置:
视频质量层级 | 分辨率 |
---|---|
1 | 3840x2160 |
2 | 2560x1440 |
3 | 1920x1080 |
4 | 1280x720 |
5 | 960x540 |
6 | 854x480 |
7 | 640x360 |
自定义分辨率时请务必将视频质量层级按分辨率从大到小进行排序,分辨率相同时需按帧率从大到小进行排序。
Request Body
请求体包含以下字段:
字段 | 类型 | 是否必填 | 描述 |
---|---|---|---|
enabled | boolean | 否 | 是否保留此模板:
|
video | object | 是 | 视频转码参数设置。 |
video.width | string | 是 | 视频帧的宽度,0 表示自适应。 |
video.height | string | 是 | 视频帧的高度,0 表示自适应。 |
video.fps | string | 否 | 帧率。不填默认与主播源视频流的帧率一致。 |
video.shortSideAsHeight | boolean | 否 | 在视频转码过程中,是否将视频的短边视为高度:
|
请求示例:
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 响应
响应包体中包含以下字段:
字段 | 类型 | 说明 |
---|---|---|
status | string | 本次请求的状态:
|
message | string | 请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。 |
响应示例:
// 请求成功时的响应示例
{
"status": "success",
}
// 请求失败时的响应示例
{
"status": "error",
"message": "invalid argument"
}
2. 观众端自适应码率播放
方式一
在拼接 URL时,将主播推流的频道名 {channelname}
改为 {channelname_abr}
,然后通过 OpenWithUrl
成功打开该 URL 即可启用自适应码率功能。开始播放后,SDK 会根据当前的网络状况自动订阅不同分辨率的视频流。
方式二
此外,声网也支持手动切换到指定的视频质量层级,你可以自定义不同质量层级的视频流所对应的分辨率。SDK 会以你指定订阅的最低质量层级分辨率为下限,在此范围内根据网络状况动态调整分辨率。你可以通过下列 API 来进行设置:
SetAbrSubscriptionLayer
:设置订阅某一质量层级的视频流。例如,如果你订阅的分辨率层级为 0,则 SDK 会订阅分辨率最高的视频流。SetAbrFallbackLayer
:设置订阅的视频流的回退层级。网络情况差时,SDK 会以你指定的回退层级的为下限,在此范围内根据网络状况动态调整分辨率。同时,SDK 会持续监控网络质量,并在网络质量改善时恢复至你所订阅的视频流质量层级。
你可以参考下列步骤来实现:
-
调用
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) {
}); -
调用
SetAbrSubscriptionLayer
设置订阅的视频质量层级。调用SetAbrFallbackLayer
设置网络情况差时回退的视频质量层级。调用SetConfigs
将设置应用到播放器中。注意观众设置订阅的视频分辨率不得超过主播源视频的分辨率。
C++rte::Player* player = new rte::Player(rte);
rte::PlayerConfig playerConfig;
// 设置订阅的视频质量层级
playerConfig.SetAbrSubscriptionLayer(kRteAbrSubscriptionLayer1);
// 设置回退的视频质量层级
playerConfig.SetAbrFallbackLayer(kRteAbrFallbackLayer6);
// 播放器配置
player->SetConfigs(&playerConfig); -
切换不同质量层级的视频流时设置平滑切换。
C++RteConfig rteConfig;
// 通过私有参数开启平滑切换
rteConfig.SetJsonParameter("{\"rtc.video.smooth_switch_stream_type\":true}");
// Rte 对象的配置
rte->SetConfigs(&rteConfig);
如果你需要删除某一自定义视频质量层级的转码参数设置,或是查询某一质量层级的转码参数,请参考删除转码模板、查询转码模板。
开发注意事项
- URL 拉流和 ABR 功能目前仅支持在单主播场景下使用。
- 当 ABR 频道持续 60 秒没有观众时,转码任务将自动终止。
参考信息
删除转码模板
删除指定视频质量层级的转码参数设置。
HTTP 请求
路径参数
参数名 | 类型 | 是否必填 | 描述 |
---|---|---|---|
appid | string | 是 | 在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。 |
layerid | string | 是 | 你想要删除的视频质量层级,取值范围 [1,7]。 |
请求示例:
curl -X DELETE "https://api.agora.io/v1/projects/{appid}/abr/config/layers/6" \
-H "Authorization: Basic {base64Credentials}" \
-H "Content-Type: application/json"
HTTP 响应
响应包体中包含以下字段:
字段 | 类型 | 说明 |
---|---|---|
status | string | 本次请求的状态:
|
message | string | 请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。 |
响应示例:
// 请求成功时的响应示例
{
"status": "success",
}
// 请求失败时的响应示例
{
"status": "error",
"message": "invalid layerid"
}
查询转码模板
查询全部或指定视频质量层级的转码参数设置。
HTTP 请求
路径参数
参数名 | 类型 | 是否必填 | 描述 |
---|---|---|---|
appid | string | 是 | 在声网控制台创建一个项目后即可得到一个 App ID。一个 App ID 是一个项目的唯一标识。 |
layerid | string | 否 | 你想要删除的视频质量层级,取值范围 [1,7]。不填表示查询全部视频质量层级的转码参数设置。 |
请求示例:
curl -X GET "https://api.agora.io/v1/projects/{appid}/abr/config/layers" \
-H "Authorization: Basic {base64Credentials}" \
-H "Content-Type: application/json"
HTTP 响应
响应包体中包含以下字段:
字段 | 类型 | 说明 |
---|---|---|
status | string | 本次请求的状态:
|
message | string | 请求失败或请求参数异常时的详细错误信息。其他常见 HTTP 响应错误码详见HTTP 状态码。 |
data | object | 查询到的转码参数设置。 |
响应示例:
// 查询所有层级的响应示例
{
"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 Unauthorized | RESTful API 认证失败。 | 请检查 HTTP 基本认证是否符合要求。 |
404 Not Found | 传入的 layerid 不存在。 | 请检查 layerid 字段。 |
405 Method Not Allowed | 该 App ID 未开通 ABR 功能。 | 请联系技术支持开通 ABR 功能。 |
429 Too Many Requests | QPS 超过限制。QPS 默认限制为 100。 | 请采取退避策略进行重试。例如,第一次等待 1 秒后重试,第二次等待 3 秒后重试,第三次等待 6 秒后重试。 |
500 Internal Server Error | 内部服务器错误。 | 请重试。若重试后仍然失败,请联系技术支持。 |