Files
gortsplib/client_media.go
2024-12-24 10:24:24 +01:00

322 lines
7.2 KiB
Go

package gortsplib
import (
"net"
"sync/atomic"
"time"
"github.com/pion/rtcp"
"github.com/pion/rtp"
"github.com/bluenviron/gortsplib/v4/pkg/description"
"github.com/bluenviron/gortsplib/v4/pkg/liberrors"
)
type clientMedia struct {
c *Client
onPacketRTCP OnPacketRTCPFunc
media *description.Media
formats map[uint8]*clientFormat
tcpChannel int
udpRTPListener *clientUDPListener
udpRTCPListener *clientUDPListener
writePacketRTPInQueue func([]byte) error
writePacketRTCPInQueue func([]byte) error
}
func (cm *clientMedia) close() {
if cm.udpRTPListener != nil {
cm.udpRTPListener.close()
cm.udpRTCPListener.close()
}
}
func (cm *clientMedia) allocateUDPListeners(
multicastEnable bool,
multicastSourceIP net.IP,
rtpAddress string,
rtcpAddress string,
) error {
if rtpAddress != ":0" {
l1 := &clientUDPListener{
c: cm.c,
multicastEnable: multicastEnable,
multicastSourceIP: multicastSourceIP,
address: rtpAddress,
}
err := l1.initialize()
if err != nil {
return err
}
l2 := &clientUDPListener{
c: cm.c,
multicastEnable: multicastEnable,
multicastSourceIP: multicastSourceIP,
address: rtcpAddress,
}
err = l2.initialize()
if err != nil {
l1.close()
return err
}
cm.udpRTPListener, cm.udpRTCPListener = l1, l2
return nil
}
var err error
cm.udpRTPListener, cm.udpRTCPListener, err = allocateUDPListenerPair(cm.c)
return err
}
func (cm *clientMedia) setMedia(medi *description.Media) {
cm.media = medi
cm.formats = make(map[uint8]*clientFormat)
for _, forma := range medi.Formats {
cm.formats[forma.PayloadType()] = &clientFormat{
cm: cm,
format: forma,
onPacketRTP: func(*rtp.Packet) {},
}
}
}
func (cm *clientMedia) start() {
if cm.udpRTPListener != nil {
cm.writePacketRTPInQueue = cm.writePacketRTPInQueueUDP
cm.writePacketRTCPInQueue = cm.writePacketRTCPInQueueUDP
if cm.c.state == clientStateRecord || cm.media.IsBackChannel {
cm.udpRTPListener.readFunc = cm.readRTPUDPRecord
cm.udpRTCPListener.readFunc = cm.readRTCPUDPRecord
} else {
cm.udpRTPListener.readFunc = cm.readRTPUDPPlay
cm.udpRTCPListener.readFunc = cm.readRTCPUDPPlay
}
} else {
cm.writePacketRTPInQueue = cm.writePacketRTPInQueueTCP
cm.writePacketRTCPInQueue = cm.writePacketRTCPInQueueTCP
if cm.c.tcpCallbackByChannel == nil {
cm.c.tcpCallbackByChannel = make(map[int]readFunc)
}
if cm.c.state == clientStateRecord || cm.media.IsBackChannel {
cm.c.tcpCallbackByChannel[cm.tcpChannel] = cm.readRTPTCPRecord
cm.c.tcpCallbackByChannel[cm.tcpChannel+1] = cm.readRTCPTCPRecord
} else {
cm.c.tcpCallbackByChannel[cm.tcpChannel] = cm.readRTPTCPPlay
cm.c.tcpCallbackByChannel[cm.tcpChannel+1] = cm.readRTCPTCPPlay
}
}
for _, ct := range cm.formats {
ct.start()
}
if cm.udpRTPListener != nil {
cm.udpRTPListener.start()
cm.udpRTCPListener.start()
}
}
func (cm *clientMedia) stop() {
if cm.udpRTPListener != nil {
cm.udpRTPListener.stop()
cm.udpRTCPListener.stop()
}
for _, ct := range cm.formats {
ct.stop()
}
}
func (cm *clientMedia) findFormatWithSSRC(ssrc uint32) *clientFormat {
for _, format := range cm.formats {
tssrc, ok := format.rtcpReceiver.SenderSSRC()
if ok && tssrc == ssrc {
return format
}
}
return nil
}
func (cm *clientMedia) writePacketRTPInQueueUDP(payload []byte) error {
return cm.udpRTPListener.write(payload)
}
func (cm *clientMedia) writePacketRTCPInQueueUDP(payload []byte) error {
return cm.udpRTCPListener.write(payload)
}
func (cm *clientMedia) writePacketRTPInQueueTCP(payload []byte) error {
cm.c.tcpFrame.Channel = cm.tcpChannel
cm.c.tcpFrame.Payload = payload
cm.c.nconn.SetWriteDeadline(time.Now().Add(cm.c.WriteTimeout))
return cm.c.conn.WriteInterleavedFrame(cm.c.tcpFrame, cm.c.tcpBuffer)
}
func (cm *clientMedia) writePacketRTCPInQueueTCP(payload []byte) error {
cm.c.tcpFrame.Channel = cm.tcpChannel + 1
cm.c.tcpFrame.Payload = payload
cm.c.nconn.SetWriteDeadline(time.Now().Add(cm.c.WriteTimeout))
return cm.c.conn.WriteInterleavedFrame(cm.c.tcpFrame, cm.c.tcpBuffer)
}
func (cm *clientMedia) readRTPTCPPlay(payload []byte) bool {
now := cm.c.timeNow()
atomic.StoreInt64(cm.c.tcpLastFrameTime, now.Unix())
pkt := &rtp.Packet{}
err := pkt.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
forma, ok := cm.formats[pkt.PayloadType]
if !ok {
cm.c.OnDecodeError(liberrors.ErrClientRTPPacketUnknownPayloadType{PayloadType: pkt.PayloadType})
return false
}
forma.readRTPTCP(pkt)
return true
}
func (cm *clientMedia) readRTCPTCPPlay(payload []byte) bool {
now := cm.c.timeNow()
atomic.StoreInt64(cm.c.tcpLastFrameTime, now.Unix())
if len(payload) > udpMaxPayloadSize {
cm.c.OnDecodeError(liberrors.ErrClientRTCPPacketTooBig{L: len(payload), Max: udpMaxPayloadSize})
return false
}
packets, err := rtcp.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
for _, pkt := range packets {
if sr, ok := pkt.(*rtcp.SenderReport); ok {
format := cm.findFormatWithSSRC(sr.SSRC)
if format != nil {
format.rtcpReceiver.ProcessSenderReport(sr, now)
}
}
cm.onPacketRTCP(pkt)
}
return true
}
func (cm *clientMedia) readRTPTCPRecord(_ []byte) bool {
return false
}
func (cm *clientMedia) readRTCPTCPRecord(payload []byte) bool {
if len(payload) > udpMaxPayloadSize {
cm.c.OnDecodeError(liberrors.ErrClientRTCPPacketTooBig{L: len(payload), Max: udpMaxPayloadSize})
return false
}
packets, err := rtcp.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
for _, pkt := range packets {
cm.onPacketRTCP(pkt)
}
return true
}
func (cm *clientMedia) readRTPUDPPlay(payload []byte) bool {
plen := len(payload)
if plen == (udpMaxPayloadSize + 1) {
cm.c.OnDecodeError(liberrors.ErrClientRTPPacketTooBigUDP{})
return false
}
pkt := &rtp.Packet{}
err := pkt.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
forma, ok := cm.formats[pkt.PayloadType]
if !ok {
cm.c.OnDecodeError(liberrors.ErrClientRTPPacketUnknownPayloadType{PayloadType: pkt.PayloadType})
return false
}
forma.readRTPUDP(pkt)
return true
}
func (cm *clientMedia) readRTCPUDPPlay(payload []byte) bool {
now := cm.c.timeNow()
plen := len(payload)
if plen == (udpMaxPayloadSize + 1) {
cm.c.OnDecodeError(liberrors.ErrClientRTCPPacketTooBigUDP{})
return false
}
packets, err := rtcp.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
for _, pkt := range packets {
if sr, ok := pkt.(*rtcp.SenderReport); ok {
format := cm.findFormatWithSSRC(sr.SSRC)
if format != nil {
format.rtcpReceiver.ProcessSenderReport(sr, now)
}
}
cm.onPacketRTCP(pkt)
}
return true
}
func (cm *clientMedia) readRTPUDPRecord(_ []byte) bool {
return false
}
func (cm *clientMedia) readRTCPUDPRecord(payload []byte) bool {
plen := len(payload)
if plen == (udpMaxPayloadSize + 1) {
cm.c.OnDecodeError(liberrors.ErrClientRTCPPacketTooBigUDP{})
return false
}
packets, err := rtcp.Unmarshal(payload)
if err != nil {
cm.c.OnDecodeError(err)
return false
}
for _, pkt := range packets {
cm.onPacketRTCP(pkt)
}
return true
}