github:https://github.com/bigonelby/webrtcUml/tree/master/latest

這張圖的內(nèi)容比較多,主要涉及了:① 視頻通道建立;② 傳輸通道建立;③ VideoRtpSender;④ 核心三劍客;⑤ pipeline下游encoder;⑥ pipeline上游track;⑦ pipline應(yīng)用層
首先看看視頻通道建立。也就是VideoChannel的創(chuàng)建。之前的圖中已經(jīng)知道,webrtc中的各種channel,最核心的是BaseChannel,每個(gè)BaseChannel都有一個(gè)MediaChannel。這里談?wù)摰木褪荁aseChannel的創(chuàng)建。創(chuàng)建的時(shí)機(jī)實(shí)際上就是sdp協(xié)商時(shí),對(duì)端回送answer后,本端會(huì)將answer通過SetRemoteDescription設(shè)置給webrtc底層。在這個(gè)函數(shù)中,實(shí)際上完成了很多架構(gòu)上的初始化。這種offer / answer的處理,PeerConnection有個(gè)重要的助手專門處理這個(gè)事情,這個(gè)助手就是SdpOfferAnswerHandler,即會(huì)調(diào)用這個(gè)類的SetRemoteDescription進(jìn)行進(jìn)一步的處理。在解析sdp的過程中,如果發(fā)現(xiàn)有新的通道,則會(huì)通過ChannelManager進(jìn)行通道的創(chuàng)建,即CreateVideoChannel
再來看看傳輸通道的建立。剛才介紹了,已經(jīng)將VideoChannel創(chuàng)建出來了,這就意味著與之相關(guān)的MediaChannel自然也已經(jīng)創(chuàng)建起來了。那么數(shù)據(jù)將如何傳輸?shù)骄W(wǎng)絡(luò)呢?就是調(diào)用VideoChannel的SetRtpTransport,從而設(shè)置發(fā)送到網(wǎng)絡(luò)的rtptransport了。底層將采集數(shù)據(jù)編碼,打包,發(fā)送時(shí),最終調(diào)用到WebrtcVideoChannel的SendRtp和SendRtcp兩個(gè)方法。這兩個(gè)方法進(jìn)一步調(diào)用了network_interface_的SendPacket方法。network_interface_是如何注冊(cè)到VideoMediaChannel中的呢?就是用的接口SetInterface。由此可見,如果我們希望替換成自定義的transport,那么只要通過SetInterface,設(shè)置成自定義的network_interface_即可。對(duì)于原生的webrtc,實(shí)現(xiàn)這個(gè)接口的正是BaseChannel,因此會(huì)進(jìn)一步調(diào)用BaseChannel的方法,從而通過其成員rtp_transport_進(jìn)行進(jìn)一步的發(fā)送,即SendRtcpPacket或SendRtpPacket。這里的rtp_transport_就是通過SetRtpTransport設(shè)置的。下面我們來看看這個(gè)rtp_transport_。這個(gè)transport實(shí)際上可以通過JsepTransport得到。關(guān)于jsep(JavaScript Session Establishment Protoco)的介紹,可以參考這篇文章:https://rtcweb-wg.github.io/jsep/。webrtc中的JsepTransport,是由控制類JsepTransportController創(chuàng)建的。這個(gè)transport_controller_是PeerConnection的另一名干將。其JsepTransport創(chuàng)建的時(shí)機(jī),也是處理offer或answer的時(shí)候。在ApplyDescription_n的時(shí)候,會(huì)調(diào)用MaybeCreateJsepTransport,從而創(chuàng)建了JsepTransport
再進(jìn)一步向后分析之前,我們必須再熟悉一下三劍客:即VideoMediaChannel,WebrtcVideoChannel和VideoChannel。實(shí)際上VideoChannel是一個(gè)BaseChannel,每個(gè)BaseChannel都有一個(gè)MediaChannel,實(shí)現(xiàn)這個(gè)MediaChannel接口的,為VideoMediaChannel,WebrtcVideoChannel實(shí)現(xiàn)了VideoMediaChannel的接口。因此可以理解為VideoChannel有一個(gè)成員是WebrtcVideoChannel。為什么是MediaChannel呢?即媒體通道,顯然這個(gè)通道和媒體相關(guān),因此其職責(zé)就是接收采集的數(shù)據(jù),進(jìn)行編碼,打包,最后通過網(wǎng)絡(luò)層發(fā)送。如何通過網(wǎng)絡(luò)層發(fā)送,上面已經(jīng)介紹了,最終通過rtp_transport_。下面我們看看采集數(shù)據(jù)是如何流入到這個(gè)MediaChannel中的。
到這里就需要介紹一下VideoRtpSender了。這個(gè)類是連接采集數(shù)據(jù)和媒體通道的關(guān)鍵。不過,這個(gè)對(duì)象也不是獨(dú)立存在的,類似的,還有VideoRtpReceiver,這兩個(gè)組員統(tǒng)一歸RtpTransceiver管理,而管理RtpTransceiver的,自然也是一個(gè)Manager,就是RtpTransmissionManager,這又是PeerConnection的得力助手。應(yīng)用可以通過AddTransceiver增加新的transceiver。PeerConnection的這個(gè)方法接收一個(gè)MediaStreamTrackInterface,這是一個(gè)mediastreamtrack,這個(gè)track非常重要,實(shí)際上這個(gè)track就是數(shù)據(jù)的源頭,比如track里可以包含一個(gè)camera的采集數(shù)據(jù)。注意到MediaStreamTrackInterface本身并不是一個(gè)source,但是通過其方法kind()就可以知道他的具體類型了。比如視頻,那么他的多態(tài)子類就是VideoTrackInterface,這個(gè)VideoTrackInterface可是一個(gè)地地道道的VideoSourceInterface,也就是說這個(gè)track的本質(zhì)就是一個(gè)source。這個(gè)對(duì)后面數(shù)據(jù)流pipeline的理解非常重要。好了,我們回過頭來繼續(xù)看PeerConnection的AddTransceiver,看看究竟做了什么事情。具體的工作由rtp_manager_完成,即RtpTransmissionManager完成。首先CreateSender,CreateReceiver,接著就可以CreateAndAddTransceiver。由此可見,VideoRtpSender實(shí)際上是由RTPTransmissionManager創(chuàng)建的。VideoRtpSender重要意義在于,他起到了承上啟下的作用。左手邊是數(shù)據(jù)源,即MediaStreamTrackInterface,通過SetTrack方法綁定;右手邊是MediaChannel,通過SetMediaChannel綁定。最后通過調(diào)用WebrtcVideoChannel的SetVideoSend方法,將數(shù)據(jù)源(video track)和媒體通道(media channel)綁定到一起。
至此,我們重要可以看看數(shù)據(jù)流的整個(gè)pipeline了。首先看看pipeline下游encoder,通過WebrtcVideoChannel的SetVideoSend方法設(shè)置,這個(gè)方法實(shí)際上傳入了一個(gè)VideoSourceInterface。我們已經(jīng)知道,這個(gè)VideoSourceInterface實(shí)際上就是VideoTrack了,后面再詳細(xì)介紹。WebrtcVideoChannel進(jìn)一步通過WebRtcVideoSendStream的SetVideoSend方法,將此VideoSourceInterface設(shè)置到底層,這個(gè)指令,通過VideoSendStream,VideoStreamEncoder,最終到達(dá)了VideoSourceSinkController的SetSource。這個(gè)VideoSourceSinkController,顧名思義,是source和sink的控制器。因此管理了source和sink,并將source和sink相互綁定,數(shù)據(jù)流將會(huì)從source中流入到sink。對(duì)于VideoSourceSInkController而言,其sink_就是VideoStreamEncoder。而source就是通過SetSource接口設(shè)置下來的,即VideoTrack。這樣,通過VideoSOurceSinkController的牽線,VideoTrack中的采集數(shù)據(jù),就流到了編碼器中,從而進(jìn)行進(jìn)一步的編碼。
我們?cè)倏纯磒ipeline的上游track。之前已經(jīng)反復(fù)介紹了,傳入到WebrtcVideoChannel的source,本質(zhì)上就是VideoTrack。這個(gè)VideoTrack是通過PeerConnection的AddTransceiver方法設(shè)置進(jìn)來的,并由VideoRtpSender設(shè)置到WebrtcVideoChannel中。上層傳入的實(shí)際上是MediaStreamTrackInterface,其本身并不是VideoSourceInterface。但是根據(jù)其kind,可以判斷出具體的類型,比如video,那么我們就知道這個(gè)子類就是VideoTrackInterface,而這個(gè)就是一個(gè)VideoSourceInterface了。我們看看圖中有各種各樣的VideoSourceInterface。實(shí)際上簡單而言,就是三個(gè)對(duì)象,即VideoTrack,和其成員AdaptedVideoTrackSource,以及VideoBroadcaster。設(shè)置到底層的是VideoTrack,VideoTrack在進(jìn)行sink綁定即AddOrUpdateSink時(shí),也會(huì)通知其成員video_source_進(jìn)行相應(yīng)的sink更新,具體而言,子類就是AdaptedVideoTrackSource,而AdaptedVideoTrackSource也會(huì)將次重要事情告訴其成員broadcaster_,這是一個(gè)VideoBroadcaster,因此VideoStreamEncoder相當(dāng)于最終綁定到了這個(gè)VideoBroadcaster的sinks_下。因此采集到的,并流入到AdaptedVideoTrackSource視頻數(shù)據(jù),就會(huì)通過VideoBroadcaster流入到編碼器VideoStreamEncoder中,從而進(jìn)行編碼了
最后看看pipline應(yīng)用層。上層RTCVideoSource實(shí)現(xiàn)了RTCVideoCapturerDelegate,采集的視頻幀將會(huì)通過這個(gè)delegate,源源不斷的流入到RTCVideoSource中,RTCVideoSource進(jìn)一步將數(shù)據(jù)送給了底層類ObjCVideoTrackSource,通過其OnCapturedFrame方法,將視頻幀送入。而ObjVideoTrackSource其本質(zhì)就是一個(gè)AdaptedVideoTrackSource,因此,可以進(jìn)一步通過VideoAdapter將采集的視頻幀進(jìn)行adapter,并將adapter后的幀通過OnFrame進(jìn)一步處理,這個(gè)視頻幀由此進(jìn)入到VideoBroadcaster中,并最終流入到VideoStreamEncoder