發起一場直播需要產生一個推流地址用於主播的直播推流,和一個播流地址用於分發給觀眾進行播放。本文檔介紹如何為阿里雲ApsaraVideo for Live服務產生帶鑒權的推流地址和播流地址,以實現安全、可靠的直播流分發。
前提條件
在產生推/播流地址前,您需要完成推/播流網域名稱的添加,並進行推/播流網域名稱關聯,詳細操作請參見添加推流網域名稱和播流網域名稱。
每個網域名稱可產生多個推流和播放地址,支援多場直播並發。推流網域名稱的並發推流上限:北京、上海、深圳為300路,其他直播中心為50路,詳情請參見使用限制。
建置規則
直播地址由協議、推流/播流網域名稱、AppName 、StreamName和鑒權串組成。
直播地址參數說明如下表所示。
參數 | 說明 | 舉例 |
協議 | 直播採用的播放協議 |
|
推流/播流網域名稱 | 已添加的網域名稱,產生推流地址時使用推流網域名稱,產生播流地址時使用播流網域名稱。 |
|
AppName | 直播的應用程式名稱,由使用者自訂,用於區分不同的直播應用或業務情境。 |
|
StreamName | 直播的流名稱,由使用者自訂,用於作為直播流的唯一標識。 |
|
鑒權串 | 是基於推/播流網域名稱配置的鑒權 Key,通過 MD5 演算法產生的加密字串,用於保障直播安全,建置規則請參見推/播流地址鑒權。 |
|
地址產生
您可以根據需要選擇以下任一方式產生推流和播流地址:
控制台產生:適用於初次體驗和測試情境,一鍵產生,地址會自動附帶加密的{鑒權串}。
代碼拼接產生:適用於生產環境。在服務端實現地址產生的自動化,便於您對直播地址進行靈活的管理和分發。
控制台產生
進入直播地址產生器頁面。
完成以下配置擷取推流地址和播放地址,點擊開始產生,即可擷取推/播流地址。
說明直播地址產生器暫不支援產生即時字幕播放地址。
代碼拼接產生
1.拼接URI
拼接規則為{協議}://{直播網域名稱}/{AppName}/{streamName},各種協議樣本請參考推流地址樣本或播流地址樣本。
// 虛擬碼
protocol = "rtmp"
domain = "example.aliyundoc.com"
appName = "liveApp"
streamName = "liveStream"
uri = protocol + "://" + domain + "/" + appName + "/" + streamName
// 結果: rtmp://example.aliyundoc.com/liveApp/liveStream2.擷取鑒權Key
鑒權Key用於產生鑒權串,您可以通過控制台URL鑒權配置或調用DescribeLiveDomainConfigs - 查詢直播網域名稱配置API擷取鑒權Key。
推流地址使用推流網域名稱的鑒權Key,播放地址使用播流網域名稱的鑒權Key。
3.拼接為直播地址
以下範例程式碼以RTMP協議為例,先產生{鑒權串},再拼接出完整的直播地址:
Java
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AuthDemo {
private static String md5Sum(String src) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
md5.update(StandardCharsets.UTF_8.encode(src));
return String.format("%032x", new BigInteger(1, md5.digest()));
}
private static String aAuth(String uri, String key, long exp) {
String pattern = "^(rtmp://)?([^/?]+)(/[^?]*)?(\\\\?.*)?$";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(uri);
String scheme = "", host = "", path = "", args = "";
if (m.find()) {
scheme = m.group(1) == null ? "rtmp://" : m.group(1);
host = m.group(2) == null ? "" : m.group(2);
path = m.group(3) == null ? "/" : m.group(3);
args = m.group(4) == null ? "" : m.group(4);
} else {
System.out.println("NO MATCH");
}
String rand = "0"; // "0" by default, other value is ok
String uid = "0"; // "0" by default, other value is ok
String sString = String.format("%s-%s-%s-%s-%s", path, exp, rand, uid, key);
String hashValue = md5Sum(sString);
String authKey = String.format("%s-%s-%s-%s", exp, rand, uid, hashValue);
if (args.isEmpty()) {
return String.format("%s%s%s%s?auth_key=%s", scheme, host, path, args, authKey);
} else {
return String.format("%s%s%s%s&auth_key=%s", scheme, host, path, args, authKey);
}
}
public static void main(String[] args) {
// 待加密的推/播流地址,example.aliyundoc.com為推/播流網域名稱,liveApp為AppName,liveStream為StreamName
// 推流和播流URL採用同樣的加密方法
// AppName或StreamName不超過256字元,支援數字、大小寫字母、短劃線(-)、底線(_)、等號(=)。
String uri = "rtmp://example.aliyundoc.com/liveApp/liveStream";
// 鑒權Key,推流地址使用推流網域名稱URL鑒權Key,播流地址使用播流網域名稱URL鑒權Key
String key = "<input private key>";
// exp值為UNIX時間戳記,單位秒,最終失效時間由該值加上網域名稱URL鑒權有效時間長度決定
// 比如您在此處設定exp為:目前時間+3600秒,那最終失效時間為:目前時間+3600秒+網域名稱URL鑒權有效時間長度。如果設定exp為:目前時間,那最終失效時間為:目前時間+網域名稱URL鑒權有效時間長度
long exp = System.currentTimeMillis() / 1000 + 1 * 3600;
String authUri = aAuth(uri, key, exp);
System.out.printf("URL : %s\nAuth: %s", uri, authUri);
}
}Python
import re
import time
import hashlib
import datetime
def md5sum(src):
m = hashlib.md5()
m.update(src)
return m.hexdigest()
def a_auth(uri, key, exp):
p = re.compile("^(rtmp://)?([^/?]+)(/[^?]*)?(\\?.*)?$")
if not p:
return None
m = p.match(uri)
scheme, host, path, args = m.groups()
if not scheme: scheme = "rtmp://"
if not path: path = "/"
if not args: args = ""
rand = "0" # "0" by default, other value is ok
uid = "0" # "0" by default, other value is ok
sstring = "%s-%s-%s-%s-%s" %(path, exp, rand, uid, key)
hashvalue = md5sum(sstring.encode('utf-8'))
auth_key = "%s-%s-%s-%s" %(exp, rand, uid, hashvalue)
if args:
return "%s%s%s%s&auth_key=%s" %(scheme, host, path, args, auth_key)
else:
return "%s%s%s%s?auth_key=%s" %(scheme, host, path, args, auth_key)
def main():
# 待加密的推/播流地址,example.aliyundoc.com為推/播流網域名稱,liveApp為AppName,liveStream為StreamName
# 推流和播流URL採用同樣的加密方法
# AppName或StreamName不超過256字元,支援數字、大小寫字母、短劃線(-)、底線(_)、等號(=)。
uri = "rtmp://example.aliyundoc.com/liveApp/liveStream"
# 鑒權Key,推流地址使用推流網域名稱URL鑒權Key,播流地址使用播流網域名稱URL鑒權Key
key = "<input private key>"
# exp值為UNIX時間戳記,單位秒,最終失效時間由該值加上網域名稱URL鑒權有效時間長度決定
# 比如您在此處設定exp為:目前時間+3600秒,那最終失效時間為:目前時間+3600秒+網域名稱URL鑒權有效時間長度。如果設定exp為:目前時間,那最終失效時間為:目前時間+網域名稱URL鑒權有效時間長度
exp = int(time.time()) + 1 * 3600
authuri = a_auth(uri, key, exp)
print("URL : %s\nAUTH: %s" %(uri, authuri))
if __name__ == "__main__":
main()Go
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"regexp"
"time"
)
func md5sum(src string) string {
h := md5.New()
h.Write([]byte(src))
return hex.EncodeToString(h.Sum(nil))
}
func a_auth(uri, key string, exp int64) string {
p, err := regexp.Compile("^(rtmp://)?([^/?]+)(/[^?]*)?(\\?.*)?$")
if err != nil {
fmt.Println(err)
return ""
}
m := p.FindStringSubmatch(uri)
var scheme, host, path, args string
if len(m) == 5 {
scheme, host, path, args = m[1], m[2], m[3], m[4]
} else {
scheme, host, path, args = "rtmp://", "", "/", ""
}
rand := "0" // "0" by default, other value is ok
uid := "0" // "0" by default, other value is ok
sstring := fmt.Sprintf("%s-%d-%s-%s-%s", path, exp, rand, uid, key)
hashvalue := md5sum(sstring)
auth_key := fmt.Sprintf("%d-%s-%s-%s", exp, rand, uid, hashvalue)
if len(args) != 0 {
return fmt.Sprintf("%s%s%s%s&auth_key=%s", scheme, host, path, args, auth_key)
} else {
return fmt.Sprintf("%s%s%s%s?auth_key=%s", scheme, host, path, args, auth_key)
}
}
func main() {
// 待加密的推/播流地址,example.aliyundoc.com為推/播流網域名稱,liveApp為AppName,liveStream為StreamName
// 推流和播流URL採用同樣的加密方法
// AppName或StreamName不超過256字元,支援數字、大小寫字母、短劃線(-)、底線(_)、等號(=)。
uri := "rtmp://example.aliyundoc.com/liveApp/liveStream"
// 鑒權Key,推流地址使用推流網域名稱URL鑒權Key,播流地址使用播流網域名稱URL鑒權Key
key := "<input private key>"
// exp值為UNIX時間戳記,單位秒,最終失效時間由該值加上網域名稱URL鑒權有效時間長度決定
// 比如您在此處設定exp為:目前時間+3600秒,那最終失效時間為:目前時間+3600秒+網域名稱URL鑒權有效時間長度。如果設定exp為:目前時間,那最終失效時間為:目前時間+網域名稱URL鑒權有效時間長度
exp := time.Now().Unix() + 3600
authuri := a_auth(uri, key, exp)
fmt.Printf("URL : %s\nAUTH: %s", uri, authuri)
}PHP
<?php
function a_auth($uri, $key, $exp) {
preg_match("/^(rtmp:\/\/)?([^\/?]+)?(\/[^?]*)?(\\?.*)?$/", $uri, $matches);
$scheme = $matches[1];
$host = $matches[2];
$path = $matches[3];
$args = $matches[4];
if (empty($args)) {
$args ="";
}
if (empty($scheme)) {
$scheme ="rtmp://";
}
if (empty($path)) {
$path ="/";
}
$rand = "0";
// "0" by default, other value is ok
$uid = "0";
// "0" by default, other value is ok
$sstring = sprintf("%s-%u-%s-%s-%s", $path, $exp, $rand, $uid, $key);
$hashvalue = md5($sstring);
$auth_key = sprintf("%u-%s-%s-%s", $exp, $rand, $uid, $hashvalue);
if ($args) {
return sprintf("%s%s%s%s&auth_key=%s", $scheme, $host, $path, $args, $auth_key);
} else {
return sprintf("%s%s%s%s?auth_key=%s", $scheme, $host, $path, $args, $auth_key);
}
}
// 待加密的推/播流地址,example.aliyundoc.com為推/播流網域名稱,liveApp為AppName,liveStream為StreamName
// 推流和播流URL採用同樣的加密方法
// AppName或StreamName不超過256字元,支援數字、大小寫字母、短劃線(-)、底線(_)、等號(=)。
$uri = "rtmp://example.aliyundoc.com/liveApp/liveStream";
// 鑒權Key,推流地址使用推流網域名稱URL鑒權Key,播流地址使用播流網域名稱URL鑒權Key
$key = "<input private key>";
// exp值為UNIX時間戳記,單位秒,最終失效時間由該值加上網域名稱URL鑒權有效時間長度決定
// 比如您在此處設定exp為:目前時間+3600秒,那最終失效時間為:目前時間+3600秒+網域名稱URL鑒權有效時間長度。如果設定exp為:目前時間,那最終失效時間為:目前時間+網域名稱URL鑒權有效時間長度
$exp = time() + 3600;
$authuri = a_auth($uri, $key, $exp);
echo "URL :" . $uri;
echo PHP_EOL;
echo "AUTH:" . $authuri;
?>C#
using System;
using System.Text.RegularExpressions;
using System.Security.Cryptography;
using System.Text;
public class Test
{
public static void Main()
{
// 待加密的推/播流地址,example.aliyundoc.com為推/播流網域名稱,liveApp為AppName,liveStream為StreamName
// 推流和播流URL採用同樣的加密方法
// AppName或StreamName不超過256字元,支援數字、大小寫字母、短劃線(-)、底線(_)、等號(=)。
string uri= "rtmp://example.aliyundoc.com/liveApp/liveStream";
// 鑒權Key,推流地址使用推流網域名稱URL鑒權Key,播流地址使用播流網域名稱URL鑒權Key
string key= "<input private key>";
DateTime dateStart = new DateTime(1970, 1, 1, 8, 0, 0);
// exp值為UNIX時間戳記,單位秒,最終失效時間由該值加上網域名稱URL鑒權有效時間長度決定
// 比如您在此處設定exp為:目前時間+3600秒,那最終失效時間為:目前時間+3600秒+網域名稱URL鑒權有效時間長度。如果設定exp為:目前時間,那最終失效時間為:目前時間+網域名稱URL鑒權有效時間長度
string exp = Convert.ToInt64((DateTime.Now - dateStart).TotalSeconds+3600).ToString();
string authUri = aAuth(uri, key, exp);
Console.WriteLine (String.Format("URL :{0}",uri));
Console.WriteLine (String.Format("AUTH :{0}",authUri));
}
public static string aAuth(string uri, string key, string exp)
{
Regex regex = new Regex("^(rtmp://)?([^/?]+)(/[^?]*)?(\\\\?.*)?$");
Match m = regex.Match(uri);
string scheme = "rtmp://", host = "", path = "/", args = "";
if (m.Success)
{
scheme=m.Groups[1].Value;
host=m.Groups[2].Value;
path=m.Groups[3].Value;
args=m.Groups[4].Value;
}else{
Console.WriteLine ("NO MATCH");
}
string rand = "0"; // "0" by default, other value is ok
string uid = "0"; // "0" by default, other value is ok
string u = String.Format("{0}-{1}-{2}-{3}-{4}", path, exp, rand, uid, key);
string hashValue = Md5(u);
string authKey = String.Format("{0}-{1}-{2}-{3}", exp, rand, uid, hashValue);
if (args=="")
{
return String.Format("{0}{1}{2}{3}?auth_key={4}", scheme, host, path, args, authKey);
} else
{
return String.Format("{0}{1}{2}{3}&auth_key={4}", scheme, host, path, args, authKey);
}
}
public static string Md5(string value)
{
MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] bytes = Encoding.ASCII.GetBytes(value);
byte[] encoded = md5.ComputeHash(bytes);
StringBuilder sb = new StringBuilder();
for(int i=0; i<encoded.Length; ++i)
{
sb.Append(encoded[i].ToString("x2"));
}
return sb.ToString();
}
}推流地址樣本
支援協議 | 地址樣本 | 說明 |
RTMP |
| 標準直播推流協議。 |
ARTC |
| 阿里雲超低延時直播RTS推流地址。 |
SRT |
| SRT協議預設關閉,需為推流網域名稱開啟SRT協議後方可使用,操作指引參見SRT推流。 |
播流地址樣本
播流地址 | 說明 | 支援協議 | 地址樣本 |
標準直播播流地址 | 推流為SRT協議時,播流協議支援RTMP、FLV、HLS、ARTC。 | RTMP |
|
FLV |
| ||
HLS |
| ||
ARTC |
| ||
轉碼流播流地址(通用轉碼/自訂轉碼) | 轉碼流地址需要在StreamName後加 | RTMP |
|
FLV |
| ||
HLS |
| ||
ARTC |
| ||
轉碼流播流地址(多碼率轉碼) | 多碼率轉碼流地址需要在StreamName後加 | HLS |
|
延播播流地址 | 延播播流地址需要在 | RTMP |
|
FLV |
| ||
HLS |
| ||
ARTC |
| ||
即時字幕播流地址 | 即時字幕播流地址需要在StreamName後加 | RTMP |
|
FLV |
| ||
HLS |
|
產生地址驗證
本文推薦使用手機端Demo APP推流,和PC端VLC播放器播流完成組建地址有效性驗證,更多推/播流方式請參見直播推流和直播播流:
推流地址驗證:
準備好一台手機,安卓系統或者iOS系統均可。掃描並安裝阿里雲直播應用Demo。
說明iOS端掃碼安裝時如果提示未受信任的企業級開發人員,需要在中找到Taobao對應的信任描述,並選擇信任。
開啟Demo App,選擇網路攝影機推流或錄屏推流。輸入推流地址,控制台產生的地址可使用二維碼掃描輸入。


點擊開始推流,此時就完成了主播開播的流程。
您可以在ApsaraVideo for Live控制台-流管理頁面,看到當前的線上流,若未看到直播流,請確認前面操作步驟是否正確。

播流地址驗證:
在進行直播播放操作時,需保持推流端維持直播推流狀態,否則播放端將會播放失敗。
下載並安裝VLC播放器。下載地址,請參見VLC media player。
運行VLC播放器。
在功能表列中選擇。
在網路頁簽中輸入網路URL,即產生的播放地址,如:
rtmp://pull-singapore.cloud-example.net/testApp/testStream?auth_key=1750150177-0-0-9b7*******31acc543a99c69********
問題排查
進行推流/播流時遇到問題可以使用自助問題排查功能對地址進行檢測,驗證地址,鑒權等資訊是否有效。