從 0 到 1 打造直播 App
概要
分享內容:
互聯網內容載體變遷歷程,文字——圖片/聲音——視頻——VR/AR——…….。從直播1.0秀場時代(YY),2.0游戲直播(斗魚、虎牙、熊貓)到如今全民直播3.0泛生活娛樂時代(映客、花椒),國外直播app(Meerkat 、Periscope),隨著VA/AR/MR提出的沉浸式視聽體驗,直播4.0時代很快就能到來。
在這個全民娛樂的時代,直播已經火得不要不要的,各大公司都有自己的直播產品。本文主要從直播的一些基本知識,一步步打造直播app。直播那么火的背后有什么樣的技術支撐呢?
先將這些APP按照視頻網站按照視頻網站、彈幕視頻、直播平臺、在線秀場、移動短視頻、移動直播來劃分類別。再按照內容和社交這個維度來進行區分,可以明顯看出視頻網站、彈幕網站和直播平臺更偏內容,他們對內容的需求更加高,用戶在上面進行社交沉淀相對比較淺。
而后面三者更加偏向社交,他們強調人而不強調內容。所以短期內不會有大的競爭關系,只是前三類、后三者之間的競爭會出現。
大體框架
基本是下圖這個套路:
錄制->編碼->網絡傳輸->解碼->播放
以上為直播的整體流程,根據該流程分為以下技術點:
-
怎樣錄制直播視頻
-
怎樣實時上傳直播視頻
-
怎樣播放直播視頻
-
直播間的用戶是如何交互
一、移動視頻直播發展
PC直播(固定場所)——>移動端(形式自由)。
隨著越來越多的直播類 App 上線,移動直播進入了前所未有的爆發階段,目前大多數移動直播以 Native 客戶端為主。但是H5端的直播在移動直播端也承載著不可替代的作用,例如 H5 有著傳播快,易發布的優勢。
完整的直播包括:
-
視頻錄制端
電腦上的音視頻輸入設備或者手機端的攝像頭或者麥克風,目前以移動端的手機視頻為主。
-
視頻播放端
可以是電腦上的播放器,手機端的 Native 播放器,還有 H5 的 video 標簽等。
-
流媒體服務器端
用來接受視頻錄制端提供的視頻源,同時提供給視頻播放端流服務。目前開源的流媒體有RED5,CRTMPD,NGINX-RTMP,SRS。
二、錄制視頻
如何生產視頻數據
封裝格式的主要作用是把視頻碼流和音頻碼流按照一定的格式存儲在一個文件中。
為什么要分封裝格式和視頻編碼格式呢?
這個其實跟網絡分七層模型一個原理。解耦和,降低依賴,底層給上層提供基礎功能,底層和上層都都可以單獨擴展,可以以多種方案組合編碼與封裝,比如MP4與H264、MP4與MPEG、TS與H264等等。比如這里面的這邊文章的編碼就只負責將最原始的音頻和視頻數據就行壓縮,而壓縮完的數據要怎么組織就拜托給上層的封裝,封裝接到視頻音頻數據負責給數據編號,指定同步協議,加入字幕等操作。經過封裝后,得到的就是可以播放的上面提到的視頻文件MP4或者MKV等等。把這個過程反過來就是上圖描述的視頻播放的過程。
1、流媒體源
-
PC端的攝像頭、屏幕
對于PC端的流媒體源,可以使用Open Broadcaster Software串流(支持多種直播平臺)。
-
移動端iOS、Android的攝像頭和麥克風。
iOS、Android主要是系統提供的API實現。
-
webRTC (Web Real-Time Communication)
webRTC是一個支持網頁瀏覽器進行實時語音對話或視頻對話的技術,可以在網頁瀏覽器中進行采集、傳輸、播放,缺點是只在 PC 的 Chrome 上支持較好,移動端支持不太理想。
使用 webRTC 錄制視頻基本流程是:
window.navigator.webkitGetUserMedia() window.webkitRTCPeerConnection webscoket
由于許多方法都要加上瀏覽器前綴,所以很多移動端的瀏覽器還不支持 webRTC,所以真正的視頻錄制還是要靠客戶端(iOS,Android)來實現,效果會好一些。
2、編碼
推薦Andorid4.3(API18)或以上使用硬編,以下版本使用軟編;iOS使用全硬編方案。
-
軟編碼:
libffmpeg
-
硬編碼:
MediaCodec(sdk level 16+, Android 4.1, 4.1.1, the JELLY_BEAN)
3、封裝
FLV(Flash Video)是Adobe公司設計開發的一種流行的流媒體格式,FLV可以使用Flash Player進行播放,FLV封裝格式的文件后綴通常為“.flv”。總體上看,FLV包括文件頭(File Header)和文件體(File Body)兩部分,其中文件體由一系列的Tag組成。
特點:視頻文件體積輕巧、封裝簡單
每個Tag前面還包含了Previous Tag Size字段,表示前面一個Tag的大小。Tag的類型可以是視頻、音頻和Script,每個Tag只能包含以上三種類型的數據中的一種。圖2展示了FLV文件的詳細結構。
Tag Data
-
Audio Tag
-
Video Tag
-
Script Tag(控制幀)或叫meta data tag
該類型Tag又通常被稱為Metadata Tag,會放一些關于FLV視頻和音頻的元數據信息如:duration、width、height等。通常該類型Tag會跟在File Header后面作為第一個Tag出現,而且只有一個。
如圖以Android為例的推流的流程圖:
三、視頻推流(Stream)
如何推
往哪里推
1、協議
國內常見公開的直播協議有幾個:RTMP、HDL(HTTP-FLV)、HLS、RTP。
RTMP
Real Time Messaging Protocol是 Macromedia 開發的一套視頻直播協議,現在屬于 Adobe。
使用RTMP技術的流媒體系統有一個非常明顯的特點:使用 Flash Player 作為播放器客戶端,而Flash Player 現在已經安裝在了全世界將近99%的PC上,因此一般情況下收看RTMP流媒體系統的視音頻是不需要安裝插件的。用戶只需要打開網頁,就可以直接收看流媒體。
和 HLS 一樣都可以應用于視頻直播,區別是 RTMP 基于 flash 無法在 iOS 的瀏覽器里播放,但是實時性比 HLS 要好。所以一般使用這種協議來上傳視頻流,也就是視頻流推送到服務器。
rtmp現在大部分國外的CDN已不支持,在國內流行度很高。原因有幾個方面:
-
開源軟件和開源庫的支持穩定完整。如斗魚主播常用的OBS軟件,開源的librtmp庫,服務端有nginx-rtmp插件。
-
播放端安裝率高。只要瀏覽器支持FlashPlayer就能播放RTMP的直播。相對其他協議而言,RTMP協議初次建立連接的時候握手過程過于復雜(RTMP協議本身的交互是基于TCP),視不同的網絡狀況會帶來給首開帶來100ms以上的延遲。基于RTMP延遲在2~5秒。
HTTP-FLV
即使用HTTP協議流式的傳輸媒體內容,直接向后臺上傳編碼后的流媒體數據。相對于RTMP,HTTP更簡單和廣為人知,而且不擔心被Adobe的專利綁架。內容延遲同樣可以做到2~5秒,打開速度更快,因為HTTP本身沒有復雜的狀態交互。所以從延遲角度來看,HTTP-FLV要優于RTMP。
HLS
即Http Live Streaming,是由蘋果提出基于HTTP的流媒體傳輸協議。HLS有一個非常大的優點:HTML5可以直接打開播放;這個意味著可以把一個直播鏈接通過微信等轉發分享,不需要安裝任何獨立的APP,有瀏覽器即可,所以流行度很高。社交直播APP,HLS可以說是剛需 。
Issue :SRS3.0提出了一種增強型HLS+
RTP
Real-time Transport Protocol,用于Internet上針對多媒體數據流的一種傳輸層協議。
實際應用場景下經常需要RTCP(RTP Control Protocol)配合來使用,可以簡單理解為RTCP傳輸交互控制的信令,RTP傳輸實際的媒體數據。
RTP在視頻監控、視頻會議、IP電話上有廣泛的應用,因為視頻會議、IP電話的一個重要的使用體驗:內容實時性強。
對比與上述3種或實際是2種協議,RTP和它們有一個重要的區別就是默認是使用UDP協議來傳輸數據,而RTMP和HTTP-FLV是基于TCP協議傳輸。
-
UDP:單個數據報,不用建立連接,簡單,不可靠,會丟包,會亂序;
-
TCP:流式,需要建立連接,復雜,可靠 ,有序。
實時音視頻流的場景不需要可靠保障,因此也不需要有重傳的機制,實時的看到圖像聲音,網絡抖動時丟了一些內容,畫面模糊和花屏,完全不重要。TCP為了重傳會造成延遲與不同步,如某一截內容因為重傳,導致1秒以后才到,那么整個對話就延遲了1秒,隨著網絡抖動,延遲還會增加成2秒、3秒,如果客戶端播放是不加以處理將嚴重影響直播的體驗。
是否有除了HLS外更低延遲的方案?
HLS的優點點是顯而易見的:移動端無需安裝APP使用兼容HTML5的瀏覽器打開即可觀看,所有主流的移動端瀏覽器基本都支持HTML5,在直播的傳播和體驗上有巨大的優勢。
下面是 HTTP-FLV、HLS 、 RTMP 的對比:
2、推流
所謂推流,就是將我們已經編碼好的音視頻數據發往視頻流服務器中,常用的第三方庫 librtmp-iOS 進行推流,librtmp 封裝了一些核心的 API 供使用者調用。例如推流 API 等等,配置服務器地址,即可將轉碼后的視頻流推往服務器。一般的推流服務器都配置了服務器端信息。
推流SDK
百度云推流SDK: 官方文檔
七牛推流SDK: Github上的官方源碼及說明
網易云推流SDK: 官方文檔
騰訊云推流SDK: 官方文檔
其他推流SDK:
https://github.com/daniulive/SmarterStreaming
https://github.com/leixiaohua1020/simplest_ffmpeg_mobile
https://github.com/begeekmyfriend/yasea
https://github.com/simple-rtmp-server/srs-sea
推流服務器
那么如何搭建一個推流服務器呢?
簡單的推流服務器搭建,服務器支持 RTMP ,大概需要以下幾個步驟:
-
安裝一臺 nginx 服務器。
-
安裝 nginx 的 RTMP 擴展,目前使用比較多的是 https://github.com/arut/nginx-rtmp-module
-
配置 nginx 的 conf 文件
-
重啟 nginx,將 RTMP 的推流地址寫為 rtmp://ip:1935/hls/mystream, 其中 hls_path 表示生成的 .m3u8 和 ts 文件所存放的地址,hls_fragment 表示切片時長,mysteam 表示一個實例,即將來要生成的文件名可以先自己隨便設置一個。
更多配置可以參考:
https://github.com/arut/nginx-rtmp-module/wiki/
下面是 nginx 的配置文件
騰訊云直播
[后臺SDK]主要是調用騰訊云API。
[服務器API]提供了直播控制臺api概覽:
-
創建直播頻道 CreateLVBChannel
-
查詢直播頻道列表 DescribeLVBChannelList
-
查詢直播頻道詳情 DescribeLVBChannel
-
修改直播頻道 ModifyLVBChannel
-
批量啟用直播頻道 StartLVBChannel
-
批量停止直播頻道 StopLVBChannel
-
查詢直播頻道當前并發收看數 DescribeLVBOnlineUsers
-
刪除直播頻道 DeleteLVBChannel
-
創建錄制任務 CreateRecord
-
終止錄制任務 StopRecord
-
查詢已錄制分片列表 DescribeRecord
-
創建截圖任務 CreateLVBShot
-
終止截圖任務 StopLVBShot
-
查看隊列消息 DescribeQueueLog
騰訊云直播方案整體流程
方案根據騰訊云的快速對接 ,最終形成閉環邏輯。
-
APP
-
視頻源推流
-
向后臺發起創建直播頻道請求
-
向后臺發起停止直播請求
-
-
后臺
-
向騰訊云發起創建、刪除(刪除前先關閉)直播頻道請求
-
直播頻道緩存隊列,處理僵尸頻道
-
向APP客戶端推送直播URL
-
-
Web
-
PC端的流視頻播放器
-
移動客戶端的流視頻播放器
-
流程圖
-
Step1:創建頻道
客戶端發起直播請求,后臺調用CreateLVBChannel,由返回的channel_id調用DescribeLVBChannel查看頻道信息。后臺向客戶端返回推流url和Web直播地址(非flv流視頻地址)。
-
Step2:SDK推流 推流SDK
-
Step3:刪除頻道 APP端推流結束,向后臺發送請求刪除頻道,只有關閉的頻道是可以刪除的,所以后臺刪除一個頻道之前,要先通過停止直播頻道接口StopLVBChannel,先將頻道狀態置為停止,之后在調用刪除直播頻道接口DeleteLVBChannel對頻道進行刪除。
四、播放直播視頻
如何看
下載直播視頻有以下方式:
-
HLS
-
rtmp
-
flv
好看的指標參數
碼率:影響體積,與體積成正比:碼率越大,體積越大;碼率越小,體積越小。
幀率:影響畫面流暢度,與畫面流暢度成正比:幀率越大,畫面越流暢;幀率越小,畫面越有跳動感。如果碼率為變量,則幀率也會影響體積,幀率越高,每秒鐘經過的畫面越多,需要的碼率也越高,體積也越大。
分辨率:影響圖像大小,與圖像大小成正比:分辨率越高,圖像越大;分辨率越低,圖像越小。
1、HLS
對于H5視頻播放,可以使用 HLS(HTTP Live Streaming)協議播放直播流,iOS和 Android 都天然支持這種協議,配置簡單,直接使用 video 標簽即可。
使用 video在移動客戶端上播放直播視頻:
<video controls autoplay> <source src="xxx.m3u8" type="application/vnd.apple.mpegurl"/> </video>
HTTP Live Streaming
HLS是一個由蘋果公司提出的基于HTTP的流媒體網絡傳輸協議。
HLS直播最大的不同在于,直播客戶端獲取到的,并不是一個完整的數據流。
HLS協議在服務器端將直播數據流存儲為連續的、很短時長的媒體文件(MPEG-TS格式),而客戶端則不斷的下載并播放這些小文件,因為服務器端總是會將最新的直播數據生成新的小文件,這樣客戶端只要不停的按順序播放從服務器獲取到的文件,就實現了直播。
由此可見,基本上可以認為,HLS是以點播的技術方式來實現直播。由于數據通過HTTP協議傳輸,所以不用考慮防火墻或者代理的問題,而且分段文件的時長很短,客戶端可以很快的選擇和切換碼率,以適應不同帶寬條件下的播放。不過HLS的這種技術特點決定了延遲一般總是會高于普通的流媒體直播協議。
每一個 .m3u8 文件,分別對應若干個 ts 文件,這些 ts 文件才是真正存放視頻的數據,m3u8 文件只是存放了一些 ts 文件的配置信息和相關路徑,當視頻播放時,.m3u8 是動態改變的,video 標簽會解析這個文件,并找到對應的 ts 文件來播放,所以一般為了加快速度,.m3u8 放在 Web 服務器上,ts 文件放在 CDN 上。
支持的視頻流編碼為H.264,音頻流編碼為AAC。
簡單講就是把整個流分成一個個小的,基于 HTTP 的文件來下載,每次只下載一些,前面提到了用于 H5 播放直播視頻時引入的一個 .m3u8 的文件,這個文件就是基于 HLS 協議,存放視頻流元數據的文件。
-
HLS的分段策略,基本上推薦是10秒一個分片,當然,具體時間還要根據分好后的分片的實際時長做標注
-
為了緩存等方面的原因,在索引文件中會保留最新的三個分片地址,以“滑動窗口”的形式進行刷新。
.m3u8 文件,其實就是以 UTF-8 編碼的 m3u 文件,這個文件本身不能播放,只是存放了播放信息的文本文件。
打開之后就是這個樣子:
EXTM3U m3u文件頭,必須放在第一行
EXT-X-MEDIA-SEQUENCE 第一個TS分片的序列號
EXT-X-TARGETDURATION 每個分片TS的最大的時長
EXT-X-ALLOW-CACHE 是否允許cache
EXT-X-ENDLIST m3u8文件結束符
EXTINF extra info,分片TS的信息,如時長,帶寬等</pre>
EXTM3U
EXT-X-TARGETDURATION:11#EXT-X-VERSION:3#EXT-X-MEDIA-SEQUENCE:0#EXT-X-PLAYLIST-TYPE:VOD
EXTINF:10.133333,
fileSequence0.ts
EXTINF:10.000666,
fileSequence1.ts
EXTINF:10.667334,
fileSequence2.ts
EXTINF:9.686001,
fileSequence3.ts
EXTINF:9.768665,
fileSequence4.ts
EXTINF:10.000000,
fileSequence5.ts
EXT-X-ENDLIST</pre>
ts 文件,就是存放視頻的文件:
HLS只請求基本的HTTP報文,與實時傳輸協議(RTP)不同,HLS可以穿過任何允許HTTP數據通過的防火墻或者代理服務器。它也很容易使用內容分發網絡來傳輸媒體流。
HLS 的請求播放流程
HTTP 請求 m3u8 的 url。
服務端返回一個 m3u8 的播放列表,這個播放列表是實時更新的,一般一次給出5段數據的 url。
客戶端解析 m3u8 的播放列表,再按序請求每一段的 url,獲取 ts 數據流。
HLS直播延時
我們知道 hls 協議是將直播流分成一段一段的小段視頻去下載播放的,所以假設列表里面的包含5個 ts 文件,每個 TS 文件包含5秒的視頻內容,那么整體的延遲就是25秒。因為當你看到這些視頻時,主播已經將視頻錄制好上傳上去了,所以時這樣產生的延遲。當然可以縮短列表的長度和單個 ts 文件的大小來降低延遲,極致來說可以縮減列表長度為1,并且 ts 的時長為1s,但是這樣會造成請求次數增加,增大服務器壓力,當網速慢時回造成更多的緩沖,所以蘋果官方推薦的 ts 時長時10s,所以這樣就會大改有30s的延遲。所以服務器接收流,轉碼,保存,切塊,再分發給客戶端,這里就延時的根本原因。
HLS優勢
但是 H5 直播視頻卻有一些不可替代的優勢:
傳播性好,利于分享等操作。
可以動態發布,有利于實時迭代產品需求并迅速上線。
不用安裝 App,直接打開瀏覽器即可。
2、RTMP
RTMP協議是應用層協議,是要靠底層可靠的傳輸層協議(通常是TCP)來保證信息傳輸的可靠性的。在基于傳輸層協議的鏈接建立完成后,RTMP協議也要客戶端和服務器通過“握手”來建立基于傳輸層鏈接之上的 NetConnection 鏈接,在Connection鏈接上會傳輸一些控制信息,如SetChunkSize,SetACKWindowSize。其中CreateStream命令會創建一個 NetStream 鏈接,用于傳輸具體的音視頻數據和控制這些信息傳輸的命令信息。他們的關系如圖所示:
RTMP Message
RTMP協議傳輸時會對數據做自己的格式化,這種格式的消息我們稱之為RTMP Message,而實際傳輸的時候為了更好地實現多路復用、分包和信息的公平性,發送端會把Message劃分為帶有Message ID的Chunk,每個Chunk可能是一個單獨的Message,也可能是Message的一部分,在接受端會根據chunk中包含的data的長度,message id和message的長度把chunk還原成完整的Message,從而實現信息的收發。
Basic Header(基本的頭信息)
chunk stream ID(流通道Id)和chunk type(chunk的類型,2位fmt),chunk stream id一般被簡寫為CSID,用來唯一標識一個特定的流通道,chunk type決定了后面Message Header的格式。長度有1、2或3個字節
Message Header(消息的頭信息)
Message Header的格式和長度取決于Basic Header的chunk type,共有4種不同的格式,由上面所提到的Basic Header中的fmt字段控制。包含timestamp,timestamp delta,message length,message type id,msg stream id,和0(表示與上一個相同)。
timestamp(時間戳):占用3個字節,因此它最多能表示到16777215=0xFFFFFF=2
24-1, 當它的值超過這個最大值時,這三個字節都置為1,這樣實際的timestamp會轉存到Extended Timestamp字段中,接受端在判斷timestamp字段24個位都為1時就會去Extended timestamp中解析實際的時間戳。
message length(消息數據的長度):占用3個字節,表示實際發送的消息的數據如音頻幀、視頻幀等數據的長度,單位是字節。注意這里是Message的長度,也就是chunk屬于的Message的總數據長度,而不是chunk本身Data的數據的長度。
message type id(消息的類型id):占用1個字節,表示實際發送的數據的類型,如8代表音頻數據、9代表視頻數據。
msg stream id(消息的流id):占用4個字節,表示該chunk所在的流的ID,和Basic Header的CSID一樣,它采用小端存儲的方式,
Extended Timestamp(擴展時間戳)
4個字節,當擴展時間戳啟用時,timestamp字段或者timestamp delta要全置為1,表示應該去擴展時間戳字段來提取真正的時間戳或者時間戳差。注意擴展時間戳存儲的是完整值,而不是減去時間戳或者時間戳差的值。
Chunk Data(塊數據)
用戶層面上真正想要發送的與協議無關的數據,長度在(0,chunkSize]之間。
RTMP在收發數據的時候并不是以Message為單位的,而是把Message拆分成Chunk發送,而且必須在一個Chunk發送完成之后才能開始發送下一個Chunk。每個Chunk中帶有MessageID代表屬于哪個Message,接受端也會按照這個id來將chunk組裝成Message。
舉個例子
chunk表示例1
首先包含第一個Message的chunk的Chunk Type為0,因為它沒有前面可參考的chunk,timestamp為1000。type為0的header占用11個字節,假定CSID為3<127,因此Basic Header占用1個字節,再加上Data的32個字節,因此第一個chunk共44=11+1+32個字節。
第二個chunk和第一個chunk的CSID,TypeId,Data的長度都相同,因此采用Chunk Type=2,timestamp delta=1020-1000=20,因此第二個chunk占用36=3+1+32個字節。
第三個chunk和第二個chunk的CSID,TypeId,Data的長度和時間戳差都相同,因此采用Chunk Type=3省去全部Message Header的信息,占用33=1+32個字節。
第四個chunk和第三個chunk情況相同,也占用33=1+32個字節。
最后實際發送的chunk如下:
chunk表示例2
注意到Data的Length=307>128,因此這個Message要切分成幾個chunk發送,第一個chunk的Type=0,Timestamp=1000,承擔128個字節的Data,因此共占用140=11+1+128個字節。
第二個chunk也要發送128個字節,其他字段也同第一個chunk,因此采用Chunk Type=3,此時時間戳也為1000,共占用129=1+128個字節。
第三個chunk要發送的Data的長度為307-128-128=51個字節,還是采用Type=3,共占用1+51=52個字節。
最后實際發送的chunk如下:
Q:為什么RTMP要將Message拆分成不同的Chunk呢?
A:通過拆分,數據量較大的Message可以被拆分成較小的“Message”,這樣就可以避免優先級低的消息持續發送阻塞優先級高的數據,比如在視頻的傳輸過程中,會包括視頻幀,音頻幀和RTMP控制信息,如果持續發送音頻數據或者控制數據的話可能就會造成視頻幀的阻塞,然后就會造成看視頻時最煩人的卡頓現象。同時對于數據量較小的Message,可以通過對Chunk Header的字段來壓縮信息,從而減少信息的傳輸量。
阻塞 vs. CPU
Chunk的默認大小是128字節,在傳輸過程中,通過一個叫做Set Chunk Size的控制信息可以設置Chunk數據量的最大值,在發送端和接受端會各自維護一個Chunk Size,可以分別設置這個值來改變自己這一方發送的Chunk的最大大小。大一點的Chunk減少了計算每個chunk的時間從而減少了CPU的占用率,但是它會占用更多的時間在發送上,尤其是在低帶寬的網絡情況下,很可能會阻塞后面更重要信息的傳輸。小一點的Chunk可以減少這種阻塞問題,但小的Chunk會引入過多額外的信息(Chunk中的Header),少量多次的傳輸也可能會造成發送的間斷導致不能充分利用高帶寬的優勢,因此并不適合在高比特率的流中傳輸。在實際發送時應對要發送的數據用不同的Chunk Size去嘗試,通過抓包分析等手段得出合適的Chunk大小,并且在傳輸過程中可以根據當前的帶寬信息和實際信息的大小動態調整Chunk的大小,從而盡量提高CPU的利用率并減少信息的阻塞機率。
播放一個RTMP協議的流媒體需要經過以下幾個步驟:握手,建立連接,建立流,播放。RTMP連接都是以握手作為開始的。建立連接階段用于建立客戶端與服務器之間的“網絡連接”;建立流階段用于建立客戶端與服務器之間的“網絡流”;播放階段用于傳輸視音頻數據。
握手(HandShake)
一個RTMP連接以握手開始,雙方分別發送大小固定的三個數據塊
握手開始于客戶端發送C0、C1塊。服務器收到C0或C1后發送S0和S1。
當客戶端收齊S0和S1后,開始發送C2。當服務器收齊C0和C1后,開始發送S2。
當客戶端和服務器分別收到S2和C2后,握手完成。
理論上來講只要滿足以上條件,如何安排6個Message的順序都是可以的,但實際實現中為了在保證握手的身份驗證功能的基礎上盡量減少通信的次數,一般的發送順序是這樣的:
Client發送C0+C1到Sever
Server發送S0+S1+S2到Client
Client發送C2到Server,握手完成
建立網絡連接(NetConnection)
客戶端發送命令消息中的“連接”(connect)到服務器,請求與一個服務應用實例建立連接。
服務器接收到連接命令消息后,發送確認窗口大小(Window Acknowledgement Size)協議消息到客戶端,同時連接到連接命令中提到的應用程序。
服務器發送設置帶寬(Set Peer Bandwitdh)協議消息到客戶端。
客戶端處理設置帶寬協議消息后,發送確認窗口大小(Window Acknowledgement Size)協議消息到服務器端。
服務器發送用戶控制消息中的“流開始”(Stream Begin)消息到客戶端。
服務器發送命令消息中的“結果”(_result),通知客戶端連接的狀態。
客戶端在收到服務器發來的消息后,返回確認窗口大小,此時網絡連接創建完成。
服務器在收到客戶端發送的連接請求后發送如下信息:
主要是告訴客戶端確認窗口大小,設置節點帶寬,然后服務器把“連接”連接到指定的應用并返回結果,“網絡連接成功”。并且返回流開始的的消息(Stream Begin 0)。
建立網絡流(NetStream)
客戶端發送命令消息中的“創建流”(createStream)命令到服務器端。
服務器端接收到“創建流”命令后,發送命令消息中的“結果”(_result),通知客戶端流的狀態。
推流流程
客戶端發送publish推流指令。
服務器發送用戶控制消息中的“流開始”(Stream Begin)消息到客戶端。
客戶端發送元數據(分辨率、幀率、音頻采樣率、音頻碼率等等)。
客戶端發送音頻數據。
客戶端發送服務器發送設置塊大小(ChunkSize)協議消息。
服務器發送命令消息中的“結果”(_result),通知客戶端推送的狀態。
客戶端收到后,發送視頻數據直到結束。
播流流程
客戶端發送命令消息中的“播放”(play)命令到服務器。
接收到播放命令后,服務器發送設置塊大小(ChunkSize)協議消息。
服務器發送用戶控制消息中的“streambegin”,告知客戶端流ID。
播放命令成功的話,服務器發送命令消息中的“響應狀態” NetStream.Play.Start & NetStream.Play.reset,告知客戶端“播放”命令執行成功。
在此之后服務器發送客戶端要播放的音頻和視頻數據。
五、直播中的用戶交互
對于直播中的用戶交互大致可以分為:
送禮物
發表評論或者彈幕
對于送禮物,在 H5 端可以利用 DOM 和 CSS3 實現送禮物邏輯和一些特殊的禮物動畫,實現技術難點不大。
對于彈幕來說,要稍微復雜一些,可能需要關注以下幾點:
彈幕實時性,可以利用 webscoket 來實時發送和接收新的彈幕并渲染出來。
對于不支持 webscoket 的瀏覽器來說,只能降級為長輪詢或者前端定時器發送請求來獲取實時彈幕。
彈幕渲染時的動畫和碰撞檢測(即彈幕不重疊)等等
Html5直播聊天室組件
該組件主要適用于基于Html5的web 大群互動直播場景。具備如下特點:
1)支持匿名身份入群,粉絲與主播進行親密互動
2)支持多人聊天,主播同一個帳號多標簽頁收發消息,粉絲再多也不用愁
3)支持多種聊天方式,文本,表情,紅包,點贊,想怎么互動就怎么互動
4)支持不同優先級消息的頻率控制,一鍵在手,權利盡在掌握中
5)對互動直播場景進行了專門的優化,參與人數多,消息量再大也能從容應對
前端技術點
秒開
時延
流暢
清晰度
六、總結
目前較為成熟的直播產品,大致都是以 Server 端、 H5直播前端 和 Native(Android,iOS)搭配實現直播。
主要從android客戶端出發,從最初的錄制視頻到客戶端觀看直播的整個流程,給出了各個技術點的概要和解決方案,從0到1完成了簡單的直播實現。從0到1易,從1到100還有更多的技術細節有待研究。
來自:http://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=2653578065&idx=1&sn=1da088b11c797d2be7b5f7afb8f056bb&chksm=84b3b156b3c438401715dc40f7791010b11050983a67fa533a4b559cb67ea6d0ce1996970481&scene=0