mirror of
				https://github.com/aler9/gortsplib
				synced 2025-10-31 18:42:40 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package rtcpsender contains a utility to generate RTCP sender reports.
 | |
| package rtcpsender
 | |
| 
 | |
| import (
 | |
| 	"sync"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/pion/rtcp"
 | |
| 	"github.com/pion/rtp"
 | |
| )
 | |
| 
 | |
| // seconds since 1st January 1900
 | |
| // higher 32 bits are the integer part, lower 32 bits are the fractional part
 | |
| func ntpTimeGoToRTCP(v time.Time) uint64 {
 | |
| 	s := uint64(v.UnixNano()) + 2208988800*1000000000
 | |
| 	return (s/1000000000)<<32 | (s % 1000000000)
 | |
| }
 | |
| 
 | |
| // RTCPSender is a utility to generate RTCP sender reports.
 | |
| type RTCPSender struct {
 | |
| 	ClockRate       int
 | |
| 	Period          time.Duration
 | |
| 	TimeNow         func() time.Time
 | |
| 	WritePacketRTCP func(rtcp.Packet)
 | |
| 
 | |
| 	mutex sync.RWMutex
 | |
| 
 | |
| 	// data from RTP packets
 | |
| 	firstRTPPacketSent bool
 | |
| 	lastTimeRTP        uint32
 | |
| 	lastTimeNTP        time.Time
 | |
| 	lastTimeSystem     time.Time
 | |
| 	localSSRC          uint32
 | |
| 	lastSequenceNumber uint16
 | |
| 	packetCount        uint32
 | |
| 	octetCount         uint32
 | |
| 
 | |
| 	terminate chan struct{}
 | |
| 	done      chan struct{}
 | |
| }
 | |
| 
 | |
| // Initialize initializes a RTCPSender.
 | |
| func (rs *RTCPSender) Initialize() {
 | |
| 	if rs.TimeNow == nil {
 | |
| 		rs.TimeNow = time.Now
 | |
| 	}
 | |
| 
 | |
| 	rs.terminate = make(chan struct{})
 | |
| 	rs.done = make(chan struct{})
 | |
| 
 | |
| 	go rs.run()
 | |
| }
 | |
| 
 | |
| // Close closes the RTCPSender.
 | |
| func (rs *RTCPSender) Close() {
 | |
| 	close(rs.terminate)
 | |
| 	<-rs.done
 | |
| }
 | |
| 
 | |
| func (rs *RTCPSender) run() {
 | |
| 	defer close(rs.done)
 | |
| 
 | |
| 	t := time.NewTicker(rs.Period)
 | |
| 	defer t.Stop()
 | |
| 
 | |
| 	for {
 | |
| 		select {
 | |
| 		case <-t.C:
 | |
| 			report := rs.report()
 | |
| 			if report != nil {
 | |
| 				rs.WritePacketRTCP(report)
 | |
| 			}
 | |
| 
 | |
| 		case <-rs.terminate:
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (rs *RTCPSender) report() rtcp.Packet {
 | |
| 	rs.mutex.Lock()
 | |
| 	defer rs.mutex.Unlock()
 | |
| 
 | |
| 	if !rs.firstRTPPacketSent {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	systemTimeDiff := rs.TimeNow().Sub(rs.lastTimeSystem)
 | |
| 	ntpTime := rs.lastTimeNTP.Add(systemTimeDiff)
 | |
| 	rtpTime := rs.lastTimeRTP + uint32(systemTimeDiff.Seconds()*float64(rs.ClockRate))
 | |
| 
 | |
| 	return &rtcp.SenderReport{
 | |
| 		SSRC:        rs.localSSRC,
 | |
| 		NTPTime:     ntpTimeGoToRTCP(ntpTime),
 | |
| 		RTPTime:     rtpTime,
 | |
| 		PacketCount: rs.packetCount,
 | |
| 		OctetCount:  rs.octetCount,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // ProcessPacketRTP extracts data from RTP packets.
 | |
| func (rs *RTCPSender) ProcessPacketRTP(pkt *rtp.Packet, ntp time.Time, ptsEqualsDTS bool) {
 | |
| 	rs.mutex.Lock()
 | |
| 	defer rs.mutex.Unlock()
 | |
| 
 | |
| 	if ptsEqualsDTS {
 | |
| 		rs.firstRTPPacketSent = true
 | |
| 		rs.lastTimeRTP = pkt.Timestamp
 | |
| 		rs.lastTimeNTP = ntp
 | |
| 		rs.lastTimeSystem = rs.TimeNow()
 | |
| 		rs.localSSRC = pkt.SSRC
 | |
| 	}
 | |
| 
 | |
| 	rs.lastSequenceNumber = pkt.SequenceNumber
 | |
| 
 | |
| 	rs.packetCount++
 | |
| 	rs.octetCount += uint32(len(pkt.Payload))
 | |
| }
 | |
| 
 | |
| // Stats are statistics.
 | |
| type Stats struct {
 | |
| 	LocalSSRC          uint32
 | |
| 	LastSequenceNumber uint16
 | |
| 	LastRTP            uint32
 | |
| 	LastNTP            time.Time
 | |
| }
 | |
| 
 | |
| // Stats returns statistics.
 | |
| func (rs *RTCPSender) Stats() *Stats {
 | |
| 	rs.mutex.RLock()
 | |
| 	defer rs.mutex.RUnlock()
 | |
| 
 | |
| 	if !rs.firstRTPPacketSent {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return &Stats{
 | |
| 		LocalSSRC:          rs.localSSRC,
 | |
| 		LastSequenceNumber: rs.lastSequenceNumber,
 | |
| 		LastRTP:            rs.lastTimeRTP,
 | |
| 		LastNTP:            rs.lastTimeNTP,
 | |
| 	}
 | |
| }
 | 
