开始融合 CDN 直播
为方便快速体验,你可以通过声网控制台完成域名、证书、防盗链密钥等配置,而无需调用 RESTful API。本文介绍如何在声网控制台配置融合 CDN 直播服务,并完成一次简单的直播。
融合 CDN 直播服务提供两种模式,开始配置之前,你需要了解这两种模式的差异:
推流 & 播放模式 | 回源拉流模式 | |
---|---|---|
实现流程 | 开发者把流推到声网服务器,声网服务器再将内容分发给观众。 | 声网服务器从开发者的源站拉流,然后将内容分发给观众。 |
适用场景 | 不需要源站服务器 | 必须有源站服务器 |
配置方式 | 前往声网控制台。详见添加域名配置。 | 根据你的域名灵活性选择:
|
前提条件
开始前,请确保你已经开通服务。
配置服务
声网控制台为融合 CDN 直播提供域名、证书、防盗链密钥等配置选项。
1. 进入配置页面
参考以下步骤:
-
登录声网控制台,点击左侧导航栏的全部产品,选择融合 CDN 直播。
-
在融合 CDN 直播页面,选择功能配置页签,进入开启融合 CDN 服务界面。
2. 添加域名配置
根据你需要的服务模式添加域名配置:
- 推流 & 播放模式
- 回源拉流模式
参考以下步骤配置推流 & 播放模式:
-
点击推流 & 播放页签。
-
添加推流域名:
- 点击添加。
- 填写用于推流的域名,从下拉菜单中选择加速区域。
- 点击创建。
在推流的默认设置中,RTMPS 访问为停用状态,证书和防盗链密钥信息为空。如果需要修改这些设置,点击 图标即可。
-
添加播放域名:
- 点击添加。
- 填写用于播放的域名,从下拉菜单中选择加速区域。
- 点击创建。
在播放的默认设置中,HTTPS 访问为停用状态,证书、跨域设置、防盗链密钥信息为空。如果需要修改这些设置,点击 图标即可。
-
(可选)添加证书:
- 点击添加。
- 填写证书名称。
- 上传你的证书 (
.pem
或.crt
) 和 Key (.key
) 文件。 - 点击保存。
参考以下步骤配置回源拉流模式:
-
点击回源拉流页签。
-
添加回源域名:
- 打开开关。
- 填写源站服务器的域名。
- 点击保存。
-
添加播放域名:
- 点击添加。
- 填写用于播放的域名,从下拉菜单中选择加速区域。
- 点击创建。
在播放的默认设置中,HTTPS 访问为停用状态,证书、跨域设置、防盗链密钥信息为空。如果需要修改这些设置,点击 图标即可。
-
(可选)添加证书:
- 点击添加。
- 填写证书名称。
- 上传你的证书 (
.pem
或.crt
) 和 Key (.key
) 文件。 - 点击保存。
3. 完成 CNAME 配置
完成添加推流域名或播放域名后,声网会自动给该域名分配一个 CNAME (后缀为 .v1.agoramdn.com
)。使用你的推流或播放域名进行直播之前,你需要在域名解析配置中添加对应的 CNAME 记录,让你的域名指向 CNAME。详情请咨询你的域名服务商。
拼接推流 URL
推流支持 RTMP 和 RTMPS 协议。详见拼接推流 URL。
开始推流
你可以通过以下方式开始推流:
拼接播流 URL
播流支持 RTMP、HTTP-FLV、HLS 协议。详见拼接播流 URL。
开始播放
播流可以使用声网 RTC SDK 的媒体播放器,也可以使用你自己的播放器。
后续步骤
调用 RESTful API 实现更多功能
融合 CDN 直播提供一套具有丰富功能的 RESTful API。如果你需要使用域名或发布点管理、直播流录制、直播流鉴权、直播流内容处理等功能,可以查看 API 参考。
如下展示调用融合 CDN 直播 RESTful API 的完整示例代码。
- Python
- Java
- Node.js
- PHP
- Postman 预请求脚本
#!/usr/bin/env python2
import hmac
import base64
import datetime
import requests
import json
from hashlib import sha256
# username
customer_username = "hmac_user_name"
# secret
customer_secret = "hmac_user_secret"
# appid
appid = "your_appid"
# streamName
stream_name = "stream_name"
# content
customer_data = json.dumps({"resumeTime": "2023-11-29T19:00:00+08:00"})
body_sha256 = sha256(customer_data.encode('utf-8')).digest()
body_sha256_base64 = base64.b64encode(body_sha256)
host = "api.sd-rtn.com"
path = "/v1/projects/%s/fls/entry_points/live/admin/banned_streams/%s" % (appid, stream_name)
date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
request_line = "{} {} {}".format("PATCH", path, "HTTP/1.1")
digest = "SHA-256={}".format(body_sha256_base64.decode("utf-8"))
signing_string = "host: {}\ndate: {}\n{}\ndigest: {}".format(host, date, request_line, digest)
signature = base64.b64encode(hmac.new(customer_secret.encode("utf-8"), signing_string.encode("utf-8"), sha256).digest())
authorization = 'hmac username="{}", algorithm="hmac-sha256", headers="host date request-line digest", signature="{}"'.format(
customer_username, signature.decode("utf-8"))
print(authorization)
headers = {
"host": host,
"date": date,
"digest": digest,
"authorization": authorization,
}
print(signing_string)
response = requests.patch("https://{}{}".format(host, path), headers=headers, data=customer_data)
print(response.status_code, response.content.decode())
print(response.headers)
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
public class GatewayKey {
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, InvalidKeyException {
String customerUsername = "hmac_user_name";
String customerSecret = "hmac_user_secret";
String customerData = "";
String appid = "your_appid";
String requestMethod = "GET";
MessageDigest messageDigest;
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(customerData.getBytes("UTF-8"));
String base64encodedString = Base64.getEncoder().encodeToString(messageDigest.digest());
String digest = "SHA-256=" + base64encodedString;
String host = "api.sd-rtn.com";
String path = String.format("/v1/projects/%s/fls/entry_points/live/reports/online_streams", appid);
String requestLine = requestMethod + " " + path + " " + "HTTP/1.1";
final Date currentTime = new Date();
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = sdf.format(currentTime);
String signingString = String.format("host: %s\ndate: %s\n%s\ndigest: %s", host, date, requestLine, digest);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(customerSecret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
String signature = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(signingString.getBytes("UTF-8")));
String authorization = String.format("hmac username=\"%s\", algorithm=\"hmac-sha256\", headers=\"host date request-line digest\", signature=\"%s\"",
customerUsername, signature);
System.out.println(authorization);
System.out.println(signingString);
URL url = new URL("https://" + host + path);
HttpURLConnection http = (HttpURLConnection) url.openConnection();
http.setRequestMethod("GET");
http.setDoOutput(true);
http.setRequestProperty("host", host);
http.setRequestProperty("date", date);
http.setRequestProperty("digest", digest);
http.setRequestProperty("authorization", authorization);
InputStream stream = http.getInputStream();
System.out.println(http.getResponseCode() + " " + http.getResponseMessage());
BufferedReader br = null;
if (http.getResponseCode() == 200) {
br = new BufferedReader(new InputStreamReader(http.getInputStream()));
String strCurrentLine;
while ((strCurrentLine = br.readLine()) != null) {
System.out.println(strCurrentLine);
}
} else {
br = new BufferedReader(new InputStreamReader(http.getErrorStream()));
String strCurrentLine;
while ((strCurrentLine = br.readLine()) != null) {
System.out.println(strCurrentLine);
}
}
http.disconnect();
}
}
var crypto = require("crypto");
var request = require("request");
var customer_username = "{your_hmac_key}";
var customer_secret = "{your_hmac_secret}";
var host = "api.sd-rtn.com";
var path = "/v1/projects/{appid}/fls/entry_points/live/admin/banned_streams/{streamName}";
var method = "PATCH";
var content = {};
content.resumeTime = "2023-11-29T19:00:00+08:00";
var contentString = JSON.stringify(content);
gmt_date = new Date().toGMTString();
digest = "SHA-256=" + Buffer.from(crypto.createHash("sha256").update(contentString).digest()).toString("base64");
request_line = method + " " + path + " " + "HTTP/1.1";
signing_string = "host: " + host;
signing_string = signing_string + "\ndate: " + gmt_date;
signing_string = signing_string + "\n" + request_line;
signing_string = signing_string + "\ndigest: " + digest;
signature = crypto.createHmac("sha256", customer_secret).update(signing_string).digest();
signature = Buffer.from(signature).toString("base64");
authorization = 'hmac username="' + customer_username + '", ';
authorization = authorization + 'algorithm="hmac-sha256", headers="host date request-line digest", signature="';
authorization = authorization + signature + '"';
request.patch(
{
url: "https://" + host + path,
headers: { "content-type": "application/json", date: gmt_date, digest: digest, authorization: authorization },
body: contentString,
},
function (err, res, body) {
console.log("err:", err);
console.log("status:", res.statusCode);
console.log("body:", body);
},
);
<?php
# 声网控制台 RESTful API 中获取的客户 ID
$customer_username = "{your username}";
# 声网控制台 RESTful API 中获取的客户密钥
$customer_secret = "{your secret}";
# 你的声网项目的 App ID
$appid = "{your appid}";
# 请求方法
$request_method = "PATCH";
# 请求包体
$data = "";
# 请求域名
$host = "api.sd-rtn.com";
# 发布点
$entry_point = "live";
# 请求路径
$path = sprintf("/v1/projects/%s/fls/entry_points/%s/reports/online_streams", $appid, $entry_point);
# 日期
$date = gmDate("D, d M Y H:i:s ", time()) . "GMT";
$request_lint = sprintf("%s %s %s", $request_method, $path, "HTTP/1.1");
$data = trim($data);
$digest = 'SHA-256=' . base64_encode(pack("H*", hash("sha256", $data)));
$signing_string = sprintf("host: %s\ndate: %s\n%s\ndigest: %s", $host, $date, $request_lint, $digest);
$signature = base64_encode(pack('H*', hash_hmac('sha256', $signing_string, $customer_secret)));
$authorization = sprintf('hmac username="%s", algorithm="hmac-sha256", headers="host date request-line digest", signature="%s"', $customer_username, $signature);
$header = [
"host: $host",
"date: $date",
"digest: $digest",
"authorization: $authorization",
];
var_dump($header);
var_dump(getCurl("https://$host$path", $header, $request_method, $data));
function getCurl($url, $headerArray, $method, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headerArray);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$output = curl_exec($ch);
curl_close($ch);
$output = json_decode($output, true);
return $output;
}
var customer_username = "hmac_user_name"
var customer_secret = "hmac_user_secret"
gmt_date = new Date().toGMTString()
digest = "SHA-256=" + CryptoJS.enc.Base64.stringify(CryptoJS.SHA256(pm.request.body.raw))
request_line = pm.request.method + " " + pm.request.url.getPath() + " " + "HTTP/1.1"
signing_string = "host: " + pm.request.url.getHost()
signing_string = signing_string + "\ndate: " + gmt_date
signing_string = signing_string + "\n" + request_line
signing_string = signing_string + "\ndigest: " + digest
signature = CryptoJS.HmacSHA256(signing_string, customer_secret)
signature = CryptoJS.enc.Base64.stringify(signature)
authorization = 'hmac username="' + customer_username + '", '
authorization = authorization + 'algorithm="hmac-sha256", headers="host date request-line digest", signature="'
authorization = authorization + signature + '"'
pm.request.headers.add({key: 'date', value: gmt_date})
pm.request.headers.add({key: 'digest', value: digest})
pm.request.headers.add({key: 'authorization', value: authorization})
使用消息通知服务
如果你需要接收推流、录制、截图等业务事件的通知,你还可以使用消息通知服务。