@@ -38,6 +38,7 @@ require (
|
||||
github.com/pion/transport/v4 v4.0.2
|
||||
github.com/pion/webrtc/v4 v4.2.13
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/wlynxg/anet v0.0.5
|
||||
golang.org/x/crypto v0.52.0
|
||||
golang.org/x/net v0.55.0
|
||||
golang.org/x/sys v0.45.0
|
||||
@@ -92,7 +93,6 @@ require (
|
||||
github.com/skeema/knownhosts v1.3.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.3.1 // indirect
|
||||
github.com/wlynxg/anet v0.0.5 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||
@@ -103,3 +103,5 @@ require (
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
replace github.com/pion/ice/v4 => github.com/aler9/ice/v4 v4.2.2-0.20260602093426-86d76c717f99
|
||||
|
||||
@@ -23,6 +23,8 @@ github.com/alecthomas/kong v1.15.0 h1:BVJstKbpO73zKpmIu+m/aLRrNmWwxXPIGTNin9VmLV
|
||||
github.com/alecthomas/kong v1.15.0/go.mod h1:wrlbXem1CWqUV5Vbmss5ISYhsVPkBb1Yo7YKJghju2I=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/aler9/ice/v4 v4.2.2-0.20260602093426-86d76c717f99 h1:qhKzvSXdqLM0Z3YT3DOi1h8kEKhW5HKwxFnS+BVTqTE=
|
||||
github.com/aler9/ice/v4 v4.2.2-0.20260602093426-86d76c717f99/go.mod h1:tmp90fBKpZhQDkHkp/QJb+Gn8vhMxuAcMq7PfhQWQHE=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
|
||||
@@ -165,8 +167,6 @@ github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i
|
||||
github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk=
|
||||
github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc=
|
||||
github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo=
|
||||
github.com/pion/ice/v4 v4.2.6 h1:17SKPTupOmumCMAQ4ntf8rv6q6XEfVzuz1gSFrnhzPE=
|
||||
github.com/pion/ice/v4 v4.2.6/go.mod h1:tmp90fBKpZhQDkHkp/QJb+Gn8vhMxuAcMq7PfhQWQHE=
|
||||
github.com/pion/interceptor v0.1.45 h1:6PUo/5829bIfRFIPPJQzuDn8EjxRTSB/CSD7QVCOaqo=
|
||||
github.com/pion/interceptor v0.1.45/go.mod h1:gNDYM/uFKcLe/B3gS2/7+aw6z+RDiMy2qKTnF1LO31w=
|
||||
github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=
|
||||
|
||||
@@ -1,40 +1,96 @@
|
||||
package webrtc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/bluenviron/gortsplib/v5/pkg/readbuffer"
|
||||
"github.com/pion/transport/v4"
|
||||
"github.com/pion/transport/v4/stdnet"
|
||||
"github.com/wlynxg/anet"
|
||||
)
|
||||
|
||||
type webrtcNet struct {
|
||||
udpReadBufferSize int
|
||||
// Net is stdnet.Net with the following changes:
|
||||
// - Interfaces() is overridden to query the OS directly on every call without caching.
|
||||
// - ListenUDP() is overridden to apply the configured read buffer size to the returned UDPConn.
|
||||
type Net struct {
|
||||
UDPReadBufferSize int
|
||||
|
||||
*stdnet.Net
|
||||
stdnet.Net
|
||||
}
|
||||
|
||||
func (n *webrtcNet) initialize() error {
|
||||
var err error
|
||||
n.Net, err = stdnet.NewNet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *webrtcNet) ListenUDP(network string, laddr *net.UDPAddr) (transport.UDPConn, error) {
|
||||
conn, err := n.Net.ListenUDP(network, laddr)
|
||||
// Interfaces returns the current list of network interfaces by querying the OS
|
||||
// on every call, with no caching.
|
||||
func (n *Net) Interfaces() ([]*transport.Interface, error) {
|
||||
oifs, err := anet.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n.udpReadBufferSize != 0 {
|
||||
err = readbuffer.SetReadBuffer(conn.(*net.UDPConn), n.udpReadBufferSize)
|
||||
ifs := make([]*transport.Interface, 0, len(oifs))
|
||||
for i := range oifs {
|
||||
ifc := transport.NewInterface(oifs[i])
|
||||
|
||||
var addrs []net.Addr
|
||||
addrs, err = anet.InterfaceAddrsByInterface(&oifs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, addr := range addrs {
|
||||
ifc.AddAddress(addr)
|
||||
}
|
||||
|
||||
ifs = append(ifs, ifc)
|
||||
}
|
||||
|
||||
return ifs, nil
|
||||
}
|
||||
|
||||
// InterfaceByIndex returns the interface specified by index.
|
||||
func (n *Net) InterfaceByIndex(index int) (*transport.Interface, error) {
|
||||
ifaces, err := n.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ifc := range ifaces {
|
||||
if ifc.Index == index {
|
||||
return ifc, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: index=%d", transport.ErrInterfaceNotFound, index)
|
||||
}
|
||||
|
||||
// InterfaceByName returns the interface specified by name.
|
||||
func (n *Net) InterfaceByName(name string) (*transport.Interface, error) {
|
||||
ifaces, err := n.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ifc := range ifaces {
|
||||
if ifc.Name == name {
|
||||
return ifc, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: %s", transport.ErrInterfaceNotFound, name)
|
||||
}
|
||||
|
||||
// ListenUDP acts like ListenPacket for UDP networks and applies the configured
|
||||
// read buffer size.
|
||||
func (n *Net) ListenUDP(network string, laddr *net.UDPAddr) (transport.UDPConn, error) {
|
||||
conn, err := net.ListenUDP(network, laddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n.UDPReadBufferSize != 0 {
|
||||
if err = readbuffer.SetReadBuffer(conn, n.UDPReadBufferSize); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/pion/ice/v4"
|
||||
"github.com/pion/interceptor"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/transport/v4"
|
||||
"github.com/pion/webrtc/v4"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/logger"
|
||||
@@ -151,7 +152,7 @@ type trackRecvPair struct {
|
||||
|
||||
// PeerConnection is a wrapper around webrtc.PeerConnection.
|
||||
type PeerConnection struct {
|
||||
UDPReadBufferSize uint
|
||||
Net transport.Net
|
||||
LocalRandomUDP bool
|
||||
ICEUDPMux ice.UDPMux
|
||||
ICETCPMux *TCPMuxWrapper
|
||||
@@ -218,14 +219,7 @@ func (co *PeerConnection) Start() error {
|
||||
|
||||
settingsEngine.SetSTUNGatherTimeout(co.STUNGatherTimeout)
|
||||
|
||||
webrtcNet := &webrtcNet{
|
||||
udpReadBufferSize: int(co.UDPReadBufferSize),
|
||||
}
|
||||
err := webrtcNet.initialize()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
settingsEngine.SetNet(webrtcNet)
|
||||
settingsEngine.SetNet(co.Net)
|
||||
|
||||
mediaEngine := &webrtc.MediaEngine{}
|
||||
|
||||
@@ -259,7 +253,7 @@ func (co *PeerConnection) Start() error {
|
||||
codecType = webrtc.RTPCodecTypeAudio
|
||||
}
|
||||
|
||||
err = mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
|
||||
err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
|
||||
RTPCodecCapability: tr.Caps,
|
||||
PayloadType: webrtc.PayloadType(96 + i),
|
||||
}, codecType)
|
||||
@@ -271,7 +265,7 @@ func (co *PeerConnection) Start() error {
|
||||
// When video is not used, a track must not be added but a codec has to present.
|
||||
// Otherwise audio is muted on Firefox and Chrome.
|
||||
if !videoSetupped {
|
||||
err = mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
|
||||
err := mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
|
||||
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||
MimeType: webrtc.MimeTypeVP8,
|
||||
ClockRate: 90000,
|
||||
@@ -284,14 +278,14 @@ func (co *PeerConnection) Start() error {
|
||||
}
|
||||
} else {
|
||||
for _, codec := range incomingVideoCodecs {
|
||||
err = mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeVideo)
|
||||
err := mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeVideo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, codec := range incomingAudioCodecs {
|
||||
err = mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeAudio)
|
||||
err := mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeAudio)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -300,7 +294,7 @@ func (co *PeerConnection) Start() error {
|
||||
|
||||
interceptorRegistry := &interceptor.Registry{}
|
||||
|
||||
err = registerInterceptors(
|
||||
err := registerInterceptors(
|
||||
mediaEngine,
|
||||
interceptorRegistry,
|
||||
func(s *statsInterceptor) {
|
||||
|
||||
@@ -108,7 +108,7 @@ func (c *Client) Initialize(ctx context.Context) error {
|
||||
}
|
||||
|
||||
c.pc = &webrtc.PeerConnection{
|
||||
UDPReadBufferSize: c.UDPReadBufferSize,
|
||||
Net: &webrtc.Net{UDPReadBufferSize: int(c.UDPReadBufferSize)},
|
||||
LocalRandomUDP: true,
|
||||
ICEServers: iceServers,
|
||||
IPsFromInterfaces: true,
|
||||
|
||||
@@ -214,6 +214,7 @@ type Server struct {
|
||||
httpServer *httpServer
|
||||
udpMuxLn net.PacketConn
|
||||
tcpMuxLn net.Listener
|
||||
net *webrtc.Net
|
||||
iceUDPMux ice.UDPMux
|
||||
iceTCPMux *webrtc.TCPMuxWrapper
|
||||
sessions map[*session]struct{}
|
||||
@@ -268,6 +269,8 @@ func (s *Server) Initialize() error {
|
||||
return err
|
||||
}
|
||||
|
||||
s.net = &webrtc.Net{UDPReadBufferSize: int(s.UDPReadBufferSize)}
|
||||
|
||||
if s.LocalUDPAddress != "" {
|
||||
s.udpMuxLn, err = net.ListenPacket(restrictnetwork.Restrict("udp", s.LocalUDPAddress))
|
||||
if err != nil {
|
||||
@@ -286,7 +289,11 @@ func (s *Server) Initialize() error {
|
||||
}
|
||||
}
|
||||
|
||||
s.iceUDPMux = pwebrtc.NewICEUDPMux(webrtcNilLogger, s.udpMuxLn)
|
||||
s.iceUDPMux = ice.NewUDPMuxDefault(ice.UDPMuxParams{
|
||||
UDPConn: s.udpMuxLn,
|
||||
Logger: webrtcNilLogger,
|
||||
Net: s.net,
|
||||
})
|
||||
}
|
||||
|
||||
if s.LocalTCPAddress != "" {
|
||||
@@ -356,7 +363,7 @@ outer:
|
||||
select {
|
||||
case req := <-s.chNewSession:
|
||||
sx := &session{
|
||||
udpReadBufferSize: s.UDPReadBufferSize,
|
||||
net: s.net,
|
||||
parentCtx: s.ctx,
|
||||
ipsFromInterfaces: s.IPsFromInterfaces,
|
||||
ipsFromInterfacesList: s.IPsFromInterfacesList,
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/pion/ice/v4"
|
||||
"github.com/pion/sdp/v3"
|
||||
"github.com/pion/transport/v4"
|
||||
pwebrtc "github.com/pion/webrtc/v4"
|
||||
|
||||
"github.com/bluenviron/mediamtx/internal/auth"
|
||||
@@ -235,7 +236,7 @@ type sessionParent interface {
|
||||
}
|
||||
|
||||
type session struct {
|
||||
udpReadBufferSize uint
|
||||
net transport.Net
|
||||
parentCtx context.Context
|
||||
ipsFromInterfaces bool
|
||||
ipsFromInterfacesList []string
|
||||
@@ -362,7 +363,7 @@ func (s *session) runPublish(req *initialRequestReq) (int, error) {
|
||||
}
|
||||
|
||||
pc := &webrtc.PeerConnection{
|
||||
UDPReadBufferSize: s.udpReadBufferSize,
|
||||
Net: s.net,
|
||||
ICEUDPMux: s.iceUDPMux,
|
||||
ICETCPMux: s.iceTCPMux,
|
||||
ICEServers: iceServers,
|
||||
@@ -512,7 +513,7 @@ func (s *session) runRead(req *initialRequestReq) (int, error) {
|
||||
}
|
||||
|
||||
pc := &webrtc.PeerConnection{
|
||||
UDPReadBufferSize: s.udpReadBufferSize,
|
||||
Net: s.net,
|
||||
ICEUDPMux: s.iceUDPMux,
|
||||
ICETCPMux: s.iceTCPMux,
|
||||
ICEServers: iceServers,
|
||||
|
||||
Reference in New Issue
Block a user