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:
Alessandro Ros
2025-07-05 11:08:57 +02:00
committed by GitHub
parent 319fd4bf97
commit 4f3337f56c
16 changed files with 554 additions and 301 deletions

View File

@@ -33,7 +33,7 @@ type serverSessionMedia struct {
rtcpPacketsInError *uint64
}
func (sm *serverSessionMedia) initialize() {
func (sm *serverSessionMedia) initialize() error {
sm.bytesReceived = new(uint64)
sm.bytesSent = new(uint64)
sm.rtpPacketsInError = new(uint64)
@@ -49,9 +49,14 @@ func (sm *serverSessionMedia) initialize() {
format: forma,
onPacketRTP: func(*rtp.Packet) {},
}
f.initialize()
err := f.initialize()
if err != nil {
return err
}
sm.formats[forma.PayloadType()] = f
}
return nil
}
func (sm *serverSessionMedia) start() {
@@ -114,7 +119,7 @@ func (sm *serverSessionMedia) stop() {
}
}
func (sm *serverSessionMedia) findFormatBySSRC(ssrc uint32) *serverSessionFormat {
func (sm *serverSessionMedia) findFormatByRemoteSSRC(ssrc uint32) *serverSessionFormat {
for _, format := range sm.formats {
stats := format.rtcpReceiver.Stats()
if stats != nil && stats.RemoteSSRC == ssrc {
@@ -124,31 +129,6 @@ func (sm *serverSessionMedia) findFormatBySSRC(ssrc uint32) *serverSessionFormat
return nil
}
func (sm *serverSessionMedia) writePacketRTCPInQueueUDP(payload []byte) error {
err := sm.ss.s.udpRTCPListener.write(payload, sm.udpRTCPWriteAddr)
if err != nil {
return err
}
atomic.AddUint64(sm.bytesSent, uint64(len(payload)))
atomic.AddUint64(sm.rtcpPacketsSent, 1)
return nil
}
func (sm *serverSessionMedia) writePacketRTCPInQueueTCP(payload []byte) error {
sm.ss.tcpFrame.Channel = sm.tcpChannel + 1
sm.ss.tcpFrame.Payload = payload
sm.ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(sm.ss.s.WriteTimeout))
err := sm.ss.tcpConn.conn.WriteInterleavedFrame(sm.ss.tcpFrame, sm.ss.tcpBuffer)
if err != nil {
return err
}
atomic.AddUint64(sm.bytesSent, uint64(len(payload)))
atomic.AddUint64(sm.rtcpPacketsSent, 1)
return nil
}
func (sm *serverSessionMedia) readPacketRTPUDPPlay(payload []byte) bool {
atomic.AddUint64(sm.bytesReceived, uint64(len(payload)))
@@ -253,7 +233,7 @@ func (sm *serverSessionMedia) readPacketRTCPUDPRecord(payload []byte) bool {
for _, pkt := range packets {
if sr, ok := pkt.(*rtcp.SenderReport); ok {
format := sm.findFormatBySSRC(sr.SSRC)
format := sm.findFormatByRemoteSSRC(sr.SSRC)
if format != nil {
format.rtcpReceiver.ProcessSenderReport(sr, now)
}
@@ -354,7 +334,7 @@ func (sm *serverSessionMedia) readPacketRTCPTCPRecord(payload []byte) bool {
for _, pkt := range packets {
if sr, ok := pkt.(*rtcp.SenderReport); ok {
format := sm.findFormatBySSRC(sr.SSRC)
format := sm.findFormatByRemoteSSRC(sr.SSRC)
if format != nil {
format.rtcpReceiver.ProcessSenderReport(sr, now)
}
@@ -391,3 +371,46 @@ func (sm *serverSessionMedia) onPacketRTCPDecodeError(err error) {
log.Println(err.Error())
}
}
func (sm *serverSessionMedia) writePacketRTCPEncoded(payload []byte) error {
sm.ss.writerMutex.RLock()
defer sm.ss.writerMutex.RUnlock()
if sm.ss.writer == nil {
return nil
}
ok := sm.ss.writer.push(func() error {
return sm.writePacketRTCPInQueue(payload)
})
if !ok {
return liberrors.ErrServerWriteQueueFull{}
}
return nil
}
func (sm *serverSessionMedia) writePacketRTCPInQueueUDP(payload []byte) error {
err := sm.ss.s.udpRTCPListener.write(payload, sm.udpRTCPWriteAddr)
if err != nil {
return err
}
atomic.AddUint64(sm.bytesSent, uint64(len(payload)))
atomic.AddUint64(sm.rtcpPacketsSent, 1)
return nil
}
func (sm *serverSessionMedia) writePacketRTCPInQueueTCP(payload []byte) error {
sm.ss.tcpFrame.Channel = sm.tcpChannel + 1
sm.ss.tcpFrame.Payload = payload
sm.ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(sm.ss.s.WriteTimeout))
err := sm.ss.tcpConn.conn.WriteInterleavedFrame(sm.ss.tcpFrame, sm.ss.tcpBuffer)
if err != nil {
return err
}
atomic.AddUint64(sm.bytesSent, uint64(len(payload)))
atomic.AddUint64(sm.rtcpPacketsSent, 1)
return nil
}