观众端 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 | 内部服务器错误。 | 请重试。若重试后仍然失败,请联系技术支持。 |