前言
現(xiàn)在直播已經(jīng)成為移動(dòng)互聯(lián)網(wǎng)時(shí)代一個(gè)新的重要流量入口塑煎,從YY最铁、斗魚到花椒直播冷尉,直播已經(jīng)成為人們分享交流的新方式系枪,應(yīng)用場景眾多嗤无,主要分為:
金融類直播:金融直播可應(yīng)用于實(shí)時(shí)解盤,在線專家講座割疾,專家在線直播技術(shù)分析嘉栓、指導(dǎo)投資者等使用場景侵佃。
大型賽事馋辈,演唱會(huì)類直播:可應(yīng)用于大型演唱會(huì)迈螟,音樂會(huì),游戲褥民,體育賽事等類直播場景消返。
互動(dòng)類直播:娛樂類互動(dòng)撵颊,如YY等驼鞭。
會(huì)議類直播:大型會(huì)議直播挣棕。
等4大類洛心。在本文中词身,我將先從rtmp協(xié)議開始法严,一步步帶領(lǐng)大家搭建一個(gè)簡易高性能的直播平臺(tái)。
RTMP協(xié)議詳解
RTMP協(xié)議Real Time Message Protocol(實(shí)時(shí)信息傳輸協(xié)議)的首字母縮寫拗馒,是由Adobe公司開發(fā)的一種用于解決多媒體數(shù)據(jù)傳輸流多路復(fù)用和分包的網(wǎng)絡(luò)協(xié)議诱桂。它工作在TCP協(xié)議之上挥等,因此是一種提供可靠交付的協(xié)議肝劲,在傳輸時(shí)不會(huì)出現(xiàn)丟包情況郭宝,從而保證了用戶體驗(yàn)(QoE)剩蟀。雖然TCP協(xié)議為了提供可靠交付付出了一些額外的開銷做為代價(jià)育特,占用了一些帶寬和處理器資源缰冤,但是隨著網(wǎng)絡(luò)帶寬的提高和硬件的發(fā)展棉浸,這些開銷會(huì)顯得越來越微不足道。因此RTMP協(xié)議在為了有很好的發(fā)展前景枝恋。
官方定義:
The Real-Time Messaging Protocol (RTMP) was designed for
high-performance transmission of audio, video, and data between Adobe
Flash Platform technologies, including Adobe Flash Player and Adobe
AIR. RTMP is now available as an open specification to create products
and technology that enable delivery of video, audio, and data in the
open AMF, SWF, FLV, and F4V formats compatible with Adobe Flash
Player.
協(xié)議分類
RTMP協(xié)議工作在TCP之上焚碌,是應(yīng)用層協(xié)議, 默認(rèn)的端口是1935霸妹。
RTMPE在RTMP的基礎(chǔ)上增加了加密功能十电。
RTMPT工作在HTTP之上,默認(rèn)端口是80或443,可穿透防火墻鹃骂。
RTMPS類似RTMPT台盯,增加了TLS/SSL的安全功能。
RTMFP為RTMP協(xié)議的UDP版本畏线。
雖然協(xié)議變種有很多,但實(shí)際在我們的直播應(yīng)用中最常見的是原生的RTMP協(xié)議象踊,因此本篇文章以該協(xié)議的1.0版本為基礎(chǔ)温亲,對其它演進(jìn)協(xié)議感興趣的同學(xué)可以關(guān)注本文的后續(xù)知識(shí)。
交互流程
RTMP的交互流程可以分為握手過程杯矩、控制命令傳輸與數(shù)據(jù)傳輸栈虚。
- 握手過程
RTMP 連接以握手開始,RTMP 握手由三個(gè)固定長度的塊組成史隆』晡瘢客戶端 (發(fā)起連接請求的終端) 和服務(wù)器端各自發(fā)送相同的三塊。便于演示泌射,本文將從客戶端發(fā)送的這些塊指定為 C0粘姜、C1 和 C2;將從服務(wù)器端發(fā)送的這些塊分別指定為 S0熔酷、S1 和 S2孤紧。
RTMP握手以客戶端發(fā)送 C0 和 C1 塊開始,客戶端要等收到S1之后才能發(fā)送C2拒秘,客戶端要等收到S2之后才能發(fā)送其他信息(控制信息和真實(shí)音視頻等數(shù)據(jù))号显,服務(wù)端要等到收到C0之后發(fā)送S1, 服務(wù)端必須等到收到C1之后才能發(fā)送S2躺酒, 服務(wù)端必須等到收到C2之后才能發(fā)送其他信息(控制信息和真實(shí)音視頻等數(shù)據(jù))押蚤。以下為RTMP握手的時(shí)序圖介紹。
流程圖中所提到的各種狀態(tài)如下:
狀態(tài) | 描述 |
---|---|
未初始化 | 客戶端在C0中發(fā)送協(xié)議版本羹应,如服務(wù)端支持揽碘,則回發(fā)送S0和S1,如果不能园匹,則連接結(jié)束 |
版本發(fā)送 | 客戶端等待S1包雳刺,服務(wù)端等待C1包,當(dāng)接收到想要的包偎肃,客戶端發(fā)送C2煞烫,服務(wù)端發(fā)送S2,此時(shí)階段變成了ACK的發(fā)送 |
ACK發(fā)送 | 客戶端和服務(wù)端分別等待S2和C2 |
握手完成 | 客戶端和服務(wù)交換消息 |
理論上來講只要滿足以上條件累颂,如何安排6個(gè)Message的順序都是可以的。但在實(shí)際實(shí)現(xiàn)中為了盡量減少通信的次數(shù),客戶端發(fā)送C0+C1紊馏,服務(wù)端發(fā)送S0+S1+S2料饥,再客戶端在發(fā)送C2結(jié)束握手。
-
控制命令傳輸
握手結(jié)束以后朱监,RTMP協(xié)議進(jìn)入控制命令傳輸過程岸啡,客戶端通過發(fā)送connnect命令與服務(wù)器實(shí)現(xiàn)雙向連接。連接成功后赫编,通過發(fā)送createStream命令建立網(wǎng)絡(luò)流巡蘸。
數(shù)據(jù)傳輸
網(wǎng)絡(luò)流建立成功后,推流(將直播內(nèi)容推送至服務(wù)器的過程)過程會(huì)發(fā)送publish命令發(fā)布音視頻內(nèi)容擂送,拉流(服務(wù)器已有直播內(nèi)容,用指定地址進(jìn)行拉取的過程)過程會(huì)發(fā)送play命令播放內(nèi)容悦荒。
協(xié)議格式
URI格式
rtmpt://127.0.0.1/{app}/{stream_name}
- {app}為音頻/視頻和其他內(nèi)容定義的一個(gè)容器。
- {stream_name}為具體的一個(gè)流名稱嘹吨。
消息(Message)格式
消息是RTMP協(xié)議中基本的數(shù)據(jù)單元搬味,不能種類的消息包含有不能的消息類型(Message Type)。RTMP協(xié)議一共規(guī)范了十多種消息類型蟀拷。其中類型為8,9的消息分別用于傳輸音頻和視頻數(shù)據(jù)碰纬。消息頭包含以下信息:
Message Type: 消息類型,占用1個(gè)字節(jié)问芬。
Length: 有效負(fù)載的字節(jié)數(shù)悦析,占用3個(gè)字節(jié)。該字段是用大字節(jié)序表示的此衅。
Timestamp: 時(shí)間戳强戴,占用4個(gè)字節(jié),用大字節(jié)序表示炕柔。
Message Stream Id: 消息流ID酌泰,標(biāo)識(shí)消息所使用的流,用大字節(jié)序表示匕累。
消息塊格式
在網(wǎng)絡(luò)上傳輸數(shù)據(jù)時(shí)陵刹,消息需要被拆分成較小的數(shù)據(jù)塊才適合在相應(yīng)的網(wǎng)絡(luò)環(huán)境上傳輸。RTMP協(xié)議中規(guī)范了對消息拆分成消息塊欢嘿,每個(gè)消息塊首部(ChunkHeader)有三部分組成:用于標(biāo)識(shí)本塊的ChunkBasicHeader衰琐,用于標(biāo)識(shí)本塊負(fù)載所屬消息的ChunkMessageHeader,以及當(dāng)時(shí)間戳溢出時(shí)才出現(xiàn)的ExtendedTimestamp炼蹦。
消息分塊
RTMP傳輸媒體數(shù)據(jù)的過程中羡宙,發(fā)送端首先把媒體數(shù)據(jù)封裝成消息,然后把消息分割成消息塊掐隐,最后將分割后的消息塊通過TCP協(xié)議發(fā)送出去狗热。接收端在通過TCP協(xié)議收到數(shù)據(jù)后钞馁,首先把消息塊重新組合成消息,然后通過對消息進(jìn)行解封裝處理就可以恢復(fù)出媒體數(shù)據(jù)匿刮。
開源技術(shù)選型
目前直播服務(wù)器有開源和商業(yè)兩種版本僧凰,商業(yè)版本主要又FMS(Flash Media Server)與Wowza。本文章僅針對開源版本做介紹熟丸,相應(yīng)的開源項(xiàng)目主要分為Red5與 Nginx-Rtmp兩類:
Red5
簡介
GitHub:https://github.com/Red5/red5-server (1k+ stars)
Red5是一個(gè)采用Java開發(fā)開源的Flash流媒體服務(wù)器训措。它支持:把音頻(MP3)和視頻(FLV)轉(zhuǎn)換成播放流; 錄制客戶端播放流(只支持FLV)光羞;共享對象绩鸣;現(xiàn)場直播流發(fā)布;遠(yuǎn)程調(diào)用纱兑。Red5使用RTMP, RTMPT, RTMPS, 和RTMPE作為流媒體傳輸協(xié)議呀闻,在其自帶的一些示例中演示了在線錄制,flash流媒體播放萍启,在線聊天总珠,視頻會(huì)議等一些基本功能。
官方給出的主要特性:
Red5 is an Open Source Flash Server written in Java that supports:
- Streaming Video (FLV, F4V, MP4, 3GP)
- Streaming Audio (MP3, F4A, M4A, AAC)
- Recording Client Streams (FLV and AVC+AAC in FLV container)
- Shared Objects
- Live Stream Publishing
- Remoting
- Protocols: RTMP, RTMPT, RTMPS, and RTMPE
Additional features supported via plugin:
- WebSocket (ws and wss)
- RTSP (From Axis-type cameras)
- HLS
安裝與簡單應(yīng)用實(shí)例(Mac下安裝)
前置條件(jdk已安裝)勘纯。
- 創(chuàng)建安裝目錄:
mkdir -p /Users/ypzdw/gitchat/rtmp/red5
- 設(shè)置主目錄環(huán)境變量:
export RED5_HOME=/Users/ypzdw/gitchat/rtmp/red5
- 下載red5應(yīng)用局服,并解壓到RED5_HOME:
目錄簡介:由于 Red5 是在 Tomcat 中運(yùn)行的,因此 Red5 項(xiàng)目與普通 JAVAEE 項(xiàng)目結(jié)構(gòu)類似
conf:red5配置目錄
lib:存放的是一些依賴jar包
weapps:用來存放應(yīng)用程序驳遵,與tomcat下的webapps目錄作用類似淫奔。
- 運(yùn)行:
cd /Users/ypzdw/gitchat/rtmp/red5
./red5.sh &
- 簡單實(shí)例
經(jīng)過前面的介紹,這里將用red5介紹一個(gè)簡單的實(shí)例堤结。打開http://127.0.0.1:5080 出現(xiàn)red5 管理控制臺(tái)唆迁。
選擇"Publisher" demo,該項(xiàng)目提供了主播端與聽課端竞穷。
主播端:“1”中 Name表示流名唐责,publish可以發(fā)布一個(gè)直播。
直播收聽端:“1”中Name為收聽的流名瘾带;“2”中 Location為直播端地址鼠哥;“3”中Log可以觀察到整個(gè)直播的交流日志。
- 停止應(yīng)用:
cd /Users/ypzdw/gitchat/rtmp/red5
./red5-shutdown.sh
Nginx-Rtmp
Github:https://github.com/arut/nginx-rtmp-module (5k+ stars)
簡介
俄羅斯人民開發(fā)的一款NGINX的流媒體插件看政,除了直播發(fā)布音視頻流之外具備流媒體服務(wù)器的常見功能:
RTMP在線直播朴恳。
基于HTTP的FLV/MP4 VOD點(diǎn)播。
HLS (HTTP Live Streaming) M3U8的支持允蚣。
基于http的操作(發(fā)布于颖、播放、錄制)嚷兔。
可以很好的協(xié)同現(xiàn)有的流媒體服務(wù)器以及播放器一起工作森渐。
在線調(diào)用ffmpeg對流媒體進(jìn)行轉(zhuǎn)碼做入。
H264/AAC音視頻編碼格式的支持。
linux/BSD/MAC系統(tǒng)的支持章母。
官方承諾的功能:
- RTMP/HLS/MPEG-DASH live streaming
- RTMP Video on demand FLV/MP4, playing from local filesystem or HTTP
- Stream relay support for distributed streaming: push & pull models
- Recording streams in multiple FLVs
- H264/AAC support
- Online transcoding with FFmpeg
- HTTP callbacks (publish/play/record/update etc)
- Running external programs on certain events (exec)
- HTTP control module for recording audio/video and dropping clients
- Advanced buffering techniques to keep memory allocations at a minimum level for faster streaming and low memory footprint
- Proved to work with Wirecast, FMS, Wowza, JWPlayer, FlowPlayer, StrobeMediaPlayback, ffmpeg, avconv, rtmpdump, flvstreamer and many more
- Statistics in XML/XSL in machine- & human- readable form
- Linux/FreeBSD/MacOS/Windows
常用指令與語法
- Core
rtmp
語法:rtmp { ... }
上下文:nginx根上下文
描述:保存所有 RTMP 配置的塊
server
語法:server { ... }
上下文:rtmp
描述:聲明一個(gè) RTMP 實(shí)例母蛛。
rtmp {
server {
}
}
listen
語法:listen (addr[:port]|port|unix:path)
上下文:server
描述:給 NGINX 添加一個(gè)監(jiān)聽端口以接收 RTMP 連接翩剪。
server {
listen 1935;
}
application
語法:application name { ... }
上下文:server
描述:創(chuàng)建一個(gè) RTMP 應(yīng)用乳怎,application 名不支撐正則表達(dá)式。
server {
listen 1935;
application myapp {
}
}
timeout
語法:timeout value
上下文:rtmp, server
描述:Socket 超時(shí)前弯。這個(gè)值主要用于寫數(shù)據(jù)時(shí)蚪缀。
timeout 60s
;
ping
語法:ping value
上下文:rtmp, server
描述:RTMP ping 間隔。零值的話將 ping 關(guān)掉恕出。RTMP ping 是一個(gè)用于檢查活動(dòng)連接的協(xié)議功能询枚。發(fā)送一個(gè)特殊的包到遠(yuǎn)程連接,然后在ping_timeout
指令指定的時(shí)間內(nèi)期待一個(gè)回復(fù)浙巫。如果在這個(gè)時(shí)間里沒有收到 ping 回復(fù)金蜀,連接斷開。ping 默認(rèn)值為一分鐘的畴。ping_timeout 默認(rèn)值為 30 秒渊抄。
ping 3m;
ping_timeout 30s;
- Access
allow
語法:allow [play|publish] address|subnet|all
上下文:rtmp, server, application
允許來自指定地址或者所有地址發(fā)布/播放。allow 和 deny 指令的先后順序可選丧裁。
allow publish 127.0.0.1;
deny publish all;
allow play 192.168.0.0/24;
deny play all;
deny
語法:deny [play|publish] address|subnet|all
上下文:rtmp, server, application
描述:參考 allow 的描述护桦。
- Exec
exec_push
語法:exec_push command arg*
上下文:rtmp, server, application
描述:定義每個(gè)流發(fā)布時(shí)要執(zhí)行的帶有參數(shù)的外部命令。發(fā)布結(jié)束時(shí)進(jìn)程終止煎娇。第一個(gè)參數(shù)是二進(jìn)制可執(zhí)行文件的完整路徑二庵。執(zhí)行外部命令時(shí)可以使用參數(shù)替換:
$name - 流的名字。
$app - 應(yīng)用名缓呛。
$addr - 客戶端地址催享。
$flashver - 客戶端 flash 版本。
$swfurl - 客戶端 swf url哟绊。
$tcurl - 客戶端 tc url因妙。
$pageurl - 客戶端頁面 url。也可以在 exec 指令中定義 Shell 格式的轉(zhuǎn)向符用于寫輸出和接收輸入匿情。
exec_pull
與exec_push類似兰迫,主要工作在play端。
- Live
live
語法:live on|off
上下文:rtmp, server, application
描述:切換直播模式炬称,即一對多廣播汁果。
live on
;
meta
語法:meta on|off
上下文:rtmp, server, application
描述:切換發(fā)送元數(shù)據(jù)到客戶端。默認(rèn)為 on玲躯。
meta off
;
interleave
語法:interleave on|off
上下文:rtmp, server, application
描述:切換交叉模式据德。在這個(gè)模式下鳄乏,音頻和視頻數(shù)據(jù)會(huì)在同一個(gè) RTMP chunk 流中傳輸。默認(rèn)為 off棘利。
interleave on
;
wait_key
語法:wait_key on|off
上下文:rtmp, server, application
描述:使視頻流從一個(gè)關(guān)鍵幀開始橱野。默認(rèn)為 off。
wait_key on
;
wait_video
語法:wait_video on|off
上下文:rtmp, server, application
描述:在第一個(gè)視頻幀發(fā)送之前禁用音頻善玫。默認(rèn)為 off水援。可以和 wait_key 進(jìn)行組合以使客戶端可以收到具有所有其他數(shù)據(jù)的視頻關(guān)鍵幀茅郎。然而這通常增加連接延遲蜗元。您可以通過在編碼器中調(diào)整關(guān)鍵幀間隔來減少延遲。
wait_video on
;
publish_notify
語法:publish_notify on|off
上下文:rtmp, server, application
描述:發(fā)送 NetStream.Publish.Start 和 NetStream.Publish.Stop 給用戶系冗。默認(rèn)為 off奕扣。
publish_notify on
;
drop_idle_publisher
語法:drop_idle_publisher timeout
上下文:rtmp, server, application
描述:終止指定時(shí)間內(nèi)閑置(沒有音頻/視頻數(shù)據(jù))的發(fā)布連接。默認(rèn)為 off掌敬。注意這個(gè)僅僅對于發(fā)布模式的連接起作用(發(fā)送 publish 命令之后)惯豆。
drop_idle_publisher 10s
;
sync
語法:sync timeout
上下文:rtmp, server, application
描述:同步音頻和視頻流。如果用戶帶寬不足以接收發(fā)布率奔害,服務(wù)器會(huì)丟棄一些幀楷兽。這將導(dǎo)致同步問題。當(dāng)時(shí)間戳差超過 sync 指定的值舀武,將會(huì)發(fā)送一個(gè)絕對幀來解決這個(gè)問題拄养。默認(rèn)為 300 ms。
sync 10ms
;
play_restart
語法:play_restart on|off
上下文:rtmp, server, application
描述:使 nginx-rtmp 能夠在發(fā)布啟動(dòng)或停止時(shí)發(fā)送 NetStream.Play.Start 和 NetStream.Play.Stop 到每個(gè)用戶银舱。如果關(guān)閉的話瘪匿,那么每個(gè)用戶就只能在回放的開始和結(jié)束時(shí)收到這些通知了。默認(rèn)為 on寻馏。
play_restart off
;
- Record
record
語法:record [off|all|audio|video|keyframes|manual]*
上下文:rtmp, server, application, recorder
描述:切換錄制模式棋弥。流可以被記錄到 flv 文件。本指令指定應(yīng)該被記錄的:
off - 什么也不錄制
all - 音頻和視頻(所有)
audio - 音頻
video - 視頻
keyframes - 只錄制關(guān)鍵視頻幀
manual - 用不自動(dòng)啟動(dòng)錄制诚欠,使用控制接口來啟動(dòng)/停止
在單個(gè)記錄指令中可以有任何兼容的組合鍵顽染。
record all
;
record_path
語法:record_path path
上下文:rtmp, server, application, recorder
描述:指定錄制的 flv 文件存放目錄。
record_path /tmp/rec
;
record_suffix
語法:record_suffix value
上下文:rtmp, server, application, recorder
描述:設(shè)置錄制文件后綴名轰绵。默認(rèn)為 '.flv'粉寞。
record_suffix _recorded.flv;
錄制后綴可以匹配 strftime 格式。以下指令
record_suffix -%d-%b-%y-%T.flv
將會(huì)產(chǎn)生形如 mystream-24-Apr-13-18:23:38.flv 的文件左腔。所有支持 strftime 格式的選項(xiàng)可以在 strftime man page 里進(jìn)行查找
record_append
語法:record_append on|off
上下文:rtmp, server, application, recorder
描述:切換文件附加模式唧垦。當(dāng)這一指令為開啟是,錄制時(shí)將把新數(shù)據(jù)附加到老文件液样,如果老文件丟失的話將重新創(chuàng)建一個(gè)振亮。文件中的老數(shù)據(jù)和新數(shù)據(jù)沒有時(shí)間差巧还。默認(rèn)為 off。
record_append on
;
- Relay
pull
語法:pull url [key=value]*
上下文:application
描述:創(chuàng)建 pull 中繼坊秸。流將從遠(yuǎn)程服務(wù)器上拉下來麸祷,成為本地可用的。僅當(dāng)至少有一個(gè)播放器正在播放本地流時(shí)發(fā)生褒搔。
Url 語法:[rtmp://]host[:port][/app[/playpath]]阶牍。如果 application 找不著那么將會(huì)使用本地 application 名。如果找不著 playpath 那么就是用當(dāng)前流的名字站超。
支持以下參數(shù):
app:明確 application 名荸恕。
name:捆綁到 relay 的本地流名字。如果為空或者沒有定義死相,那么將會(huì)使用 application 中的所有本地流。
tcUrl:如果為空的話自動(dòng)構(gòu)建咬像。
pageUrl:模擬頁面 url算撮。
swfUrl:模擬 swf url。
flashVer:模擬 flash 版本县昂,默認(rèn)為 'LNX.11,1,102,55'肮柜。
playPath:遠(yuǎn)程播放地址。
live:切換直播特殊行為倒彰,值:0,1审洞。
start:開始時(shí)間。
stop:結(jié)束時(shí)間待讳。
static:創(chuàng)建靜態(tài) pull芒澜,這樣的 pull 在 nginx 啟動(dòng)時(shí)創(chuàng)建。
如果某參數(shù)的值包含空格创淡,那么你應(yīng)該在整個(gè) key=value 對周圍使用引號(hào)痴晦,比如:'pageUrl=FAKE PAGE URL'。
pullrtmp://cdn2.example.com/another/a?b=1&c=d pageUrl=http://www.example.com/video.html swfUrl=http://www.example.com/player.swf live=1
;
push
語法:push url [key=value]*
上下文:application
描述:push 的語法和 pull 一樣琳彩。不同于 pull 指令的是 push 推送發(fā)布流到遠(yuǎn)程服務(wù)器誊酌。
push_reconnect
語法:push_reconnect time
上下文:rtmp, server, application
描述:在斷開連接后,在 push 重新連接前等待的時(shí)間露乏。默認(rèn)為 3 秒碧浊。
push_reconnect 1s
;
session_relay
語法:session_relay on|off
上下文:rtmp, server, application
描述:切換會(huì)話 relay 模式。在這種模式下連接關(guān)閉時(shí) relay 銷毀瘟仿。當(dāng)設(shè)置為 off 時(shí)箱锐,流關(guān)閉,relay 銷毀猾骡,這樣子以后另一個(gè) relay 可以被創(chuàng)建瑞躺。默認(rèn)為 off敷搪。
session_relay on
;
- Notify
on_connect
語法:on_connect url
上下文:rtmp, server
描述:設(shè)置 HTTP 連接回調(diào)。當(dāng)客戶分發(fā)連接命令一個(gè)連接命令時(shí)幢哨,一個(gè) HTTP 請求異步發(fā)送赡勘,命令處理將被暫停,直到它返回結(jié)果代碼。當(dāng) HTTP 2XX 碼(成功狀態(tài)碼)返回時(shí)捞镰,RTMP 會(huì)話繼續(xù)闸与。返回碼 3XX (重定向狀態(tài)碼)會(huì)使 RTMP 重定向到另一個(gè)從 HTTP 返回頭里獲取到的 application。否則(其他狀態(tài)碼)連接丟棄岸售。
注意這一指令在 application 域是不允許的践樱,因?yàn)?application 在連接階段還是未知的。
HTTP 請求接收到一些參數(shù)凸丸。在 application/x-www-form-urlencoded MIME 類型下使用 POST 方法拷邢。以下參數(shù)將被傳給調(diào)用者:
call=connect。
addr - 客戶端 IP 地址屎慢。
app - application 名瞭稼。
flashVer - 客戶端 flash 版本。
swfUrl - 客戶端 swf url腻惠。
tcUrl - tcUrl环肘。
pageUrl - 客戶端頁面 url。
除了上述參數(shù)以外集灌,所有顯式傳遞給連接命令的參數(shù)也由回調(diào)發(fā)送悔雹。你應(yīng)該將連接參數(shù)和 play/publish 參數(shù)區(qū)分開。播放器常常有獨(dú)特的方式設(shè)置連接字符串不同于 play/publish 流名字欣喧。
on_play
語法:on_play url
上下文:rtmp, server, application
描述:設(shè)置 HTTP 播放回調(diào)谆焊。每次一個(gè)客戶分發(fā)播放命令時(shí)妹孙,一個(gè) HTTP 請求異步發(fā)送骤视,命令處理會(huì)掛起 - 直到它返回結(jié)果碼扛吞。之后再解析 HTTP 結(jié)果碼。
HTTP 2XX 返回碼的話繼續(xù) RTMP 會(huì)話酷鸦。
HTTP 3XX 返回碼的話 重定向 RTMP 到另一個(gè)流饰躲,這個(gè)流的名字在 HTTP 返回頭的 Location 獲取。
HTTP 請求接收到一些個(gè)參數(shù)臼隔。在 application/x-www-form-urlencoded MIME 類型下使用 POST 方法嘹裂。以下參數(shù)會(huì)被傳送給調(diào)用者:
call=play。
addr - 客戶端 IP 地址摔握。
app - application 名寄狼。
flashVer - 客戶端 flash 版本。
swfUrl - 客戶端 swf url。
tcUrl - tcUrl泊愧。
pageUrl - 客戶端頁面 url伊磺。
name - 流名。
on_publish
語法:on_publish url
上下文:rtmp, server, application
描述:同上面提到的 on_play 一樣删咱,唯一的不同點(diǎn)在于這個(gè)指令在發(fā)布命令設(shè)置回調(diào)屑埋。不同于遠(yuǎn)程 pull,push 在這里是可以的痰滋。
on_done
語法:on_done url
上下文:rtmp, server, application
描述:設(shè)置播放/發(fā)布禁止回調(diào)摘能。上述所有適用于此。但這個(gè)回調(diào)并不檢查 HTTP 狀態(tài)碼敲街。
on_play_done
語法:on_publish_done url
上下文:rtmp, server, application
描述:等同于 on_done 的表現(xiàn)团搞,但只適用于播放結(jié)束事件。
on_publish_done
語法:on_publish_done url
上下文:rtmp, server, application
描述:等同于 on_done 的表現(xiàn)多艇,但只適用于發(fā)布結(jié)束事件逻恐。
on_record_done
語法:on_record_done url
上下文:rtmp, server, application, recorder
描述:設(shè)置 record_done 回調(diào)。除了普通 HTTP 回調(diào)參數(shù)它接受錄制文件路徑墩蔓。
on_record_done http://example.com/recorded;
on_update
語法:on_update url
上下文:rtmp, server, application
描述:設(shè)置 update 回調(diào)梢莽。這個(gè)回調(diào)會(huì)在 notify_update_timeout 期間調(diào)用。如果一個(gè)請求返回結(jié)果不是 2XX奸披,連接禁止。這可以用來同步過期的會(huì)話涮雷。追加 time 參數(shù)即播放/發(fā)布調(diào)用后的秒數(shù)會(huì)被發(fā)送給處理程序阵面。
on_update http://example.com/update;
notify_update_timeout
語法:notify_update_timeout timeout
上下文:rtmp, server, application
描述:在 on_update 回調(diào)之間的超時(shí)設(shè)置。默認(rèn)為 30 秒洪鸭。
notify_update_timeout 10s;
on_update http://example.com/update;
notify_update_strict
語法:notify_update_strict on|off
上下文:rtmp, server, application
描述:切換 on_update 回調(diào)嚴(yán)格模式样刷。默認(rèn)為 off。當(dāng)設(shè)置為 on 時(shí)览爵,所有連接錯(cuò)誤置鼻,超時(shí)以及 HTTP 解析錯(cuò)誤和空返回會(huì)被視為更新失敗并導(dǎo)致連接終止。當(dāng)設(shè)置為 off 時(shí)只有 HTTP 返回碼不同于 2XX 時(shí)導(dǎo)致失敗蜓竹。
notify_update_strict on;
on_update http://example.com/update;
notify_relay_redirect
語法:notify_relay_redirect on|off
上下文:rtmp, server, application
描述:使本地流可以重定向?yàn)?on_play 和 on_publish 遠(yuǎn)程重定向箕母。新的流名字是 RTMP URL 用于遠(yuǎn)程重定向。默認(rèn)為 off俱济。
notify_relay_redirect on;
notify_method
語法:notify_method get|post
上下文:rtmp, server, application, recorder
描述:設(shè)置 HTTP 方法通知嘶是。默認(rèn)是帶有 application/x-www-form-urlencoded 的 POST 內(nèi)容類型。在一些情況下 GET 更好蛛碌,例如如果你打算在 nginx 的 http{} 部分處理調(diào)用聂喇。在這種情況下你可以使用 arg_* 變量去訪問參數(shù)。
notify_method get;
Statistics
statistics 模塊不同于本文列舉的其他模塊蔚携,它是 NGINX HTTP 模塊希太。因此 statistics 指令應(yīng)該位于 http{} 塊內(nèi)部克饶。
rtmp_stat
語法:rtmp_stat all
上下文:http, server, location
描述:為當(dāng)前 HTTP location 設(shè)置 RTMP statistics 處理程序。RTMP statistics 是一個(gè)靜態(tài)的 XML 文檔誊辉》龋可以使用 rtmp_stat_stylesheet 指令在瀏覽器中作為 XHTML 頁面查看這個(gè)文檔。
http {
server {
location /stat {
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl {
root /path/to/stat/xsl/file;
}
}
}
rtmp_stat_stylesheet
語法:rtmp_stat_stylesheet path
上下文:http, server, location
描述:添加 XML 樣式表引用到 statistics XML 使其可以在瀏覽器中可視芥映。
測試
我所在的公司的直播業(yè)務(wù)中洲尊,前期也是采用red5,但是隨著用戶數(shù)的不斷增長奈偏,red5完全不能支撐整個(gè)業(yè)務(wù)坞嘀。問題集中爆發(fā)在幾個(gè)方面:
對于單主播,聽者超過400人時(shí)惊来,CPU超過90%(主機(jī)為4核丽涩,32G)。
人數(shù)越多裁蚁,音質(zhì)矢渊,畫面卡頓很多,不穩(wěn)定枉证,用戶體驗(yàn)很差矮男。于是我們決定對red5進(jìn)行替換,對各種選型進(jìn)行了調(diào)研室谚,并在red5相同環(huán)境下做了測試毡鉴,發(fā)現(xiàn)nginx-rtmp的性能非常突出,最終選用nginx-rtmp替換Red5秒赤,到目前為止猪瞬,已經(jīng)無故障運(yùn)行近一年。附nginx-rtmp測試數(shù)據(jù):
Server |CPU|內(nèi)存|連接數(shù)|帶寬|延遲
---|---
nginx-rtmp|8.3%|13MB|500|100Mbps|0.8秒
nginx-rtmp|27.3%|19MB|1000|200Mbps|0.8秒
nginx-rtmp|50.2%|37MB|2500|500Mbps|0.8秒
nginx-rtmp|70.2%|61MB|4000|650Mbps|0.8秒
從測試結(jié)果可以得知入篮,nginx-rtmp模塊運(yùn)行穩(wěn)定陈瘦,單CPU4000人時(shí)負(fù)載只有70%,已經(jīng)接近網(wǎng)卡流量的極限潮售,比Red5 在性能上高一個(gè)數(shù)量級(jí)痊项。
快速實(shí)現(xiàn)一個(gè)直播平臺(tái)
實(shí)戰(zhàn)前準(zhǔn)備
- 硬件
阿里云ECS: CPU:2核心,內(nèi)存:8G饲做,硬盤:40G
- 操作系統(tǒng)
CentOS 7.2 x86_64 Linux
- 配置服務(wù)器
超過1024的連接數(shù)測試需要打開linux的限制线婚。且必須以root登錄和執(zhí)行
設(shè)置連接數(shù):ulimit -HSn 10240
查看連接數(shù):
- 域名
非必須,如沒有盆均,可以直接使用ip也可以塞弊。但是正式環(huán)境中為了減少收聽端對ip地址的依賴性,一般會(huì)使用域名而非ip地址來連接直播服務(wù)器。本文使用域名為datahq.cn.
申請域名:國內(nèi)可以選擇萬網(wǎng)或新網(wǎng)游沿;國外的name.com和godaddy.com口碑不錯(cuò)饰抒。
域名備案:國外的服務(wù)器和網(wǎng)站在上線前都需要經(jīng)過工信部備案和公安部備案;如果在阿里云上購買ECS可以直接使用其的免費(fèi)備案服務(wù)诀黍。
建立直播子域名:
- 客戶端
為方便測試袋坑,本文使用Red5 作為直播的客戶端
- 直播端
目前最好用的直播端軟件是OBS(Open Broadcaster Software)。下載地址是:
https://obsproject.com/download
快速設(shè)置:
視頻的清晰度與碼率和品質(zhì)有關(guān)眯勾,碼率大枣宫,品質(zhì)高,那么視頻的清晰度就高吃环,同時(shí)也颤,對帶寬的要求也越大。詳細(xì)的參數(shù)設(shè)定參考如下:
- 在來源中新增“視頻捕捉設(shè)備”郁轻,并設(shè)置分辨率翅娶,您可以從分辨率選擇最接近的一項(xiàng)。本例分辨率為1280x720好唯,如下圖所示
- 通過“設(shè)置”->“視頻”中設(shè)置壓縮分辨率竭沫,您可以從壓縮分辨率選擇與自己期望最接近的一項(xiàng)。本例期望分辨率為960x540骑篙,如下圖所示
- 直播推流設(shè)置蜕提,打開“設(shè)置”->"流",URL輸入推流地址的URL靶端,流名稱輸入推流的名稱贯溅,如下圖所示
實(shí)戰(zhàn)
- 架構(gòu)方案
目前,我們線上的直播架構(gòu)為:
支撐線上峰值近10萬人躲查,并無故障運(yùn)行一年有余。
配置中心會(huì)定期刷新直播端與收聽端APP的路由信息译柏。
直播端APP推流到Master集群镣煮。
由于nginx-rtmp本身不支持集群,因此我們在架構(gòu)時(shí)沒有采用從Master集群Forward推流到Slave集群的方式鄙麦,而是設(shè)計(jì)了當(dāng)收聽端拉流到slave服務(wù)器集群時(shí)典唇,如果不存在該流,就會(huì)從Master集群主動(dòng)拉取流的架構(gòu)胯府,解決了直播集群的大規(guī)模并發(fā)問題介衔。
該架構(gòu)在大規(guī)模并發(fā)情況下,比Master推流到Slave流的架構(gòu)節(jié)省了很大的帶寬骂因。
除此之外我們對nginx-rtmp進(jìn)行了源代碼的修改炎咖,支撐了一些如合成,轉(zhuǎn)碼,高級(jí)錄制等功能乘盼。
本文為了各位同學(xué)能夠更快的掌握如何搭建的過程升熊,因此沒有采用以上的架構(gòu),相信通過下面的實(shí)踐绸栅,各位也能夠搭建相應(yīng)的架構(gòu)级野。
架構(gòu)圖中黃色標(biāo)識(shí)了我們要使用的直播server。
- 編譯與部署
創(chuàng)建源碼存儲(chǔ)目錄:mkdir -p /root/rtmp/src
粹胯。
進(jìn)入源碼目錄:
cd /root/rtmp/src
下載nginx源碼并解壓蓖柔,注意nginx-rtmp對nginx版本的選擇限制較多,在選擇時(shí)為了少踩不需要的坑风纠,建議根據(jù)官方提示選擇對應(yīng)的nginx 版本况鸣,如圖本文選擇nginx-1.11.5:
wget http://nginx.org/download/nginx-1.11.5.tar.gz
tar -zxvf nginx-1.11.5.tar.gz
下載nginx-rtmp模塊源碼:
wget https://github.com/arut/nginx-rtmp-module/archive/v1.1.10.tar.gz
tar -zxvf v1.1.10.tar.gz
編譯nginx,如果需要調(diào)試消息則打開--with-debug:
./configure --add-module=/root/rtmp/src/nginx-rtmp-module-1.1.10 --with-debug
make
make install
默認(rèn)編譯到路徑:
/usr/local/nginx
驗(yàn)證編譯是否成功:
創(chuàng)建錄制文件存儲(chǔ)目錄:
mkdir -p /usr/local/nginx/files
rtmp 模塊配置(nginx.conf):
本文所采用的配置如下
user root;//使用root用戶運(yùn)行nginx
worker_processes 1;//指明了nginx要開啟的進(jìn)程數(shù),一般等于cpu的總核數(shù),如果沒有出現(xiàn)io性能問題议忽,最好不要修改
error_log logs/error.log debug;//錯(cuò)誤日志存放路徑;日志級(jí)別為debug懒闷,調(diào)試用。
events {
worker_connections 1024;//每個(gè)工作進(jìn)程的最大連接數(shù)量栈幸;
}
http {
include mime.types;//設(shè)定mime類型,類型由mime.type文件定義
default_type application/octet-stream;
client_max_body_size 3m;//設(shè)定通過nginx上傳文件的大小
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';//日志格式設(shè)置
access_log logs/access.log main;//訪問日志存儲(chǔ)路徑
sendfile on;//指定 nginx 是否調(diào)用sendfile 函數(shù)(zero copy 方式)來輸出文件
keepalive_timeout 65;//keepalive超時(shí)時(shí)間
server {//配置虛擬機(jī)
listen 8080;//監(jiān)聽端口
server_name rtmp.datahq.cn 59.110.237.245;//名稱
location /stat{//配置統(tǒng)計(jì)頁面路徑
rtmp_stat all;
rtmp_stat_stylesheet stat.xsl;
}
location /stat.xsl{//統(tǒng)計(jì)模板路徑
root /usr/local/nginx/conf;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
rtmp{
server{
listen 0.0.0.0:1935;//監(jiān)聽端口
ping 30s;//活動(dòng)連接檢查周期
application live{//應(yīng)用名
live on;//打開直播模式
meta copy; //是否發(fā)送直播端元數(shù)據(jù)信息
session_relay on;//打開會(huì)話轉(zhuǎn)發(fā)模式
drop_idle_publisher 10s;//10s沒有推流愤估,自動(dòng)斷開直播端
sync 10ms;//同步流時(shí)間閥值
record_append on;//打開直播流錄制追加模式
record_path /usr/local/nginx/files;//錄制文件地址
record all;//打開錄制功能
}
}
}
拷貝統(tǒng)計(jì)模板到ngin配置目錄:
cp /root/rtmp/src/nginx-rtmp-module-1.1.10/stat.xsl /usr/local/nginx/conf/
啟動(dòng)直播服務(wù)器:
cd /usr/local/nginx/sbin && ./nginx
打開統(tǒng)計(jì)頁面控制臺(tái):
http://rtmp.datahq.cn:8080/stat
統(tǒng)計(jì)表各屬性說明為:
clients:連接數(shù)
live streams:流名
codec:編碼
bits:分辨率
size:視頻畫面大小
fps:每秒傳輸幀數(shù)
freq:音頻率
chan:音頻聲道
State:流狀態(tài)
Time:流活動(dòng)時(shí)間
其它4個(gè)為輸入與輸出流的每秒傳輸速率。
- 測試直播
打開OBS速址,推流至rtmp://rtmp.datahq.cn/live玩焰,流名為demo
打開red5,從rtmp://rtmp.datahq.cn/live拉取直播流芍锚,流名為demo
打開直播統(tǒng)計(jì)后臺(tái):如果看到已經(jīng)有一個(gè)推流昔园,一個(gè)拉流,并有數(shù)據(jù)傳輸時(shí)并炮,說明整個(gè)直播鏈路已經(jīng)暢通默刚。
查看直播錄制文件:
此時(shí)看下系統(tǒng)的負(fù)載:可以發(fā)現(xiàn)CPU,內(nèi)存的負(fù)載都很低逃魄,可以忽略不計(jì)荤西。
- 上線
到本節(jié)為止,一個(gè)簡單的直播平臺(tái)就搭建好了伍俘,接下來我們要做的就是上線邪锌,因?yàn)闆]有上線,一切都是零癌瘾。下面是我們在上線過程中遇到的一些坑觅丰,供各位同學(xué)參考:
系統(tǒng)打開文件數(shù)默認(rèn)太低,造成部分用戶連接不上妨退。
遇到活動(dòng)高峰妇萄,網(wǎng)絡(luò)帶寬成為瓶頸蜕企,造成收聽用戶卡頓很多。在生產(chǎn)環(huán)境中需要時(shí)刻關(guān)注是否升級(jí)帶寬嚣伐。
上線盡量選擇在沒有直播的時(shí)候進(jìn)行糖赔。
總結(jié)
今天給大家分享了直播平臺(tái)搭建的一些知識(shí),涉及到了rtmp協(xié)議轩端,直播選型的一些注意點(diǎn)放典,大規(guī)模直播架構(gòu),nginx-rtmp直播服務(wù)器實(shí)戰(zhàn)搭建等基茵。如果各位有直播的需要奋构,可以順著本文的一些知識(shí)點(diǎn)進(jìn)行實(shí)戰(zhàn)。