media-soup信令与代码流程分析

这篇文章是对mediasoup代码分析的一个总结,总结的相对简单,仅是对学习过程的一个记录,更详细的介绍请参考文末参考文章的介绍

总体框架

mediasoup总体的架构分为两个层次,nodejs层和C++层。

nodejs负责信令处理和房间管理,信令部分主要是入会、离会、SDP协商、连接通道建立等,房间管理nodejs是用的protoo,不熟悉的朋友墙裂建议阅读下protoo,protoo已经为我们实现了room、peer的建立、管理等操作,还可以在peer上注册自定义事件,mediasoup很多信令(join、createWebrtcTransport、produce)都是建立在peer上注册事件,理解protoo框架是理解信令流程的基础。

nodejs和worker(C++)之间是主进程和子进程的关系,两者直接通过pipe的方式进行通信,通信协议为json,所有的通信指令定义均在ChannelRequest.cpp中定义

整体的交互流程是,client与server先通过createWebrtcTransport进行sdp协商,协商好音视频传输通道,后续的音视频传输均是在这个通道上进行,真正的音视频rtp均是发送给worker,和nodejs层没有关系

信令流程

connectionrequest
    getOrCreateRoom
        创建protoo.room
        mediasoupWorker.createRouter-->触发c++层面创建router,可以将router理解为一个room
        mediasoupRouter.createAudioLevelObserver--->触发c++层面创建AudioLevelObserver
            Router::HandleRequest
                在构造函数中会创建定时器timer,AudioLevelObserver会定期从producer中的rtp包中获取音量信息,
                获取完音量信息后,会定期向应用层上报音量信息
                关键函数有:AudioLevelObserver::ReceiveRtpPacket、AudioLevelObserver::Update()
    room.handleProtooConnection
        创建protoo peer
        注册peer request和close事件,后续所有事件都会触发peer request相对应的回调函数进行处理
        在request中,有重要的getRouterRtpCapabilities、createWebRtcTransport、connectWebRtcTransport、join、produce等事件
    router.createDirectTransport--和bot相关
    transport.produceData--和bot相关 
peer.getRouterRtpCapabilities
peer.createWebRtcTransport(收)
    router.createWebRtcTransport--生成server的sdp信息返回给client
        创建子类webrtctransport对象,同时创建基类构造函数,设定定时器,此定时器用于周期发送SR和RR
        Transport::OnTimer、Transport::OnTimer
        WebRtcTransport::SendRtcpCompoundPacket
        
        在WebRtcTransport构造函数中,创建对应的监听socket,监听ip是nodejs传递过来的,port随机选择,创建对应的candidate,用于后续ice协商
        创建ice server,传递ice-ufrag和ice-pwd用于后续的身份校验
        创建dtls transport对象
        ice和dtle会整理为服务的sdp,返回给client
    transport.enableTraceEvent
        c++层面Transport::EmitTraceEventBweType,收集带宽估计相关数据,上报到nodejs,
        然后nodejs再通过peer.notify的downlinkBwe事件,将信息发送给client
    transport.setMaxIncomingBitrate
        为带宽估计设置接收的最大码率
peer.createWebRtcTransport(发)
    router.createWebRtcTransport
    transport.enableTraceEvent
    transport.setMaxIncomingBitrate
    
peer.join
    在nodejs层面做的事情
    1.为之前已经入会peer的produce创建当前即将入会peer的对应的consumer,注意此处是为每个product都会创建对应的consumer,包括不同的音频和视频produce
    2.每创建一个consume,都需要向客户端发送newConsumer消息
    3.同时向其它之前已经入会的peer发送newPeer消息
    nodejs--->c++
    1.transport.consume,nodejs通知c++创建consumer,注意每个consumer都会通知创建
        根据consumer的类型(SIMPLE、SIMULCAST、SVC、PIPE)创建对应的consume对象,
        创建rtpstream,用于发送rtp包
        通知router,建立consumer和producer映射关系
        创建tccClient,用于带宽估计
    2.consumer.resume,nodejs通知c++启动媒体流的传输
        SimpleConsumer::RequestKeyFrame()--->Transport::OnConsumerKeyFrameRequested-->Router::OnTransportConsumerKeyFrameRequested
        ---->RtpStreamRecv::RequestKeyFrame()-->OnRtpStreamSendRtcpPacket,通过fir或pli索要关键帧
    
