制與帶寬估計(jì)實(shí)戰(zhàn))
做流媒體自建服務(wù)這么長(zhǎng)時(shí)間對(duì)接mediasoup的時(shí)候simulcast和svc這兩個(gè)詞幾乎天天見(jiàn)。但說(shuō)句實(shí)話(huà)它們本身不難理解難的是搞明白它們?cè)趍ediasoup里面到底怎么流轉(zhuǎn)、怎么選路、怎么和帶寬估計(jì)配合。如果你也卡在這一塊這篇文章應(yīng)該能幫你把這塊拼圖補(bǔ)上。這其實(shí)是我們流媒體學(xué)習(xí)之路系列的第7篇前面聊過(guò)mediasoup的基礎(chǔ)架構(gòu)、Router/Transport/PipeTransport這些核心概念也梳理過(guò)RTP和RTCP的調(diào)協(xié)細(xì)節(jié)。這次我把simulcast和svc放在一起講是因?yàn)樗鼈冊(cè)赟FU場(chǎng)景里解決的是同一個(gè)問(wèn)題網(wǎng)絡(luò)帶寬不均衡時(shí)怎么給不同的接收端分發(fā)不同質(zhì)量的視頻流。但實(shí)現(xiàn)思路完全不同踩坑姿勢(shì)也完全不一樣。1. simulcast與svc兩種不同的視頻分層思路1.1 simulcast多路獨(dú)立編碼接收端按需挑一路simulcast翻譯過(guò)來(lái)叫“聯(lián)播”本質(zhì)上是發(fā)送端同時(shí)編碼產(chǎn)生多路分辨率、碼率、幀率都不相同的視頻流每一路都是獨(dú)立編碼、可單獨(dú)解碼的完整視頻流。比如一個(gè)1080p的信號(hào)源可以先出三層1080p高層、720p中層、360p低層然后同時(shí)往SFU推這三路。在WebRTC和mediasoup里這三路流通過(guò)不同的SSRC來(lái)區(qū)分同時(shí)通過(guò)RTP擴(kuò)展頭里的ridRTP Stream ID字段作為每路流的“身份證”。接收端想看清楚一點(diǎn)就問(wèn)SFU要高層網(wǎng)絡(luò)不好就問(wèn)SFU要低層切換閾值由應(yīng)用層決定。SFU不做任何轉(zhuǎn)碼只是按需轉(zhuǎn)發(fā)其中的某一層。這樣做的優(yōu)勢(shì)非常明顯SFU不需要轉(zhuǎn)碼延遲低、CPU消耗少。各層之間的質(zhì)量差別很穩(wěn)定高層清晰低層流暢。但它也有一個(gè)先天短板——帶寬利用效率低。因?yàn)榘l(fā)送端要同時(shí)編碼并上推多路流實(shí)際上行帶寬是“各層碼率之和”而不是單一編碼一路。如果在1對(duì)1通話(huà)場(chǎng)景里接收端只會(huì)用到其中一路其他層完全是白白浪費(fèi)。所以業(yè)內(nèi)才有“simulcast費(fèi)上行帶寬”這個(gè)說(shuō)法。1.2 svc一層基礎(chǔ)層疊加增強(qiáng)層按需丟棄部分包SVCScalable Video Coding可伸縮視頻編碼換了一種思路只編碼一路視頻流但這路流內(nèi)部天然分層級(jí)。最低層通常叫基礎(chǔ)層base layer只有它才能獨(dú)立解碼圖像質(zhì)量最低、分辨率最低、幀率也最低。在基礎(chǔ)層之上還有若干增強(qiáng)層比如空間增強(qiáng)層可以拉高分辨率時(shí)間增強(qiáng)層可以補(bǔ)幀率質(zhì)量增強(qiáng)層可以降量化步長(zhǎng)提升畫(huà)質(zhì)。SVC在RTP傳輸中的做法是整條流仍然只有一個(gè)SSRC和一路RTP包但每個(gè)包通過(guò)SVC規(guī)范里定義的RTP擴(kuò)展頭比如時(shí)間層的tsid、空間層的tlid來(lái)標(biāo)識(shí)自己屬于哪個(gè)層。接收端或SFU拿到包之后可以按層級(jí)做篩選丟棄。比如說(shuō)當(dāng)前網(wǎng)絡(luò)只能撐住基礎(chǔ)層SFU就把所有增強(qiáng)層的包全部丟掉只轉(zhuǎn)發(fā)基礎(chǔ)層的包接收端照樣能解碼出視頻只是分辨率低、畫(huà)質(zhì)差點(diǎn)。SVC最大的優(yōu)點(diǎn)是帶寬利用率高因?yàn)榘l(fā)送端只需要編碼一條流增強(qiáng)層的碼率在必要時(shí)候才真正被轉(zhuǎn)發(fā)出去不會(huì)像simulcast那樣早早上行帶寬全都占滿(mǎn)。它的主要缺點(diǎn)也很現(xiàn)實(shí)編碼器復(fù)雜度高CPU占用比simulcast高不少而且終端支持不統(tǒng)一比如某些客戶(hù)端對(duì)H.264 SVC壓根不支持VP9和AV1的SVC支持情況也因平臺(tái)而異。1.3 二者最本質(zhì)的差異空間冗余的取舍如果用生活化的方式理解simulcast像是一家餐廳同時(shí)準(zhǔn)備小份、中份、大份三個(gè)獨(dú)立菜品顧客要哪個(gè)就給哪個(gè)沒(méi)點(diǎn)的那份就白白在廚房里放著換菜速度很快。SVC像是一個(gè)多層蛋糕第一層是可以單獨(dú)吃的上面的每一層必須疊加在下面才能吃服務(wù)員只會(huì)把客人夠得到的部分端上去但蛋糕本體做得更復(fù)雜。從SFU的角度看simulcast轉(zhuǎn)發(fā)的是“獨(dú)立流”的某個(gè)分支SVC轉(zhuǎn)發(fā)的是“同一條流”中的部分包。這兩種機(jī)制在媒資系統(tǒng)里都對(duì)RTCP帶寬估計(jì)敏感但在mediasoup的具體實(shí)現(xiàn)上有非常大的區(qū)別接下去我會(huì)把底層機(jī)制展開(kāi)講。2. 深入mediasoup的simulcast與svc處理機(jī)制2.1 mediasoup怎么識(shí)別分層流mediasoup內(nèi)部設(shè)計(jì)了一套邏輯來(lái)統(tǒng)一處理simulcast和SVC。它把每一路可辨識(shí)的層抽象成“空間層”Spatial Layer和“時(shí)間層”Temporal Layer兩個(gè)維度然后用一個(gè)Layer集合來(lái)跟蹤。對(duì)于simulcast發(fā)送端上推的三路獨(dú)立視頻流在mediasoup看來(lái)就是三個(gè)空間層。每一層有自己的SSRC、獨(dú)立RTP序列號(hào)空間和獨(dú)立碼率統(tǒng)計(jì)。時(shí)間層的概念在simulcast里也存在比如VP8的動(dòng)態(tài)時(shí)間層、H.264的某些編碼器實(shí)現(xiàn)會(huì)在一路流里再做時(shí)間分層但simulcast的時(shí)間層不像SVC那么突出。對(duì)于SVCmediasoup在接收端解析RTP包里的層標(biāo)識(shí)擴(kuò)展頭把包歸入不同空間層和時(shí)間層。SVC和一個(gè)SSRC配對(duì)所有層的包都混在這一個(gè)流里mediasoup必須通過(guò)RTP頭精確區(qū)分。以VP9 SVC為例同一個(gè)SSRC的RTP包既可能有空間層0的時(shí)間層0也可能有空間層1的時(shí)間層1各自對(duì)應(yīng)不同的RTP頭擴(kuò)展字段值。mediasoup在做轉(zhuǎn)發(fā)時(shí)不是簡(jiǎn)單粗暴地把所有包都轉(zhuǎn)發(fā)給consumer而是通過(guò)consumer的targetLayer來(lái)確定當(dāng)前要轉(zhuǎn)發(fā)的空間層和時(shí)間層然后只轉(zhuǎn)發(fā)該層及其下層的包。對(duì)simulcast來(lái)說(shuō)如果consumer選了空間層2那mediasoup只轉(zhuǎn)發(fā)空間層2那條SSRC的包。對(duì)SVC來(lái)說(shuō)如果consumer選了空間層1時(shí)間層1mediasoup需要同時(shí)轉(zhuǎn)發(fā)空間層0和空間層1中不高于時(shí)間層1的包因?yàn)榭臻g層1的解碼依賴(lài)基礎(chǔ)層。2.2 RTP擴(kuò)展頭與SDP協(xié)商分層的“身份證”在這個(gè)體系里RTP擴(kuò)展頭是分層的核心標(biāo)識(shí)。mediasoup能夠正確識(shí)別simulcast和SVC完全取決于發(fā)送端是否在SDP協(xié)商階段帶上對(duì)應(yīng)的RTP擴(kuò)展頭并且在實(shí)際的RTP包里填上了正確的值。simulcast場(chǎng)景使用的擴(kuò)展頭主要是urn:ietf:params:rtp-hdrext:sdes:rid也就是我們常說(shuō)的rid擴(kuò)展頭。發(fā)送端在編碼完三層流之后在每一層的RTP包里把rid字段寫(xiě)成對(duì)應(yīng)的Stream ID。mediasoup拿到SDP時(shí)通過(guò)arid和asimulcast屬性來(lái)重建發(fā)送端的simulcast場(chǎng)景。SDP里simulcast的典型描述長(zhǎng)這樣arid:f1 send arid:f2 send arid:f3 send asimulcast:send f1;f2;f3SVC則需要借助其他擴(kuò)展頭比如VP9 SVC里tsid和tlid或者是后來(lái)標(biāo)準(zhǔn)的http://www.webrtc.org/experiments/rtp-hdrext/vp9-tl0等。SDP里同樣會(huì)通過(guò)asvc等屬性來(lái)聲明。mediasoup對(duì)這些擴(kuò)展頭的解析實(shí)現(xiàn)在自家的RtpStream和Producer里面所以如果你要自定義擴(kuò)展頭不走offer里的擴(kuò)展頭協(xié)商機(jī)制mediasoup是識(shí)別不出來(lái)的。在WebRTC的常規(guī)協(xié)商流程里SDP的offer和answer都是自動(dòng)生成的但用戶(hù)要確保編碼器設(shè)置正確。你要是配置了simulcast但沒(méi)開(kāi)啟rid那mediasoup收到的還是一路平坦的視頻流根本沒(méi)法選層。同理SVC沒(méi)帶好層標(biāo)識(shí)頭mediasoup也無(wú)法感知這是SVC。2.3 WebRTC里的Simulcast流程從瀏覽器到mediasoup正常情況下一個(gè)基于mediasoup的WebRTC應(yīng)用瀏覽器端的流轉(zhuǎn)到mediasoup的路徑是這樣的瀏覽器端先用getUserMedia拿到攝像頭流然后通過(guò)RTCPeerConnection創(chuàng)建發(fā)送端。這里的關(guān)鍵是addTransceiver或者setParameters的encodings數(shù)組數(shù)組里的每一項(xiàng)就對(duì)應(yīng)一個(gè)simulcast層。瀏覽器在本地編碼器里會(huì)嘗試生成多個(gè)編碼層并在SDP里帶著對(duì)應(yīng)的rid和simulcast聲明發(fā)出去。mediasoup收到offer之后先是調(diào)協(xié)出公用的RTP能力再根據(jù)SDP信息創(chuàng)建RtpStreamRecv解析出每層的SSRC、rid、碼率參數(shù)然后通知應(yīng)用層“這個(gè)Producer有3個(gè)空間層”。應(yīng)用層通過(guò)router.createProducer創(chuàng)建producer把對(duì)應(yīng)的rtpParameters保存下來(lái)。這個(gè)時(shí)候Consumer端來(lái)了一個(gè)接收者mediasoup會(huì)通過(guò)RTP參數(shù)協(xié)商為接收者生成一個(gè)Consumer。如果接收者網(wǎng)絡(luò)狀況好應(yīng)用層會(huì)把Consumer的targetLayer設(shè)置為空間層2如果網(wǎng)絡(luò)不佳設(shè)為空間層1或0。mediasoup收到指令后就只轉(zhuǎn)發(fā)對(duì)應(yīng)層所在SSRC的包。整個(gè)流程看起來(lái)不復(fù)雜但每一環(huán)都有很多細(xì)節(jié)要扣。比如瀏覽器端是否真的開(kāi)啟了編碼器的多路同時(shí)編碼碼率控制模式用的CBR還是VBR關(guān)鍵幀間隔多少都會(huì)直接影響后續(xù)的選層體驗(yàn)。3. 實(shí)操把simulcast跑起來(lái)3.1 Producer端配置encodings聲明三層在mediasoup中最核心的就是Producer端的encodings配置。我曾經(jīng)在一個(gè)自建流媒體服務(wù)項(xiàng)目里把1080p的視頻源做成了三層simulcast當(dāng)時(shí)用的mediasoup-client配置如下const producer await sendTransport.produce({ track, encodings: [ { maxBitrate: 1500000, scaleResolutionDownBy: 1 }, { maxBitrate: 500000, scaleResolutionDownBy: 2 }, { maxBitrate: 150000, scaleResolutionDownBy: 4 } ], codecOptions: { videoGoogleStartBitrate: 800 } });這里的scaleResolutionDownBy是mediasoup-client基于原始分辨率做等比縮放的核心參數(shù)。原始1080p第一次不縮放第二次縮小一半成540p第三次縮到270p。實(shí)際跑起來(lái)瀏覽器會(huì)開(kāi)啟三個(gè)獨(dú)立的編碼器實(shí)例同時(shí)工作輸出的三層視頻流在SDP里對(duì)應(yīng)三個(gè)SSRC、三個(gè)rid。如果你的上層應(yīng)用不是瀏覽器而是自研客戶(hù)端直接對(duì)接mediasoup那rtpParameters要自己手動(dòng)組織encodings數(shù)組里的每個(gè)對(duì)象要手動(dòng)填好rid、maxBitrate、scaleResolutionDownBy等字段。在非瀏覽器環(huán)境里還要特別注意編碼器是否支持多路并發(fā)輸出很多硬編碼器雖然支持simulcast但層數(shù)限制為2層這個(gè)時(shí)候強(qiáng)行配3層會(huì)導(dǎo)致編碼失敗。3.2 Consumer端選層與切層Consumer端在mediasoup里最簡(jiǎn)單的選層操作是直接指定空間層和時(shí)間層??蚣軐用鎚ediasoup提供了一套清晰的API比如consumer.setPreferredLayers({ spatialLayer: 1, temporalLayer: 2 })。實(shí)際使用中我們?cè)谝曨l會(huì)議場(chǎng)景里會(huì)在每個(gè)consumer上監(jiān)聽(tīng)?zhēng)捁烙?jì)事件一旦檢測(cè)到接收端下行帶寬充足就把preferredSpatialLayer提高到2讓用戶(hù)看到高清畫(huà)面帶寬吃緊時(shí)先降時(shí)間層再降空間層這樣畫(huà)面模糊但不會(huì)卡頓。在mediasoup的消費(fèi)者選項(xiàng)中也有preferredSpatialLayer和preferredTemporalLayer的初始化參數(shù)配合上面的setPreferredLayers可以在創(chuàng)建consumer時(shí)就設(shè)定默認(rèn)層。有一個(gè)關(guān)鍵點(diǎn)需要注意mediasoup的consumer選層指令是實(shí)時(shí)的但切換的生效時(shí)機(jī)取決于關(guān)鍵幀。接收端要從低層切到高層必須等高層那個(gè)SSRC產(chǎn)生一個(gè)關(guān)鍵幀才可能無(wú)損切換。所以很多生產(chǎn)級(jí)應(yīng)用會(huì)讓編碼器在simulcast三路上周期性產(chǎn)生關(guān)鍵幀避免切層時(shí)出現(xiàn)長(zhǎng)時(shí)間花屏。我們當(dāng)時(shí)把關(guān)鍵幀間隔設(shè)在2秒既保證帶寬不太浪費(fèi)又能快速切層。3.3 帶寬估計(jì)與選層策略的配合單純做了simulcast選層還不夠真正讓系統(tǒng)自適應(yīng)網(wǎng)絡(luò)的核心在于帶寬估計(jì)。mediasoup內(nèi)置了transport-cc帶寬估計(jì)機(jī)制它能夠在SFU側(cè)估算出每一條Transport的可用帶寬但默認(rèn)情況下它不會(huì)自動(dòng)幫你切層。切層邏輯需要應(yīng)用層自己實(shí)現(xiàn)。我在實(shí)際項(xiàng)目里是這么做的首先在mediasoup的worker里開(kāi)啟了transport-cc并且在各個(gè)consumer上監(jiān)聽(tīng)score事件。mediasoup會(huì)定期為每個(gè)consumer的層評(píng)分包括空間層分?jǐn)?shù)、時(shí)間層分?jǐn)?shù)和編碼層分?jǐn)?shù)。一旦評(píng)分明顯下降說(shuō)明當(dāng)前層碼率超出了接收端帶寬我會(huì)立刻把preferredSpatialLayer降一級(jí)再觀(guān)察評(píng)分是否恢復(fù)。這套邏輯在協(xié)議上依賴(lài)RTCP Receiver Report和Transport-CC反饋所以你們要在創(chuàng)建router的時(shí)候把enableTcp設(shè)為true同時(shí)確保rtcp配置合理。不開(kāi)啟transport-ccmediasoup照樣能跑simulcast但選層就只能靠拍腦袋了。4. simulcast還是svc我該怎么選4.1 帶寬消耗與計(jì)算對(duì)比如果要從帶寬維度做選型必須先搞清楚simulcast和SVC的碼率構(gòu)成。simulcast下發(fā)送端的實(shí)際上行帶寬大約是各層碼率之和。假設(shè)11080p高層2.5Mbps、720p中層1Mbps、360p低層300kbps那上行就是約3.8Mbps。而下行帶寬取決于接收端選中的層。要是三個(gè)人同時(shí)收高層每人都消耗2.5MbpsSFU的出口就是7.5Mbps。如果是SVC發(fā)送端編碼一條總碼率約3.5Mbps的流上行就是這個(gè)數(shù)不需要為每個(gè)層單獨(dú)付出完整碼率。下行方面如果要1080pSFU轉(zhuǎn)發(fā)全部約3.5Mbps的包如果只能收360p只需要轉(zhuǎn)發(fā)基礎(chǔ)層的幾百kbps包。同等畫(huà)質(zhì)下SVC的總碼率一般能比simulcast節(jié)省20%到40%具體消耗還得看內(nèi)容復(fù)雜度、編碼器實(shí)現(xiàn)和層間相關(guān)度。但對(duì)于包含大量會(huì)議場(chǎng)景的多人視頻simulcast的上行浪費(fèi)是繞不開(kāi)的痛。4.2 編碼復(fù)雜度與終端支持再看編碼與終端的適配。simulcast的編碼復(fù)雜度最低因?yàn)槊恳宦肪褪且淮纬R?guī)編碼多個(gè)編碼器并行工作。但編碼器數(shù)量多CPU使用率會(huì)上來(lái)。好在現(xiàn)代瀏覽器對(duì)simulcast的編碼支持已經(jīng)非常成熟主流平臺(tái)WebRTC的simulcast都穩(wěn)定。SVC起步晚目前主要在VP9和AV1上表現(xiàn)較好尤其是VP9的SVC模式在很多WebRTC引擎已經(jīng)可用。如果你用的是H.264SVC的支持就慘不忍睹了因?yàn)镠.264 SVC的profile在WebRTC和硬編碼器里基本是被冷落的。所以我做一個(gè)產(chǎn)品線(xiàn)建議如果是純WebRTC的會(huì)議場(chǎng)景優(yōu)先simulcast它生態(tài)成熟、問(wèn)題容易排查如果是直播、云轉(zhuǎn)碼或者存儲(chǔ)邊界弱化的場(chǎng)景SVC優(yōu)勢(shì)更明顯帶寬利用率高、端到端延遲低。4.3 實(shí)際項(xiàng)目里的選型建議我接手的幾個(gè)自建流媒體服務(wù)項(xiàng)目里最后都是simulcast為主力。原因很簡(jiǎn)單客戶(hù)端的兼容性最穩(wěn)編碼器不用搞復(fù)雜的層級(jí)設(shè)置開(kāi)箱即用。而SVC我更多放在一些對(duì)帶寬極其敏感的1對(duì)1通話(huà)和移動(dòng)端弱網(wǎng)場(chǎng)景里。如果你新項(xiàng)目要確定方案先從這兩個(gè)問(wèn)題出發(fā)第一你的終端設(shè)備多樣嗎是否有老平臺(tái)第二你的瓶頸在上行還是下行。如果上行帶寬寬裕但下行各異simulcast最合適。如果上行本來(lái)就不夠且客戶(hù)端都能支持VP9/AV1 SVC那SVC值得賭一把。另外mediasoup實(shí)際上支持simulcast和SVC共存你可以讓同一個(gè)router里的不同producer用不同模式但為降低排查復(fù)雜度生產(chǎn)環(huán)境建議同一類(lèi)終端統(tǒng)一切到一種模式。5. 常見(jiàn)問(wèn)題與排查技巧5.1 simulcast流“選不了層”怎么辦這是我在做mediasoup聯(lián)調(diào)時(shí)最常遇到的問(wèn)題。表現(xiàn)是producer明明跑了三層simulcast但consumer創(chuàng)建后設(shè)preferredSpatialLayer怎么都不生效或者只看到一層。排查順序一般是先看SDP。確認(rèn)offer里有沒(méi)有asimulcast:send有沒(méi)有rid聲明。如果沒(méi)有就能確定發(fā)送端根本沒(méi)有協(xié)商好simulcast。其次看mediasoup側(cè)producer的score事件看看各層評(píng)分是否都在正常輸出。如果某一層評(píng)分特別低可能是那層編碼器沒(méi)有產(chǎn)生足夠的關(guān)鍵幀或者碼率設(shè)置太低導(dǎo)致畫(huà)面靜止。還有一個(gè)容易忽略的細(xì)節(jié)simulcast的編碼器需要手動(dòng)開(kāi)啟“關(guān)鍵幀同時(shí)生成”功能。部分瀏覽器默認(rèn)只有高層會(huì)周期出關(guān)鍵幀低層只在初始時(shí)出一次。這種情況下你從高層切到低層沒(méi)問(wèn)題但從低層切回高層就會(huì)等待一個(gè)很不確定的關(guān)鍵幀周期造成切層后卡片幾秒。建議在編碼器配置里對(duì)各層設(shè)置關(guān)鍵幀間隔。5.2 SVC在mediasoup中的限制SVC要跑通除了編碼器支持mediasoup本身也要能識(shí)別層信息。在部分mediasoup版本里SVC的consumer創(chuàng)建成功不等于你可以直接選層。你會(huì)發(fā)現(xiàn)有些時(shí)候設(shè)置preferredSpatialLayer沒(méi)有反應(yīng)原因是RTP擴(kuò)展頭沒(méi)協(xié)商上比如sdes:rtp-stream-id只對(duì)simulcast的rid有效SVC得用tsid和tlid那一套擴(kuò)展頭。所以排查SVC時(shí)要重點(diǎn)看協(xié)商出的RTP capabilities里擴(kuò)展頭是否包含SVC相關(guān)的uri。如果終端和mediasoup沒(méi)達(dá)成一致那就只能當(dāng)普通單流處理沒(méi)有任何分層收益。另外記住SVC不能和simulcast在同一路producer里混用這兩個(gè)模式在SDP里是互斥的你聲明了simulcast就別想同時(shí)有SVC層標(biāo)識(shí)。5.3 切層瞬間的體驗(yàn)優(yōu)化最后分享一個(gè)切層體驗(yàn)優(yōu)化的技巧。simulcast切層最怕什么不是切不到而是切了之后糊了很久。這通常是因?yàn)榫幋a器關(guān)鍵幀在切換目標(biāo)層上過(guò)慢。我們線(xiàn)上方案是給三層同時(shí)開(kāi)啟如下編碼器選項(xiàng)videoKeyFrameInterval2同時(shí)啟動(dòng)videoKeyFrameForce邏輯在用戶(hù)主動(dòng)切層的指令到達(dá)SFU后通過(guò)信令通知瀏覽器那邊的編碼器立刻產(chǎn)生一次關(guān)鍵幀。這樣切層延遲能壓到半秒以?xún)?nèi)。還有一個(gè)小技巧是針對(duì)Consumer端的緩存在mediasoup里切層前先不要立刻丟棄當(dāng)前層的包讓接收端保持一個(gè)關(guān)鍵的緩沖周期等新層的關(guān)鍵幀到達(dá)后再做切換畫(huà)面會(huì)平滑很多。這個(gè)和播放器的追幀策略有點(diǎn)像總的思路就是“先并行后切換”。流媒體這條路學(xué)的時(shí)候覺(jué)得每個(gè)點(diǎn)都懂聯(lián)調(diào)的時(shí)候到處都是坑。simulcast和SVC是SFU里最核心的兩個(gè)武器選對(duì)場(chǎng)景、配置對(duì)參數(shù)、做好切層策略整個(gè)視頻服務(wù)的體驗(yàn)立馬不一樣。上面這些內(nèi)容都是我在實(shí)際項(xiàng)目里的經(jīng)驗(yàn)總結(jié)希望能幫你少踩幾個(gè)坑也歡迎在評(píng)論區(qū)交流你們的選型方案。