zhngs

zhngs

pion媒体数据流向

1.onTrack分析
2.媒体启动流程
3.媒体数据流向的本质
4.startRTPSenders函数
5.configureRTPReceivers函数

1.onTrack分析

pion的onTrack回调可以拿到remote track

  • PeerConnection的startReceiver和handleIncomingSSRC方法会回调onTrack
  • handleIncomingSSRC函数是用来处理未在sdp中声明的ssrc
  • startReceiver会利用sdp中解析出来的trackDetail,调用RTPReceiver的startReceive,startReceive会从dtlsTransport中拿到rtpReadStream、rtpInterceptor、rtcpReadStream、rtcpInterceptor,给RTPReceiver中的track赋值。对于rtx track,pion没有暴露给使用者,而是在函数中单独起了一个协程来读取

2.媒体启动流程

  • DtlsTransport的startSRTP会调用NewSessionSRTP和NewSessionSRTCP,并把从ice那里拿到的多路复用的socket结构传入进去

  • 最终会调用srtp包中的session.start方法,核心拿到数据的逻辑是在一个协程的for循环中,读多路复用的socket,并执行传入的session接口的decrypt方法

    go func() { defer func() { close(s.newStream) s.readStreamsLock.Lock() s.readStreamsClosed = true s.readStreamsLock.Unlock() close(s.closed) }() b := make([]byte, 8192) for { var i int i, err = s.nextConn.Read(b) if err != nil { if !errors.Is(err, io.EOF) { s.log.Error(err.Error()) } return } if err = child.decrypt(b[:i]); err != nil { s.log.Info(err.Error()) } } }()
  • decrypt方法会将新的stream通过chan传给AcceptStream函数,并最终被上层应用回调拿到stream

3.媒体数据流向的本质

在pion接收或发送媒体数据需要理解如下条件

  • 有一个可用的local-remote candidate对,stun、dtls包可以从中拿到,媒体包可以通过回调分发到上层
  • 要清楚sdp和pc的关系,sdp交换是主要是为了协商两端的媒体信息,所以一个pc对应一个local sdp和一个remote sdp
  • pc和stream的关系,一个pc对应一个stream,一个stream有多个track,对于Unified Plan,一个m line就是一个track,一个track和一个ssrc唯一对应,这里track也有可能会有重传ssrc。这里需要明确m line是可以不带track信息的,此时只有codec信息
  • pion中peerconnection的结构中有RTPTransceiver数组,一个RTPTransceiver和一个mid对应,RTPTransceiver包含一个RTPSender和RTPReceiver,两者中都有track列表。对于Unified Plan来说,一个mid只有一个track,此时RTPTRansciever实际只对应一个track;对于Plan B来说,一个mid可以有多个track,此时RTPSender和RTPReceiver中都track列表就可以起到作用
  • 正式开启媒体交互需要三个函数,pc.startRTPSenders,pc.configureRTPReceivers,startRTP。startRTPSenders的作用是配置媒体发送的数据结构,configureRTPReceivers的作用是配置媒体接收的数据结构,startRTP正式开启媒体接收流程

4.startRTPSenders函数

  • 遍历pc的所有transceiver,执行RTPSender的Send函数
  • Send函数会遍历RTPSender的trackEncodings,添加baseTrackLocalContext结构,对track字段调用Bind,并创建streamInfo字段,将writeStream字段和api的interceptor绑定

5.configureRTPReceivers函数

  • 对未在pc的transceiver的track收集起来,遍历执行pc.configureReceiver
  • 针对每一个receiver,增加tracks切片的成员