peer.connectWebRtcTransport--大致流程应该是搞ssl握手协商的
    transport.connect
        get dtlsRemoteFingerprint
        get dtlsRemoteRole
        WebRtcTransport::MayRunDtlsTransport
            DtlsTransport::Run
                CLIENT
                    SSL_do_handshake
                    SendPendingOutgoingDtlsData
                SERVER
                    SSL_set_accept_state
                    SSL_do_handshake
peer.connectWebRtcTransport
    transport.connect

peer.produce(音频)
    transport.produce--c++层面创建produce
        发送端创建音频producer,在request上会带上客户端的rtpMapping、rtpParameters
        rtpObserver.addProducer建立producer到AudioLevelObserver映射
        创建Producer对象后,通过OnTransportNewProducer()函数告诉Router有Producer创建。
        创建tccServer,用于带宽估计
    为其它已经入会peer创建对应当前producer的consumer,这个流程和上面join时创建consumer是一样的
peer.produce(视频)
    同音频
peer.produceData
    transport.produceData
peer.produceData
    transport.produceData
    transport.consumeData


<注>下面这些consumer的事件都是nodejs和c++之间的内部事件,不是client主动发起的,都是由join或produce事件驱动而来
transport.consume
创建接收端的音频consumer

transport.consume
创建接收端的视频consumer
    Transport::HandleRequest--创建consumer对象
    Router::OnTransportNewConsumer--通知router,建立produce和consumer的映射关系
    
consumer.resume
启动音频流的传输    
consumer.resume    
启动视频流的传输

    
<注>,这里面transport是2个,一个用于发送,一个用于接收,但是produce或consume是多个,取决于发送几个音视频流,接收几个音视频流
<注>, mediasoup中的所有数据全部都需要加密,普通文本信息通过DTLS加密,而音视频数据通过libsrtp加密。

在这里插入图片描述

 收媒体包代码流程

UdpSocket::UserOnUdpDatagramReceived
    WebRtcTransport::OnUdpSocketPacketReceived                                
        WebRtcTransport::OnPacketReceived,根据数据包类型,分别进行不同的处理
            OnStunDataReceived
                IceServer::ProcessStunPacket
            OnRtcpDataReceived
                Transport::ReceiveRtcpPacket
                    Transport::HandleRtcpPacket
                        --由此看出mediasoup支持的RTCP报文有:RR、SR、SDES、BYE、XR、PSFB、RTPFB,
                        --其中PSFB包括PLI、FIR、AFB,
                        --其中AFB报文是WebRTC自己扩展的报文,用于remb算法;
                        --RTPFB又包括NACK和TCC,其中TCC报文是WebRTC自己扩展的报文,用于google TCC算法
                        rr--送到对应的consumer处理
                        sr--送到对应的producer处理
                        pli--
                            SimpleConsumer::ReceiveKeyFrameRequest
                                RtpStreamSend::ReceiveKeyFrameRequest,统计计数+1
                                SimpleConsumer::RequestKeyFrame()--通过transport--router--找到对应的producer,向producer发送请求关键帧请求
                                    Transport::OnConsumerKeyFrameRequested
                                        Router::OnTransportConsumerKeyFrameRequested
                                            Producer::RequestKeyFrame
                        nack--
                            SimpleConsumer::ReceiveNack
                                RtpStreamSend::ReceiveNack
                                    SimpleConsumer::OnRtpStreamRetransmitRtpPacket    --先解析出NACK请求中的RTP序号,
                                                                                    --然后从缓存中找出所有需要重传的RTP包。
                                                                                    --将找出的所有重传RTP包,通过consumer将这些RTP再次发送给客户端。
                                        Transport::OnConsumerRetransmitRtpPacket
                                            WebRtcTransport::SendRtpPacket
                                
                        

            OnRtpDataReceived--对srtp进行解密,将二进制字节流data解析成标准rtp packet,将rtp packet传递给基类transport
                Transport::ReceiveRtpPacket
                    Producer::ReceiveRtpPacket
                        Transport::OnProducerRtpPacketReceived
                            Router::OnTransportProducerRtpPacketReceived
                                --rtp传递给router,由router进行路由,传递给对应的consumer
                                --调用对应的音量观察者,对音量进行统计并上报应用层
                                SimpleConsumer::SendRtpPacket
                                    Transport::OnConsumerSendRtpPacket
                                        WebRtcTransport::SendRtpPacket--对数据进行加密,加密完通过ice server将包发送出去
                    
            OnDtlsDataReceived
                DtlsTransport::ProcessDtlsData
                --收到的DTLS数据包,可能是握手数据包,也可能是Sctp数据包。
                --如果是后者,将数据写入BIO后,让dtls解密接收到的数据,
                --然后通过SSL_read()获取解密后的数据,最后通过OnDtlsTransportApplicationDataReceived函数将解密后的数据送至WebRtcTransport。
                    WebRtcTransport::OnDtlsTransportApplicationDataReceived
                        Transport::ReceiveSctpData
                            SctpAssociation::ProcessSctpData

                
            
            
            
