Files
go2rtc/pkg/rtsp/ports.go
T
2025-06-01 01:44:01 +03:00

76 lines
1.6 KiB
Go

package rtsp
import (
"fmt"
"net"
"sync"
)
var mu sync.Mutex
type UDPPortPair struct {
RTPListener *net.UDPConn
RTCPListener *net.UDPConn
RTPPort int
RTCPPort int
}
func (p *UDPPortPair) Close() {
if p.RTPListener != nil {
_ = p.RTPListener.Close()
}
if p.RTCPListener != nil {
_ = p.RTCPListener.Close()
}
}
func GetUDPPorts(ip net.IP, maxAttempts int) (*UDPPortPair, error) {
mu.Lock()
defer mu.Unlock()
if ip == nil {
ip = net.IPv4(0, 0, 0, 0)
}
for i := 0; i < maxAttempts; i++ {
// Get a random even port from the OS
tempListener, err := net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: 0})
if err != nil {
continue
}
addr := tempListener.LocalAddr().(*net.UDPAddr)
basePort := addr.Port
tempListener.Close()
// 11. RTP over Network and Transport Protocols (https://www.ietf.org/rfc/rfc3550.txt)
// For UDP and similar protocols,
// RTP SHOULD use an even destination port number and the corresponding
// RTCP stream SHOULD use the next higher (odd) destination port number
if basePort%2 == 1 {
basePort--
}
// Try to bind both ports
rtpListener, err := net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: basePort})
if err != nil {
continue
}
rtcpListener, err := net.ListenUDP("udp", &net.UDPAddr{IP: ip, Port: basePort + 1})
if err != nil {
rtpListener.Close()
continue
}
return &UDPPortPair{
RTPListener: rtpListener,
RTCPListener: rtcpListener,
RTPPort: basePort,
RTCPPort: basePort + 1,
}, nil
}
return nil, fmt.Errorf("failed to allocate consecutive UDP ports after %d attempts", maxAttempts)
}