mirror of
https://github.com/aler9/gortsplib
synced 2025-10-04 14:52:46 +08:00

RTP packets were previously take from a buffer pool. This was messing up the Client, since that buffer pool was used by multiple routines at once, and was probably messing up the Server too, since packets can be pushed to different queues and there's no guarantee that these queues have an overall size less than ReadBufferCount. This buffer pool is removed; this decreases performance but avoids bugs.
303 lines
7.7 KiB
Go
303 lines
7.7 KiB
Go
package gortsplib
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/pion/rtcp"
|
|
"github.com/pion/rtp"
|
|
|
|
"github.com/aler9/gortsplib/v2/pkg/base"
|
|
"github.com/aler9/gortsplib/v2/pkg/media"
|
|
"github.com/aler9/gortsplib/v2/pkg/rtcpreceiver"
|
|
"github.com/aler9/gortsplib/v2/pkg/rtpreorderer"
|
|
)
|
|
|
|
type serverSessionMedia struct {
|
|
ss *ServerSession
|
|
media *media.Media
|
|
tcpChannel int
|
|
udpRTPReadPort int
|
|
udpRTPWriteAddr *net.UDPAddr
|
|
udpRTCPReadPort int
|
|
udpRTCPWriteAddr *net.UDPAddr
|
|
tcpRTPFrame *base.InterleavedFrame
|
|
tcpRTCPFrame *base.InterleavedFrame
|
|
tcpBuffer []byte
|
|
formats map[uint8]*serverSessionFormat // record
|
|
writePacketRTPInQueue func([]byte)
|
|
writePacketRTCPInQueue func([]byte)
|
|
readRTP func([]byte) error
|
|
readRTCP func([]byte) error
|
|
onPacketRTCP func(rtcp.Packet)
|
|
}
|
|
|
|
func newServerSessionMedia(ss *ServerSession, medi *media.Media) *serverSessionMedia {
|
|
return &serverSessionMedia{
|
|
ss: ss,
|
|
media: medi,
|
|
onPacketRTCP: func(rtcp.Packet) {},
|
|
}
|
|
}
|
|
|
|
func (sm *serverSessionMedia) start() {
|
|
switch *sm.ss.setuppedTransport {
|
|
case TransportUDP, TransportUDPMulticast:
|
|
sm.writePacketRTPInQueue = sm.writePacketRTPInQueueUDP
|
|
sm.writePacketRTCPInQueue = sm.writePacketRTCPInQueueUDP
|
|
|
|
if sm.ss.state == ServerSessionStatePlay {
|
|
sm.readRTCP = sm.readRTCPUDPPlay
|
|
} else {
|
|
sm.readRTP = sm.readRTPUDPRecord
|
|
sm.readRTCP = sm.readRTCPUDPRecord
|
|
|
|
for _, tr := range sm.formats {
|
|
tr.udpReorderer = rtpreorderer.New()
|
|
|
|
cmedia := sm.media
|
|
tr.udpRTCPReceiver = rtcpreceiver.New(
|
|
sm.ss.s.udpReceiverReportPeriod,
|
|
nil,
|
|
tr.format.ClockRate(),
|
|
func(pkt rtcp.Packet) {
|
|
sm.ss.WritePacketRTCP(cmedia, pkt)
|
|
})
|
|
}
|
|
}
|
|
|
|
case TransportTCP:
|
|
sm.writePacketRTPInQueue = sm.writePacketRTPInQueueTCP
|
|
sm.writePacketRTCPInQueue = sm.writePacketRTCPInQueueTCP
|
|
|
|
if sm.ss.state == ServerSessionStatePlay {
|
|
sm.readRTP = sm.readRTPTCPPlay
|
|
sm.readRTCP = sm.readRTCPTCPPlay
|
|
} else {
|
|
sm.readRTP = sm.readRTPTCPRecord
|
|
sm.readRTCP = sm.readRTCPTCPRecord
|
|
}
|
|
|
|
sm.tcpRTPFrame = &base.InterleavedFrame{Channel: sm.tcpChannel}
|
|
sm.tcpRTCPFrame = &base.InterleavedFrame{Channel: sm.tcpChannel + 1}
|
|
sm.tcpBuffer = make([]byte, maxPacketSize+4)
|
|
}
|
|
|
|
if *sm.ss.setuppedTransport == TransportUDP {
|
|
if sm.ss.state == ServerSessionStatePlay {
|
|
// firewall opening is performed by RTCP sender reports generated by ServerStream
|
|
|
|
// readers can send RTCP packets only
|
|
sm.ss.s.udpRTCPListener.addClient(sm.ss.author.ip(), sm.udpRTCPReadPort, sm)
|
|
} else {
|
|
// open the firewall by sending test packets to the counterpart.
|
|
sm.ss.WritePacketRTP(sm.media, &rtp.Packet{Header: rtp.Header{Version: 2}})
|
|
sm.ss.WritePacketRTCP(sm.media, &rtcp.ReceiverReport{})
|
|
|
|
sm.ss.s.udpRTPListener.addClient(sm.ss.author.ip(), sm.udpRTPReadPort, sm)
|
|
sm.ss.s.udpRTCPListener.addClient(sm.ss.author.ip(), sm.udpRTCPReadPort, sm)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sm *serverSessionMedia) stop() {
|
|
if *sm.ss.setuppedTransport == TransportUDP {
|
|
sm.ss.s.udpRTPListener.removeClient(sm)
|
|
sm.ss.s.udpRTCPListener.removeClient(sm)
|
|
}
|
|
|
|
for _, tr := range sm.formats {
|
|
if tr.udpRTCPReceiver != nil {
|
|
tr.udpRTCPReceiver.Close()
|
|
tr.udpRTCPReceiver = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTPInQueueUDP(payload []byte) {
|
|
atomic.AddUint64(sm.ss.bytesSent, uint64(len(payload)))
|
|
sm.ss.s.udpRTPListener.write(payload, sm.udpRTPWriteAddr)
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTCPInQueueUDP(payload []byte) {
|
|
atomic.AddUint64(sm.ss.bytesSent, uint64(len(payload)))
|
|
sm.ss.s.udpRTCPListener.write(payload, sm.udpRTCPWriteAddr)
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTPInQueueTCP(payload []byte) {
|
|
atomic.AddUint64(sm.ss.bytesSent, uint64(len(payload)))
|
|
sm.tcpRTPFrame.Payload = payload
|
|
sm.ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(sm.ss.s.WriteTimeout))
|
|
sm.ss.tcpConn.conn.WriteInterleavedFrame(sm.tcpRTPFrame, sm.tcpBuffer)
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTCPInQueueTCP(payload []byte) {
|
|
atomic.AddUint64(sm.ss.bytesSent, uint64(len(payload)))
|
|
sm.tcpRTCPFrame.Payload = payload
|
|
sm.ss.tcpConn.nconn.SetWriteDeadline(time.Now().Add(sm.ss.s.WriteTimeout))
|
|
sm.ss.tcpConn.conn.WriteInterleavedFrame(sm.tcpRTCPFrame, sm.tcpBuffer)
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTP(payload []byte) {
|
|
sm.ss.writer.queue(func() {
|
|
sm.writePacketRTPInQueue(payload)
|
|
})
|
|
}
|
|
|
|
func (sm *serverSessionMedia) writePacketRTCP(payload []byte) {
|
|
sm.ss.writer.queue(func() {
|
|
sm.writePacketRTCPInQueue(payload)
|
|
})
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTCPUDPPlay(payload []byte) error {
|
|
plen := len(payload)
|
|
|
|
atomic.AddUint64(sm.ss.bytesReceived, uint64(plen))
|
|
|
|
if plen == (maxPacketSize + 1) {
|
|
onDecodeError(sm.ss, fmt.Errorf("RTCP packet is too big to be read with UDP"))
|
|
return nil
|
|
}
|
|
|
|
packets, err := rtcp.Unmarshal(payload)
|
|
if err != nil {
|
|
onDecodeError(sm.ss, err)
|
|
return nil
|
|
}
|
|
|
|
for _, pkt := range packets {
|
|
sm.onPacketRTCP(pkt)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTPUDPRecord(payload []byte) error {
|
|
plen := len(payload)
|
|
|
|
atomic.AddUint64(sm.ss.bytesReceived, uint64(plen))
|
|
|
|
if plen == (maxPacketSize + 1) {
|
|
onDecodeError(sm.ss, fmt.Errorf("RTP packet is too big to be read with UDP"))
|
|
return nil
|
|
}
|
|
|
|
pkt := &rtp.Packet{}
|
|
err := pkt.Unmarshal(payload)
|
|
if err != nil {
|
|
onDecodeError(sm.ss, err)
|
|
return nil
|
|
}
|
|
|
|
forma, ok := sm.formats[pkt.PayloadType]
|
|
if !ok {
|
|
onDecodeError(sm.ss, fmt.Errorf("received RTP packet with unknown payload type (%d)", pkt.PayloadType))
|
|
return nil
|
|
}
|
|
|
|
now := time.Now()
|
|
atomic.StoreInt64(sm.ss.udpLastPacketTime, now.Unix())
|
|
|
|
forma.readRTPUDP(pkt, now)
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTCPUDPRecord(payload []byte) error {
|
|
plen := len(payload)
|
|
|
|
atomic.AddUint64(sm.ss.bytesReceived, uint64(plen))
|
|
|
|
if plen == (maxPacketSize + 1) {
|
|
onDecodeError(sm.ss, fmt.Errorf("RTCP packet is too big to be read with UDP"))
|
|
return nil
|
|
}
|
|
|
|
packets, err := rtcp.Unmarshal(payload)
|
|
if err != nil {
|
|
onDecodeError(sm.ss, err)
|
|
return nil
|
|
}
|
|
|
|
now := time.Now()
|
|
atomic.StoreInt64(sm.ss.udpLastPacketTime, now.Unix())
|
|
|
|
for _, pkt := range packets {
|
|
if sr, ok := pkt.(*rtcp.SenderReport); ok {
|
|
format := serverFindFormatWithSSRC(sm.formats, sr.SSRC)
|
|
if format != nil {
|
|
format.udpRTCPReceiver.ProcessSenderReport(sr, now)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, pkt := range packets {
|
|
sm.onPacketRTCP(pkt)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTPTCPPlay(payload []byte) error {
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTCPTCPPlay(payload []byte) error {
|
|
if len(payload) > maxPacketSize {
|
|
onDecodeError(sm.ss, fmt.Errorf("RTCP packet size (%d) is greater than maximum allowed (%d)",
|
|
len(payload), maxPacketSize))
|
|
return nil
|
|
}
|
|
|
|
packets, err := rtcp.Unmarshal(payload)
|
|
if err != nil {
|
|
onDecodeError(sm.ss, err)
|
|
return nil
|
|
}
|
|
|
|
for _, pkt := range packets {
|
|
sm.onPacketRTCP(pkt)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTPTCPRecord(payload []byte) error {
|
|
pkt := &rtp.Packet{}
|
|
err := pkt.Unmarshal(payload)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
forma, ok := sm.formats[pkt.PayloadType]
|
|
if !ok {
|
|
onDecodeError(sm.ss, fmt.Errorf("received RTP packet with unknown payload type (%d)", pkt.PayloadType))
|
|
return nil
|
|
}
|
|
|
|
forma.readRTPTCP(pkt)
|
|
return nil
|
|
}
|
|
|
|
func (sm *serverSessionMedia) readRTCPTCPRecord(payload []byte) error {
|
|
if len(payload) > maxPacketSize {
|
|
onDecodeError(sm.ss, fmt.Errorf("RTCP packet size (%d) is greater than maximum allowed (%d)",
|
|
len(payload), maxPacketSize))
|
|
return nil
|
|
}
|
|
|
|
packets, err := rtcp.Unmarshal(payload)
|
|
if err != nil {
|
|
onDecodeError(sm.ss, err)
|
|
return nil
|
|
}
|
|
|
|
for _, pkt := range packets {
|
|
sm.onPacketRTCP(pkt)
|
|
}
|
|
|
|
return nil
|
|
}
|