1欧芽、先播放后推流
痛點(diǎn):推流成功前不能提前播放
-
場(chǎng)景介紹:
有些及時(shí)推流的場(chǎng)景莉掂,存在推流和播放同時(shí)發(fā)生的場(chǎng)景,這種場(chǎng)景一般是一對(duì)一的千扔,譬如說基于rtmp推流的行車記錄儀憎妙,用戶在調(diào)閱車載攝像頭視頻的,下發(fā)推流命令給設(shè)備時(shí)昏鹃,同時(shí)開始播放視頻,如果播放請(qǐng)求先于推流到達(dá)流媒體服務(wù)器诀诊,那么流媒體服務(wù)器通常會(huì)立即返回流未找到的錯(cuò)誤洞渤,為了解決這個(gè)問題,一般的解決方案是属瓣,通過設(shè)備確認(rèn)推流成功再開啟播放载迄,但是這樣往往會(huì)增加視頻打開延時(shí),拉低用戶體驗(yàn)抡蛙。zlmediakit針對(duì)此場(chǎng)景作出特別優(yōu)化护昧,可以在流不存在時(shí),先不回復(fù)播放器粗截,等推流成功后再返回播放成功惋耙,如果超時(shí)時(shí)間內(nèi),推流還不上線,那么再返回播放流不存在錯(cuò)誤绽榛,通過配置文件可以修改此延時(shí):
[general] #播放最多等待時(shí)間湿酸,單位毫秒 #播放在播放某個(gè)流時(shí),如果該流不存在灭美, #ZLMediaKit會(huì)最多讓播放器等待maxStreamWaitMS毫秒 #如果在這個(gè)時(shí)間內(nèi)推溃,該流注冊(cè)成功,那么會(huì)立即返回播放器播放成功 #否則返回播放器未找到該流届腐,該機(jī)制的目的是可以先播放再推流 maxStreamWaitMS=15000
提示: 此功能同樣適用于拉流铁坎,通過該功能可以實(shí)現(xiàn)按需推拉流。
2犁苏、無人觀看事件
痛點(diǎn): 推流無人觀看時(shí)白白浪費(fèi)流量
-
場(chǎng)景介紹:
在一些物聯(lián)網(wǎng)應(yīng)用場(chǎng)景硬萍,設(shè)備推流給服務(wù)端,用戶通過app查看設(shè)備視頻傀顾,當(dāng)用戶關(guān)閉app時(shí)襟铭,設(shè)備應(yīng)該停止推流以節(jié)省流量。為了實(shí)現(xiàn)該功能短曾,一般的解決方案是播放端通過發(fā)送心跳維持設(shè)備推流寒砖,但是這樣往往存在狀態(tài)的不確定性,以及增加系統(tǒng)復(fù)雜度(想想app嫉拐、web哩都、小程序端同時(shí)維持推流心跳的場(chǎng)景)。針對(duì)此種場(chǎng)景婉徘,zlmediakit提供播放用戶統(tǒng)計(jì)功能漠嵌,在觀看數(shù)為0時(shí)會(huì)觸發(fā)無人觀看事件,用戶通過接收zlmediakit的 hook(http請(qǐng)求)盖呼,可以返回是否讓zlmediakit關(guān)閉該推流(或拉流)儒鹿,hook地址配置文件為:
[hook] #是否啟用hook事件,啟用后几晤,推拉流都將進(jìn)行鑒權(quán) enable=1 #無人觀看流事件约炎,通過該事件,可以選擇是否關(guān)閉無人觀看的流蟹瘾。配合general.streamNoneReaderDelayMS選項(xiàng)一起使用 on_stream_none_reader=https://127.0.0.1/index/hook/on_stream_none_reader
提示: hook介紹地址
3圾浅、流未找到事件
痛點(diǎn): 我們只需對(duì)外提供播放url,而不是其他憾朴!
-
場(chǎng)景介紹:
通常而言狸捕,我們通過播放url來分發(fā)視頻內(nèi)容,但是這些視頻內(nèi)容是及時(shí)生成的众雷,在無人播放時(shí)灸拍,它并不存在(不存在推流或拉流代理)做祝。這種場(chǎng)景下,通常的做法是用戶需要限制客戶端株搔,因?yàn)樘峁┑牟皇遣シ舥rl剖淀,而是獲取url的api,用戶先獲取播放url用于觸發(fā)設(shè)備推流纤房,然后才能播放纵隔,這種方式通常而言比較繁瑣,需要特定的播放前邏輯炮姨,限制了一些應(yīng)用場(chǎng)景捌刮。zlmediakit提供流未找到事件,可以匯報(bào)給你的業(yè)務(wù)服務(wù)器舒岸,告知流不存在绅作,這個(gè)時(shí)候,你可以再從容控制設(shè)備開始推流蛾派,或者讓zlmediakit開始拉流代理俄认,hook地址配置文件為:
[hook] #是否啟用hook事件,啟用后洪乍,推拉流都將進(jìn)行鑒權(quán) enable=1 #播放時(shí)眯杏,未找到流事件,通過配合hook.on_stream_none_reader事件可以完成按需拉流 on_stream_not_found=https://127.0.0.1/index/hook/on_stream_not_found
提示: hook介紹地址
4壳澳、斷連續(xù)推
痛點(diǎn):推流斷開岂贩,推流器重連了,導(dǎo)致播放器都全部斷開了巷波!
-
場(chǎng)景介紹:
一般推流器斷開萎津,服務(wù)器處理播放器的邏輯有這幾種,一種是立即斷開所有播放這個(gè)流的播放器抹镊,同時(shí)銷毀推流器锉屈、播放器對(duì)象以便節(jié)省資源,這也是zlmediakit的默認(rèn)做法垮耳。另外一種是以srs為代表颈渊,推流器斷開后,基本什么也不做氨菇,不回收推流器開辟的資源儡炼,也不斷開播放器(而是讓播放器主動(dòng)超時(shí)斷開)妓湘。
srs這種處理方式有個(gè)好處查蓉,就是推流器重新推流后,播放器可以接著播放榜贴,用戶體驗(yàn)比較好豌研。壞處就是資源不能及時(shí)回收妹田,如果有惡意鏈接不主動(dòng)及時(shí)超時(shí)斷開,可能會(huì)消耗服務(wù)器大量的文件描述符資源鹃共,同時(shí)由于推流器創(chuàng)建的媒體源資源無法主動(dòng)釋放鬼佣,當(dāng)創(chuàng)建很多個(gè)推流時(shí),內(nèi)存占用不能及時(shí)降低霜浴。
zlmediakit現(xiàn)在針對(duì)這種場(chǎng)景晶衷,新增支持?jǐn)噙B續(xù)推功能,解決了推流重連導(dǎo)致播放器斷開的問題阴孟,也解決了資源無法及時(shí)回收的弊端晌纫,做法是,在推流器斷開時(shí)永丝,延時(shí)銷毀媒體源資源對(duì)象(同時(shí)延時(shí)斷開播放器)锹漱,當(dāng)推流器再次推流時(shí),復(fù)用該資源對(duì)象慕嚷,播放器可以接著觀看視頻哥牍;如果超時(shí)后,推流器未上線喝检,那么再斷開播放器并回收所有資源嗅辣。超時(shí)延時(shí)配置文件為:
[general] #推流斷開后可以在超時(shí)時(shí)間內(nèi)重新連接上繼續(xù)推流,這樣播放器會(huì)接著播放蛇耀。 #置0關(guān)閉此特性(推流斷開會(huì)導(dǎo)致立即斷開播放器) #此參數(shù)不應(yīng)大于播放器超時(shí)時(shí)間 continue_push_ms=15000
-
實(shí)現(xiàn)代碼片段:
void RtmpSession::onError(const SockException& err) { //省略無關(guān)代碼 GET_CONFIG(uint32_t, continue_push_ms, General::kContinuePushMS); if (_push_src && continue_push_ms) { //取消推流對(duì)象所有權(quán) _push_src_ownership = nullptr; auto push_src = std::move(_push_src); //延時(shí)若干秒再銷毀對(duì)象(注銷流, 同時(shí)觸發(fā)斷開所有播放器操作) getPoller()->doDelayTask(continue_push_ms, [push_src]() { return 0; }); } } void RtmpSession::onCmd_publish(AMFDecoder &dec) { //省略大量無關(guān)代碼 auto src = MediaSource::find(RTMP_SCHEMA, _media_info._vhost, _media_info._app, _media_info._streamid); while (src) { //嘗試斷連后繼續(xù)推流 auto rtmp_src = dynamic_pointer_cast<RtmpMediaSourceImp>(src); if (!rtmp_src) { //源不是rtmp推流產(chǎn)生的 break; } auto ownership = rtmp_src->getOwnership(); if (!ownership) { //獲取推流源所有權(quán)失敗 break; } //復(fù)用之前推流資源對(duì)象 _push_src = std::move(rtmp_src); //持有對(duì)象所有權(quán) _push_src_ownership = std::move(ownership); break; } //省略大量無關(guān)代碼 }
提示:斷連續(xù)推功能支持rtsp/rtmp/webrtc推流辩诞。
5、集群部署
痛點(diǎn): 溯源方式單一纺涤,邊沿服務(wù)器不能使用HLS译暂。
-
場(chǎng)景介紹:
一般流媒體集群實(shí)現(xiàn)方式采用溯源方式實(shí)現(xiàn),服務(wù)器分為源站和邊沿站撩炊。源站一般用于接收推流外永,它一般不直接承載用戶的播放請(qǐng)求,而是通過邊沿服務(wù)器向其拉流同時(shí)分發(fā)給播放器拧咳,通過該模式可以支持海量的用戶播放請(qǐng)求伯顶。srs很早之前已經(jīng)通過配置文件的方式支持該功能,由于zlmediakit比較早也提供按需拉流的功能骆膝,本質(zhì)上也支持溯源模式的集群祭衩,不過用戶需要對(duì)接hook和api,開發(fā)門檻比較高阅签,所以最近zlmediakit也支持了通過配置文件的方式來實(shí)現(xiàn)集群模式掐暮,配置文件如下:
[cluster] #設(shè)置源站拉流url模板, 格式跟printf類似,第一個(gè)%s指定app,第二個(gè)%s指定stream_id, #開啟集群模式后政钟,on_stream_not_found和on_stream_none_reader hook將無效. #溯源模式支持以下類型: #rtmp方式: rtmp://127.0.0.1:1935/%s/%s #rtsp方式: rtsp://127.0.0.1:554/%s/%s #hls方式: http://127.0.0.1:80/%s/%s/hls.m3u8 #http-ts方式: http://127.0.0.1:80/%s/%s.live.ts #支持多個(gè)源站路克,不同源站通過分號(hào)(;)分隔 origin_url= #溯源總超時(shí)時(shí)長(zhǎng)樟结,單位秒,float型精算;假如源站有3個(gè)瓢宦,那么單次溯源超時(shí)時(shí)間為timeout_sec除以3 #單次溯源超時(shí)時(shí)間不要超過general.maxStreamWaitMS配置 timeout_sec=15
zlmediakit的溯源方式支持rtsp/rtmp/hls/http-ts(http-flv的方式暫未開放), 方式多樣豐富灰羽,同時(shí)源站不分主備驮履,采用round robin方式來實(shí)現(xiàn)源站的負(fù)載均衡。需要指出的是廉嚼,由于zlmediakit很早就支持hls的按需拉流功能疲吸,所以zlmediakit的邊沿站也支持hls協(xié)議(其實(shí)支持zlmediakit任意支持的協(xié)議),這點(diǎn)是srs不具備的前鹅。
另外需要指出的是摘悴,由于zlmediakit同時(shí)支持rtsp和webrtc,而它們兩者都是基于rtp的舰绘,在zlmediakit內(nèi)部蹂喻,無須轉(zhuǎn)協(xié)議簡(jiǎn)單處理后就可互聯(lián)互通,所以使用zlmediakit來做大規(guī)模的webrtc低延時(shí)直播已經(jīng)成為可能捂寿;相較于傳統(tǒng)的基于rtmp的cdn口四,rtsp更適合作為webrtc的cdn基礎(chǔ)傳輸協(xié)議,開發(fā)者不需要處理繁瑣的解復(fù)用復(fù)用邏輯秦陋,即可平滑的實(shí)現(xiàn)rtsp與webrtc的互轉(zhuǎn)蔓彩。
6、WebRTC單端口驳概、多線程赤嚼、支持連接遷移
痛點(diǎn):支持多線程的webrtc服務(wù)器不支持單端口,支持單端口的不支持多線程(同時(shí)可能不支持鏈接遷移)
-
場(chǎng)景介紹:
由于webrtc傳輸是基于udp協(xié)議的顺又,傳統(tǒng)的webrtc服務(wù)器都是多端口模式更卒,譬如janus/mediasoup。這給部署和管理帶來極大痛苦,而且由于端口個(gè)數(shù)有限(理論上限6萬多)稚照,每個(gè)webrtc客戶端要占用1至4個(gè)端口蹂空,受限于端口數(shù)量,一臺(tái)webrtc服務(wù)器最多可以承載1~6萬左右的客戶端數(shù)果录。
而支持單端口的webrtc服務(wù)器(譬如srs)上枕,又不支持多線程;由于webrtc計(jì)算復(fù)雜度(加解密)遠(yuǎn)大于直播弱恒,其性能跟直播比有數(shù)量級(jí)的差距辨萍,所以往往單線程在webrtc的應(yīng)用場(chǎng)景已經(jīng)力不從心。
zlmediakit針對(duì)這些痛點(diǎn)斤彼,提出了最佳解決方案:
- 支持單udp端口部署分瘦,一個(gè)udp端口承載所有客戶端。
- 單udp端口支持多線程琉苇,單端口多次bind/connect方式實(shí)現(xiàn)一個(gè)客戶端對(duì)應(yīng)一個(gè)fd嘲玫,fd均勻分配到不同線程。
- 用戶網(wǎng)絡(luò)遷移時(shí)(譬如wifi切換為4G)并扇,通過stun包鎖定用戶去团,實(shí)現(xiàn)無感知的連接遷移,用戶體驗(yàn)不中斷穷蛹。
以上3個(gè)特性都同時(shí)具備的土陪,目前在開源界唯zlmediakit一家。
提示: 關(guān)于怎么解決webrtc單端口連接遷移和多線程連接遷移時(shí)線程安全問題的請(qǐng)觀看該視頻