pion学习总结:等待传出track的一般流程
Howard Yin 2021-09-02 14:20:03  WebRTC编程框架pion实操
# 先创建设置然后创建PeerConnection:
和传入连接一样的过程,见《pion学习总结:等待传入track的一般流程》
# 创建track
这一步主要是要生成一个TrackLocal子类,在里面指定你要给远端发什么东西以及怎么发。
比如在用实例学习pion - play-from-disk里面用的是pion给的样例track:
    // Create a video track
    videoTrack, videoTrackErr := webrtc.NewTrackLocalStaticSample(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion")
    if videoTrackErr != nil {
        panic(videoTrackErr)
    }
 1
2
3
4
5
2
3
4
5
再比如在用实例学习pion - rtp-to-webrtc里面用的是pion内置的基础RTP媒体track:
// Create a video track
videoTrack, err := webrtc.NewTrackLocalStaticRTP(webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP8}, "video", "pion")
if err != nil {
    panic(err)
}
 1
2
3
4
5
2
3
4
5
# 将track添加到PeerConnection
就是一个AddTrack函数,不必多讲:
rtpSender, err := peerConnection.AddTrack(videoTrack)
if err != nil {
    panic(err)
}
 1
2
3
4
2
3
4
# 等待连接传入
# 开始往track里写数据
有连接连上了就可以通过track向对方发数据了,也就是往track里写数据。往track里写数据的操作是用户自己定义的,其归根结底就是不断调用TrackLocalContext里的TrackLocalWriter.WriteRTP(这个TrackLocalContext来自于pion里调用用户实现的TrackLocal.Bind,具体情况可参见《pion中的TrackLocal》)。
比如在《用实例学习pion - play-from-disk》里,调用TrackLocalWriter.WriteRTP的过程就封装在WriteSample里,读取视频后这边只要没隔一帧的时间发一次数据即可:
        // Keep track of last granule, the difference is the amount of samples in the buffer
        var lastGranule uint64
        // It is important to use a time.Ticker instead of time.Sleep because
        // * avoids accumulating skew, just calling time.Sleep didn't compensate for the time spent parsing the data
        // * works around latency issues with Sleep (see https://github.com/golang/go/issues/44343)
        ticker := time.NewTicker(oggPageDuration)
        for ; true; <-ticker.C {
            pageData, pageHeader, oggErr := ogg.ParseNextPage()
            if oggErr == io.EOF {
                fmt.Printf("All audio pages parsed and sent")
                os.Exit(0)
            }
            if oggErr != nil {
                panic(oggErr)
            }
            // The amount of samples is the difference between the last and current timestamp
            sampleCount := float64(pageHeader.GranulePosition - lastGranule)
            lastGranule = pageHeader.GranulePosition
            sampleDuration := time.Duration((sampleCount/48000)*1000) * time.Millisecond
            if oggErr = audioTrack.WriteSample(media.Sample{Data: pageData, Duration: sampleDuration}); oggErr != nil {
                panic(oggErr)
            }
        }
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
再比如在《用实例学习pion - rtp-to-webrtc》里,track用的是pion内置的TrackLocalStaticRTP:
// Read RTP packets forever and send them to the WebRTC Client
inboundRTPPacket := make([]byte, 1600) // UDP MTU
for {
    n, _, err := listener.ReadFrom(inboundRTPPacket)
    if err != nil {
        panic(fmt.Sprintf("error during read: %s", err))
    }
    if _, err = videoTrack.Write(inboundRTPPacket[:n]); err != nil {
        if errors.Is(err, io.ErrClosedPipe) {
            // The peerConnection has been closed.
            return
        }
        panic(err)
    }
}
 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TrackLocalStaticRTP是一种编解码方式不变的TrackLocal,调用TrackLocalWriter.WriteRTP的过程就在TrackLocalStaticRTP.WriteRTP里。关于这里用的TrackLocalStaticRTP的更多介绍可以参见《pion中的TrackLocal》。