Files
gortsplib/rtcp-receiver.go
2020-09-01 00:22:40 +02:00

148 lines
3.2 KiB
Go

package gortsplib
import (
"math/rand"
"time"
"github.com/pion/rtcp"
)
type frameRtpReq struct {
sequenceNumber uint16
}
type frameRtcpReq struct {
ssrc uint32
ntpTimeMiddle uint32
}
type lastFrameTimeReq struct {
res chan time.Time
}
type reportReq struct {
res chan []byte
}
// RtcpReceiver is an object that helps building RTCP receiver reports, by parsing
// incoming frames.
type RtcpReceiver struct {
frameRtp chan frameRtpReq
frameRtcp chan frameRtcpReq
lastFrameTime chan lastFrameTimeReq
report chan reportReq
terminate chan struct{}
done chan struct{}
}
// NewRtcpReceiver allocates a RtcpReceiver.
func NewRtcpReceiver() *RtcpReceiver {
rr := &RtcpReceiver{
frameRtp: make(chan frameRtpReq),
frameRtcp: make(chan frameRtcpReq),
lastFrameTime: make(chan lastFrameTimeReq),
report: make(chan reportReq),
terminate: make(chan struct{}),
done: make(chan struct{}),
}
go rr.run()
return rr
}
func (rr *RtcpReceiver) run() {
lastFrameTime := time.Now()
publisherSSRC := uint32(0)
receiverSSRC := rand.Uint32()
sequenceNumberCycles := uint16(0)
lastSequenceNumber := uint16(0)
lastSenderReport := uint32(0)
outer:
for {
select {
case req := <-rr.frameRtp:
if req.sequenceNumber < lastSequenceNumber {
sequenceNumberCycles += 1
}
lastSequenceNumber = req.sequenceNumber
lastFrameTime = time.Now()
case req := <-rr.frameRtcp:
publisherSSRC = req.ssrc
lastSenderReport = req.ntpTimeMiddle
case req := <-rr.lastFrameTime:
req.res <- lastFrameTime
case req := <-rr.report:
rr := &rtcp.ReceiverReport{
SSRC: receiverSSRC,
Reports: []rtcp.ReceptionReport{
{
SSRC: publisherSSRC,
LastSequenceNumber: uint32(sequenceNumberCycles)<<8 | uint32(lastSequenceNumber),
LastSenderReport: lastSenderReport,
},
},
}
frame, _ := rr.Marshal()
req.res <- frame
case <-rr.terminate:
break outer
}
}
close(rr.frameRtp)
close(rr.frameRtcp)
close(rr.lastFrameTime)
close(rr.report)
close(rr.done)
}
// Close closes a RtcpReceiver.
func (rr *RtcpReceiver) Close() {
close(rr.terminate)
<-rr.done
}
// OnFrame process a RTP or RTCP frame and extract the data needed by RTCP receiver reports.
func (rr *RtcpReceiver) OnFrame(streamType StreamType, buf []byte) {
if streamType == StreamTypeRtp {
// extract sequence number of first frame
if len(buf) >= 3 {
sequenceNumber := uint16(uint16(buf[2])<<8 | uint16(buf[1]))
rr.frameRtp <- frameRtpReq{sequenceNumber}
}
} else {
frames, err := rtcp.Unmarshal(buf)
if err == nil {
for _, frame := range frames {
if senderReport, ok := (frame).(*rtcp.SenderReport); ok {
rr.frameRtcp <- frameRtcpReq{
senderReport.SSRC,
uint32(senderReport.NTPTime >> 16),
}
}
}
}
}
}
// LastFrameTime returns the time the last frame was received.
func (rr *RtcpReceiver) LastFrameTime() time.Time {
res := make(chan time.Time)
rr.lastFrameTime <- lastFrameTimeReq{res}
return <-res
}
// Report generates a RTCP receiver report.
func (rr *RtcpReceiver) Report() []byte {
res := make(chan []byte)
rr.report <- reportReq{res}
return <-res
}