mirror of
https://github.com/aler9/gortsplib
synced 2025-10-16 20:20:40 +08:00
rtcpsender: extract clock rate from sdp instead of estimating it
This commit is contained in:
@@ -503,11 +503,6 @@ func (c *ConnClient) Setup(u *base.URL, mode headers.TransportMode, proto base.S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.streamUrl = u
|
|
||||||
c.streamProtocol = &proto
|
|
||||||
|
|
||||||
c.tracks = append(c.tracks, track)
|
|
||||||
|
|
||||||
if mode == headers.TransportModePlay {
|
if mode == headers.TransportModePlay {
|
||||||
c.rtcpReceivers[track.Id] = rtcpreceiver.New(nil)
|
c.rtcpReceivers[track.Id] = rtcpreceiver.New(nil)
|
||||||
|
|
||||||
@@ -516,8 +511,16 @@ func (c *ConnClient) Setup(u *base.URL, mode headers.TransportMode, proto base.S
|
|||||||
c.udpLastFrameTimes[track.Id] = &v
|
c.udpLastFrameTimes[track.Id] = &v
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.rtcpSenders[track.Id] = rtcpsender.New()
|
clockRate, err := track.ClockRate()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to get track clock rate: %s", err)
|
||||||
}
|
}
|
||||||
|
c.rtcpSenders[track.Id] = rtcpsender.New(clockRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.streamUrl = u
|
||||||
|
c.streamProtocol = &proto
|
||||||
|
c.tracks = append(c.tracks, track)
|
||||||
|
|
||||||
if proto == StreamProtocolUDP {
|
if proto == StreamProtocolUDP {
|
||||||
rtpListener.remoteIp = c.nconn.RemoteAddr().(*net.TCPAddr).IP
|
rtpListener.remoteIp = c.nconn.RemoteAddr().(*net.TCPAddr).IP
|
||||||
|
@@ -12,10 +12,10 @@ import (
|
|||||||
|
|
||||||
// RtcpReceiver allows to generate RTCP receiver reports.
|
// RtcpReceiver allows to generate RTCP receiver reports.
|
||||||
type RtcpReceiver struct {
|
type RtcpReceiver struct {
|
||||||
|
receiverSSRC uint32
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
firstRtpReceived bool
|
firstRtpReceived bool
|
||||||
senderSSRC uint32
|
senderSSRC uint32
|
||||||
receiverSSRC uint32
|
|
||||||
sequenceNumberCycles uint16
|
sequenceNumberCycles uint16
|
||||||
lastSequenceNumber uint16
|
lastSequenceNumber uint16
|
||||||
lastSenderReportTime uint32
|
lastSenderReportTime uint32
|
||||||
|
@@ -13,20 +13,21 @@ import (
|
|||||||
|
|
||||||
// RtcpSender allows to generate RTCP sender reports.
|
// RtcpSender allows to generate RTCP sender reports.
|
||||||
type RtcpSender struct {
|
type RtcpSender struct {
|
||||||
|
clockRate float64
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
firstRtpReceived bool
|
firstRtpReceived bool
|
||||||
secondRtpReceived bool
|
|
||||||
senderSSRC uint32
|
senderSSRC uint32
|
||||||
packetCount uint32
|
|
||||||
octetCount uint32
|
|
||||||
rtpTimeOffset uint32
|
rtpTimeOffset uint32
|
||||||
rtpTimeTime time.Time
|
rtpTimeTime time.Time
|
||||||
clock float64
|
packetCount uint32
|
||||||
|
octetCount uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// New allocates a RtcpSender.
|
// New allocates a RtcpSender.
|
||||||
func New() *RtcpSender {
|
func New(clockRate int) *RtcpSender {
|
||||||
return &RtcpSender{}
|
return &RtcpSender{
|
||||||
|
clockRate: float64(clockRate),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnFrame processes a RTP or RTCP frame and extract the needed data.
|
// OnFrame processes a RTP or RTCP frame and extract the needed data.
|
||||||
@@ -45,13 +46,6 @@ func (rs *RtcpSender) OnFrame(ts time.Time, streamType base.StreamType, buf []by
|
|||||||
// save RTP time offset and correspondent time
|
// save RTP time offset and correspondent time
|
||||||
rs.rtpTimeOffset = pkt.Timestamp
|
rs.rtpTimeOffset = pkt.Timestamp
|
||||||
rs.rtpTimeTime = ts
|
rs.rtpTimeTime = ts
|
||||||
|
|
||||||
} else if !rs.secondRtpReceived && pkt.Timestamp != rs.rtpTimeOffset {
|
|
||||||
rs.secondRtpReceived = true
|
|
||||||
|
|
||||||
// estimate clock
|
|
||||||
rs.clock = float64(pkt.Timestamp-rs.rtpTimeOffset) /
|
|
||||||
ts.Sub(rs.rtpTimeTime).Seconds()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rs.packetCount++
|
rs.packetCount++
|
||||||
@@ -65,7 +59,7 @@ func (rs *RtcpSender) Report(ts time.Time) []byte {
|
|||||||
rs.mutex.Lock()
|
rs.mutex.Lock()
|
||||||
defer rs.mutex.Unlock()
|
defer rs.mutex.Unlock()
|
||||||
|
|
||||||
if !rs.firstRtpReceived || !rs.secondRtpReceived {
|
if !rs.firstRtpReceived {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,14 +67,14 @@ func (rs *RtcpSender) Report(ts time.Time) []byte {
|
|||||||
SSRC: rs.senderSSRC,
|
SSRC: rs.senderSSRC,
|
||||||
NTPTime: func() uint64 {
|
NTPTime: func() uint64 {
|
||||||
// seconds since 1st January 1900
|
// seconds since 1st January 1900
|
||||||
n := (float64(ts.UnixNano()) / 1000000000) + 2208988800
|
s := (float64(ts.UnixNano()) / 1000000000) + 2208988800
|
||||||
|
|
||||||
// higher 32 bits are the integer part, lower 32 bits are the fractional part
|
// higher 32 bits are the integer part, lower 32 bits are the fractional part
|
||||||
integerPart := uint32(n)
|
integerPart := uint32(s)
|
||||||
fractionalPart := uint32((n - float64(integerPart)) * 0xFFFFFFFF)
|
fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
|
||||||
return uint64(integerPart)<<32 | uint64(fractionalPart)
|
return uint64(integerPart)<<32 | uint64(fractionalPart)
|
||||||
}(),
|
}(),
|
||||||
RTPTime: rs.rtpTimeOffset + uint32((ts.Sub(rs.rtpTimeTime)).Seconds()*rs.clock),
|
RTPTime: rs.rtpTimeOffset + uint32((ts.Sub(rs.rtpTimeTime)).Seconds()*float64(rs.clockRate)),
|
||||||
PacketCount: rs.packetCount,
|
PacketCount: rs.packetCount,
|
||||||
OctetCount: rs.octetCount,
|
OctetCount: rs.octetCount,
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,7 @@ const (
|
|||||||
// Encoder is a RPT/AAC encoder.
|
// Encoder is a RPT/AAC encoder.
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
payloadType uint8
|
payloadType uint8
|
||||||
samplingRate float64
|
sampleRate float64
|
||||||
sequenceNumber uint16
|
sequenceNumber uint16
|
||||||
ssrc uint32
|
ssrc uint32
|
||||||
initialTs uint32
|
initialTs uint32
|
||||||
@@ -35,7 +35,7 @@ func NewEncoder(relativeType uint8, config []byte) (*Encoder, error) {
|
|||||||
|
|
||||||
return &Encoder{
|
return &Encoder{
|
||||||
payloadType: 96 + relativeType,
|
payloadType: 96 + relativeType,
|
||||||
samplingRate: float64(codec.Config.SampleRate),
|
sampleRate: float64(codec.Config.SampleRate),
|
||||||
sequenceNumber: uint16(rand.Uint32()),
|
sequenceNumber: uint16(rand.Uint32()),
|
||||||
ssrc: rand.Uint32(),
|
ssrc: rand.Uint32(),
|
||||||
initialTs: rand.Uint32(),
|
initialTs: rand.Uint32(),
|
||||||
@@ -52,7 +52,7 @@ func (e *Encoder) Write(data []byte, timestamp time.Duration) ([][]byte, error)
|
|||||||
return nil, fmt.Errorf("data is too big")
|
return nil, fmt.Errorf("data is too big")
|
||||||
}
|
}
|
||||||
|
|
||||||
rtpTs := e.initialTs + uint32((timestamp-e.started).Seconds()*e.samplingRate)
|
rtpTs := e.initialTs + uint32((timestamp-e.started).Seconds()*e.sampleRate)
|
||||||
|
|
||||||
// 13 bits payload size
|
// 13 bits payload size
|
||||||
// 3 bits AU-Index(-delta)
|
// 3 bits AU-Index(-delta)
|
||||||
|
26
track.go
26
track.go
@@ -107,6 +107,32 @@ func NewTrackAac(id int, config []byte) (*Track, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClockRate returns the clock rate of the track.
|
||||||
|
func (t *Track) ClockRate() (int, error) {
|
||||||
|
// https://tools.ietf.org/html/rfc4566
|
||||||
|
// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
|
||||||
|
for _, a := range t.Media.Attributes {
|
||||||
|
if a.Key == "rtpmap" {
|
||||||
|
tmp := strings.Split(a.Value, " ")
|
||||||
|
if len(tmp) != 2 {
|
||||||
|
return 0, fmt.Errorf("invalid format (%s)", a.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = strings.Split(tmp[1], "/")
|
||||||
|
if len(tmp) != 2 && len(tmp) != 3 {
|
||||||
|
return 0, fmt.Errorf("invalid format (%s)", a.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
v, err := strconv.ParseInt(tmp[1], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int(v), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("attribute 'rtpmap' not found")
|
||||||
|
}
|
||||||
|
|
||||||
// Tracks is a list of tracks.
|
// Tracks is a list of tracks.
|
||||||
type Tracks []*Track
|
type Tracks []*Track
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user