mirror of
https://github.com/aler9/gortsplib
synced 2025-09-27 03:25:52 +08:00
set SSRC of outgoing packets (#803)
In client and server, each format now has a fixed, unique, known in advance SSRC, that is applied to outgoing packets belonging to each format. This is needed to support SRTP/MIKEY, that require each format to have a fixed, unique, and known in advance SSRC. A secondary effect is that SETUP responses now always contain SSRCs of each format, regardless of the fact that the first packet has been produced or not (previously we needed at least one packet, from which the SSRC was extracted).
This commit is contained in:
@@ -8,17 +8,43 @@ import (
|
||||
"github.com/pion/rtp"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/format"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/liberrors"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/rtcpreceiver"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/rtcpsender"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/rtplossdetector"
|
||||
"github.com/bluenviron/gortsplib/v4/pkg/rtpreorderer"
|
||||
)
|
||||
|
||||
func isClientLocalSSRCTaken(ssrc uint32, c *Client, exclude *clientFormat) bool {
|
||||
for _, cm := range c.setuppedMedias {
|
||||
for _, cf := range cm.formats {
|
||||
if cf != exclude && cf.localSSRC == ssrc {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func clientPickLocalSSRC(cf *clientFormat) (uint32, error) {
|
||||
for {
|
||||
ssrc, err := randUint32()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if ssrc != 0 && !isClientLocalSSRCTaken(ssrc, cf.cm.c, cf) {
|
||||
return ssrc, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type clientFormat struct {
|
||||
cm *clientMedia
|
||||
format format.Format
|
||||
onPacketRTP OnPacketRTPFunc
|
||||
|
||||
localSSRC uint32
|
||||
udpReorderer *rtpreorderer.Reorderer // play
|
||||
tcpLossDetector *rtplossdetector.LossDetector // play
|
||||
rtcpReceiver *rtcpreceiver.RTCPReceiver // play
|
||||
@@ -29,10 +55,18 @@ type clientFormat struct {
|
||||
rtpPacketsLost *uint64
|
||||
}
|
||||
|
||||
func (cf *clientFormat) initialize() {
|
||||
func (cf *clientFormat) initialize() error {
|
||||
var err error
|
||||
cf.localSSRC, err = clientPickLocalSSRC(cf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cf.rtpPacketsReceived = new(uint64)
|
||||
cf.rtpPacketsSent = new(uint64)
|
||||
cf.rtpPacketsLost = new(uint64)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cf *clientFormat) start() {
|
||||
@@ -64,6 +98,7 @@ func (cf *clientFormat) start() {
|
||||
|
||||
cf.rtcpReceiver = &rtcpreceiver.RTCPReceiver{
|
||||
ClockRate: cf.format.ClockRate(),
|
||||
LocalSSRC: &cf.localSSRC,
|
||||
Period: cf.cm.c.receiverReportPeriod,
|
||||
TimeNow: cf.cm.c.timeNow,
|
||||
WritePacketRTCP: func(pkt rtcp.Packet) {
|
||||
@@ -90,6 +125,16 @@ func (cf *clientFormat) stop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (cf *clientFormat) remoteSSRC() (uint32, bool) {
|
||||
if cf.rtcpReceiver != nil {
|
||||
stats := cf.rtcpReceiver.Stats()
|
||||
if stats != nil {
|
||||
return stats.RemoteSSRC, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (cf *clientFormat) readPacketRTPUDP(pkt *rtp.Packet) {
|
||||
packets, lost := cf.udpReorderer.Process(pkt)
|
||||
if lost != 0 {
|
||||
@@ -133,6 +178,28 @@ func (cf *clientFormat) handlePacketsLost(lost uint64) {
|
||||
cf.cm.c.OnPacketsLost(lost)
|
||||
}
|
||||
|
||||
func (cf *clientFormat) writePacketRTP(pkt *rtp.Packet, ntp time.Time) error {
|
||||
pkt.SSRC = cf.localSSRC
|
||||
|
||||
byts := make([]byte, cf.cm.c.MaxPacketSize)
|
||||
n, err := pkt.MarshalTo(byts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
byts = byts[:n]
|
||||
|
||||
cf.rtcpSender.ProcessPacket(pkt, ntp, cf.format.PTSEqualsDTS(pkt))
|
||||
|
||||
ok := cf.cm.c.writer.push(func() error {
|
||||
return cf.writePacketRTPInQueue(byts)
|
||||
})
|
||||
if !ok {
|
||||
return liberrors.ErrClientWriteQueueFull{}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cf *clientFormat) writePacketRTPInQueueUDP(payload []byte) error {
|
||||
err := cf.cm.udpRTPListener.write(payload)
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user