发媒体包代码流程            
WebRtcTransport::SendRtpPacket            
    this->iceServer->GetSelectedTuple()->Send(data, len, cb);------>TransportTuple::Send

信令收包代码流程:
Worker::OnChannelRequest            

信令发包代码:
ChannelRequest::Accept

在这里插入图片描述

参考文章:

protoo

mediasoup源码分析-初始化、建立连接及媒体数据的处理流程_大话音视频的博客-CSDN博客_mediasoup 源码分析mediasoup流程图_wzw88486969的博客-CSDN博客

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
要在 mediasoup-demo-android-master 中添加 flexfec 代码,您可以按照以下步骤进行: 1. 在 mediasoup-client-android 库中添加 flexfec 相关的代码。具体来说,需要修改 mediasoup-client-android 库中的 webrtc 相关代码,以支持 flexfec。这个过程比较复杂,需要有一定的开发经验和技能。 2. 将修改后的 mediasoup-client-android 库作为依赖项引入 mediasoup-demo-android-master 应用中。在 mediasoup-demo-android-master 的 build.gradle 文件中添加以下代码: ``` dependencies { implementation project(':mediasoup-client-android') } ``` 3. 在代码中使用新的 mediasoup-client-android 库中的 flexfec 相关的 API。具体来说,您需要在 mediasoup-demo-android-master 应用中的 PeerConnectionManager 类中添加以下代码: ``` private void enableFlexfec() { PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); options.disableEncryption = true; options.disableNetworkMonitor = true; options.enableDtlsSrtp = true; options.useMediaTransport = true; options.enableRtpDataChannel = true; options.flexfecEnabled = true; // enable flexfec factory = PeerConnectionFactory.builder() .setOptions(options) .createPeerConnectionFactory(); } ``` 这个方法将启用 flexfec,您可以将其调用添加到合适的位置。 4. 在 mediasoup-demo-android-master 应用中添加 flexfec 相关的 UI。这个过程包括添加一个开关按钮,以启用或禁用 flexfec,以及在界面上显示 flexfec 相关的统计信息。具体来说,您需要在 mediasoup-demo-android-master 应用中的 CallActivity 类中添加以下代码: ``` private void updateFlexfecEnabled(boolean enabled) { peerConnectionManager.setFlexfecEnabled(enabled); } private void showFlexfecStats() { // show flexfec stats } ``` 这些方法将分别处理开关按钮和统计信息的显示。 需要注意的是,上述步骤需要一定的开发经验和技能。如果您不熟悉 Android 开发和 WebRTC 技术,建议先学习相关知识再进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值