remove custom forks of pion/webrtc and pion/ice (#4861)

this fixes IPv6 reliability issues and allows to receive upstream
updates in a more linear way.
This commit is contained in:
Alessandro Ros
2025-08-12 14:30:08 +02:00
committed by GitHub
parent 89993951ca
commit 5ae934887d
7 changed files with 305 additions and 98 deletions

12
go.mod
View File

@@ -24,13 +24,13 @@ require (
github.com/gorilla/websocket v1.5.3
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/matthewhartstonge/argon2 v1.3.4
github.com/pion/ice/v4 v4.0.7
github.com/pion/ice/v4 v4.0.10
github.com/pion/interceptor v0.1.40
github.com/pion/logging v0.2.4
github.com/pion/rtcp v1.2.15
github.com/pion/rtp v1.8.21
github.com/pion/sdp/v3 v3.0.15
github.com/pion/webrtc/v4 v4.0.7
github.com/pion/webrtc/v4 v4.1.3
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.41.0
golang.org/x/sys v0.35.0
@@ -69,10 +69,10 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v3 v3.0.4 // indirect
github.com/pion/dtls/v3 v3.0.6 // indirect
github.com/pion/mdns/v2 v2.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/sctp v1.8.36 // indirect
github.com/pion/sctp v1.8.39 // indirect
github.com/pion/srtp/v3 v3.0.6 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v3 v3.0.7 // indirect
@@ -94,7 +94,3 @@ 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.0.0-20250301104324-b2df7db9f75d
replace github.com/pion/webrtc/v4 => github.com/aler9/webrtc/v4 v4.0.0-20250228091429-18796cd12b4f

16
go.sum
View File

@@ -19,10 +19,6 @@ github.com/alecthomas/kong v1.12.1 h1:iq6aMJDcFYP9uFrLdsiZQ2ZMmcshduyGv4Pek0MQPW
github.com/alecthomas/kong v1.12.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/aler9/ice/v4 v4.0.0-20250301104324-b2df7db9f75d h1:x28XXs2QllDNMOEjurxOMKEcg5150lQuzyjNFiHlvkM=
github.com/aler9/ice/v4 v4.0.0-20250301104324-b2df7db9f75d/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
github.com/aler9/webrtc/v4 v4.0.0-20250228091429-18796cd12b4f h1:QM/Wq0tWsInWN9rtxdMNnCBWg5o3XJl6LdWAS61h2yc=
github.com/aler9/webrtc/v4 v4.0.0-20250228091429-18796cd12b4f/go.mod h1:C+5JA7KiyLyoKyGh7hVFD/HCAon3IB/tfniocpZ9JoU=
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=
@@ -155,8 +151,10 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E=
github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU=
github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4=
github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4=
github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic=
github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=
@@ -169,8 +167,8 @@ github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
github.com/pion/rtp v1.8.21 h1:3yrOwmZFyUpcIosNcWRpQaU+UXIJ6yxLuJ8Bx0mw37Y=
github.com/pion/rtp v1.8.21/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
github.com/pion/sctp v1.8.36 h1:owNudmnz1xmhfYje5L/FCav3V9wpPRePHle3Zi+P+M0=
github.com/pion/sctp v1.8.36/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
github.com/pion/sdp/v3 v3.0.15 h1:F0I1zds+K/+37ZrzdADmx2Q44OFDOPRLhPnNTaUX9hk=
github.com/pion/sdp/v3 v3.0.15/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4=
@@ -181,6 +179,8 @@ github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
github.com/pion/webrtc/v4 v4.1.3 h1:YZ67Boj9X/hk190jJZ8+HFGQ6DqSZ/fYP3sLAZv7c3c=
github.com/pion/webrtc/v4 v4.1.3/go.mod h1:rsq+zQ82ryfR9vbb0L1umPJ6Ogq7zm8mcn9fcGnxomM=
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=

View File

@@ -5,8 +5,10 @@ import (
"context"
"errors"
"fmt"
"net"
"slices"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
@@ -24,6 +26,40 @@ const (
webrtcStreamID = "mediamtx"
)
func interfaceIPs(interfaceList []string) ([]string, error) {
intfs, err := net.Interfaces()
if err != nil {
return nil, err
}
var ips []string
for _, intf := range intfs {
if len(interfaceList) == 0 || slices.Contains(interfaceList, intf.Name) {
var addrs []net.Addr
addrs, err = intf.Addrs()
if err == nil {
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip != nil {
ips = append(ips, ip.String())
}
}
}
}
}
return ips, nil
}
// * skip ConfigureRTCPReports
// * add statsInterceptor
func registerInterceptors(
@@ -98,7 +134,7 @@ type trackRecvPair struct {
type PeerConnection struct {
LocalRandomUDP bool
ICEUDPMux ice.UDPMux
ICETCPMux ice.TCPMux
ICETCPMux *TCPMuxWrapper
ICEServers []webrtc.ICEServer
IPsFromInterfaces bool
IPsFromInterfacesList []string
@@ -135,31 +171,24 @@ func (co *PeerConnection) Start() error {
settingsEngine.SetIncludeLoopbackCandidate(true)
settingsEngine.SetInterfaceFilter(func(iface string) bool {
return co.IPsFromInterfaces && (len(co.IPsFromInterfacesList) == 0 ||
slices.Contains(co.IPsFromInterfacesList, iface))
})
settingsEngine.SetAdditionalHosts(co.AdditionalHosts)
// always enable all networks since we might be the client of a remote TCP listener
settingsEngine.SetNetworkTypes([]webrtc.NetworkType{
webrtc.NetworkTypeUDP4,
// always enable TCP since we might be the client of a remote TCP listener
networkTypes := []webrtc.NetworkType{
webrtc.NetworkTypeTCP4,
webrtc.NetworkTypeUDP6,
webrtc.NetworkTypeTCP6,
})
}
if co.LocalRandomUDP || co.ICEUDPMux != nil || len(co.ICEServers) != 0 {
networkTypes = append(networkTypes, webrtc.NetworkTypeUDP4, webrtc.NetworkTypeUDP6)
}
settingsEngine.SetNetworkTypes(networkTypes)
if co.ICEUDPMux != nil {
settingsEngine.SetICEUDPMux(co.ICEUDPMux)
}
if co.ICETCPMux != nil {
settingsEngine.SetICETCPMux(co.ICETCPMux)
}
if co.LocalRandomUDP {
settingsEngine.SetLocalRandomUDP(true)
settingsEngine.SetICETCPMux(co.ICETCPMux.Mux)
}
settingsEngine.SetSTUNGatherTimeout(time.Duration(co.STUNGatherTimeout))
@@ -388,19 +417,139 @@ func (co *PeerConnection) Close() {
<-co.closed
}
func (co *PeerConnection) removeUnwantedCandidates(firstMedia *sdp.MediaDescription) error {
var allowedIPs []string
if co.IPsFromInterfaces {
var err error
allowedIPs, err = interfaceIPs(co.IPsFromInterfacesList)
if err != nil {
return err
}
}
var newAttributes []sdp.Attribute //nolint:prealloc
for _, attr := range firstMedia.Attributes {
if attr.Key == "candidate" {
parts := strings.Split(attr.Value, " ")
// hide random UDP candidates
if !co.LocalRandomUDP && co.ICEUDPMux == nil && parts[2] == "udp" && parts[7] == "host" {
continue
}
// hide disallowed IPs
if parts[7] == "host" && !slices.Contains(allowedIPs, parts[4]) {
continue
}
}
newAttributes = append(newAttributes, attr)
}
firstMedia.Attributes = newAttributes
return nil
}
func (co *PeerConnection) addAdditionalCandidates(firstMedia *sdp.MediaDescription) error {
i := 0
for _, attr := range firstMedia.Attributes {
if attr.Key == "end-of-candidates" {
break
}
i++
}
for _, host := range co.AdditionalHosts {
newAttrs := append([]sdp.Attribute(nil), firstMedia.Attributes[:i]...)
if co.ICEUDPMux != nil {
port := strconv.FormatInt(int64(co.ICEUDPMux.GetListenAddresses()[0].(*net.UDPAddr).Port), 10)
tmp, err := randUint32()
if err != nil {
return err
}
id := strconv.FormatInt(int64(tmp), 10)
newAttrs = append(newAttrs, sdp.Attribute{
Key: "candidate",
Value: id + " 1 udp 2130706431 " + host + " " + port + " typ host",
})
newAttrs = append(newAttrs, sdp.Attribute{
Key: "candidate",
Value: id + " 2 udp 2130706431 " + host + " " + port + " typ host",
})
}
if co.ICETCPMux != nil {
port := strconv.FormatInt(int64(co.ICETCPMux.Ln.Addr().(*net.TCPAddr).Port), 10)
tmp, err := randUint32()
if err != nil {
return err
}
id := strconv.FormatInt(int64(tmp), 10)
newAttrs = append(newAttrs, sdp.Attribute{
Key: "candidate",
Value: id + " 1 tcp 1671430143 " + host + " " + port + " typ host tcptype passive",
})
newAttrs = append(newAttrs, sdp.Attribute{
Key: "candidate",
Value: id + " 2 tcp 1671430143 " + host + " " + port + " typ host tcptype passive",
})
}
newAttrs = append(newAttrs, firstMedia.Attributes[i:]...)
firstMedia.Attributes = newAttrs
}
return nil
}
func (co *PeerConnection) filterLocalDescription(desc *webrtc.SessionDescription) (*webrtc.SessionDescription, error) {
var psdp sdp.SessionDescription
psdp.Unmarshal([]byte(desc.SDP)) //nolint:errcheck
firstMedia := psdp.MediaDescriptions[0]
err := co.removeUnwantedCandidates(firstMedia)
if err != nil {
return nil, err
}
err = co.addAdditionalCandidates(firstMedia)
if err != nil {
return nil, err
}
out, _ := psdp.Marshal()
desc.SDP = string(out)
return desc, nil
}
// CreatePartialOffer creates a partial offer.
func (co *PeerConnection) CreatePartialOffer() (*webrtc.SessionDescription, error) {
offer, err := co.wr.CreateOffer(nil)
tmp, err := co.wr.CreateOffer(nil)
if err != nil {
return nil, err
}
offer := &tmp
err = co.wr.SetLocalDescription(*offer)
if err != nil {
return nil, err
}
err = co.wr.SetLocalDescription(offer)
offer, err = co.filterLocalDescription(offer)
if err != nil {
return nil, err
}
return &offer, nil
return offer, nil
}
// SetAnswer sets the answer.
@@ -423,15 +572,16 @@ func (co *PeerConnection) CreateFullAnswer(
return nil, err
}
answer, err := co.wr.CreateAnswer(nil)
tmp, err := co.wr.CreateAnswer(nil)
if err != nil {
if errors.Is(err, webrtc.ErrSenderWithNoCodecs) {
return nil, fmt.Errorf("codecs not supported by client")
}
return nil, err
}
answer := &tmp
err = co.wr.SetLocalDescription(answer)
err = co.wr.SetLocalDescription(*answer)
if err != nil {
return nil, err
}
@@ -441,7 +591,14 @@ func (co *PeerConnection) CreateFullAnswer(
return nil, err
}
return co.wr.LocalDescription(), nil
answer = co.wr.LocalDescription()
answer, err = co.filterLocalDescription(answer)
if err != nil {
return nil, err
}
return answer, nil
}
func (co *PeerConnection) waitGatheringDone(ctx context.Context) error {

View File

@@ -3,6 +3,7 @@ package webrtc
import (
"context"
"net"
"regexp"
"sort"
"strings"
"testing"
@@ -60,12 +61,59 @@ func TestPeerConnectionCloseImmediately(t *testing.T) {
func TestPeerConnectionCandidates(t *testing.T) {
for _, ca := range []string{
"udp random",
"udp",
"tcp",
"stun",
"udp+stun",
"udp random+stun",
} {
t.Run(ca, func(t *testing.T) {
pc2, err := webrtc.NewPeerConnection(webrtc.Configuration{})
require.NoError(t, err)
defer pc2.Close() //nolint:errcheck
track, err := webrtc.NewTrackLocalStaticRTP(
webrtc.RTPCodecCapability{
MimeType: webrtc.MimeTypeVP8,
ClockRate: 90000,
},
"video",
"publisher",
)
require.NoError(t, err)
_, err = pc2.AddTrack(track)
require.NoError(t, err)
offer, err := pc2.CreateOffer(nil)
require.NoError(t, err)
var udpMux ice.UDPMux
if ca == "udp" || ca == "udp+stun" {
var ln net.PacketConn
ln, err = net.ListenPacket("udp", ":3454")
require.NoError(t, err)
defer ln.Close()
udpMux = webrtc.NewICEUDPMux(webrtcNilLogger, ln)
}
var tcpMux *TCPMuxWrapper
if ca == "tcp" {
var ln net.Listener
ln, err = net.Listen("tcp", ":3454")
require.NoError(t, err)
defer ln.Close()
tcpMux = &TCPMuxWrapper{
Mux: webrtc.NewICETCPMux(webrtcNilLogger, ln, 8),
Ln: ln,
}
}
pc := &PeerConnection{
LocalRandomUDP: (ca == "udp random" || ca == "udp random+stun"),
ICEUDPMux: udpMux,
ICETCPMux: tcpMux,
IPsFromInterfaces: true,
IPsFromInterfacesList: []string{"lo"},
HandshakeTimeout: conf.Duration(10 * time.Second),
@@ -73,33 +121,38 @@ func TestPeerConnectionCandidates(t *testing.T) {
Log: test.NilLogger,
}
if ca == "udp" || ca == "udp+stun" {
pc.LocalRandomUDP = true
}
if ca == "stun" || ca == "udp+stun" {
if ca == "stun" || ca == "udp+stun" || ca == "udp random+stun" {
pc.ICEServers = []webrtc.ICEServer{{
URLs: []string{"stun:stun.l.google.com:19302"},
}}
}
err := pc.Start()
err = pc.Start()
require.NoError(t, err)
defer pc.Close()
_, err = pc.CreatePartialOffer()
answer, err := pc.CreateFullAnswer(context.Background(), &offer)
require.NoError(t, err)
// convert partial offer into full offer
err = pc.waitGatheringDone(context.Background())
require.NoError(t, err)
offer := pc.wr.LocalDescription()
if ca == "udp" || ca == "udp+stun" {
require.Equal(t, 2, strings.Count(offer.SDP, "typ host"))
n := len(regexp.MustCompile("(?m)^a=candidate:.+? udp .+? typ host").FindAllString(answer.SDP, -1))
if ca == "udp" || ca == "udp random" || ca == "udp+stun" || ca == "udp random+stun" {
require.Equal(t, 2, n)
} else {
require.Equal(t, 0, n)
}
if ca == "stun" || ca == "udp+stun" {
require.Equal(t, 2, strings.Count(offer.SDP, "typ srflx"))
n = len(regexp.MustCompile("(?m)^a=candidate:.+? tcp .+? typ host tcptype passive").FindAllString(answer.SDP, -1))
if ca == "tcp" {
require.Equal(t, 2, n)
} else {
require.Equal(t, 0, n)
}
n = len(regexp.MustCompile("(?m)^a=candidate:.+? udp .+? typ srflx").FindAllString(answer.SDP, -1))
if ca == "stun" || ca == "udp+stun" || ca == "udp random+stun" {
require.Equal(t, 2, n)
} else {
require.Equal(t, 0, n)
}
})
}
@@ -117,7 +170,7 @@ func TestPeerConnectionConnectivity(t *testing.T) {
"additional hosts",
} {
// LocalRandomUDP doesn't work with AdditionalHosts
// we do not care since currently we are not using them together
// we don't care since we are not currently using them together
if mode == "active udp" && ip == "additional hosts" {
continue
}
@@ -145,7 +198,7 @@ func TestPeerConnectionConnectivity(t *testing.T) {
defer clientPC.Close()
var udpMux ice.UDPMux
var tcpMux ice.TCPMux
var tcpMux *TCPMuxWrapper
switch mode {
case "passive udp":
@@ -160,7 +213,10 @@ func TestPeerConnectionConnectivity(t *testing.T) {
ln, err = net.Listen("tcp4", ":4458")
require.NoError(t, err)
defer ln.Close()
tcpMux = webrtc.NewICETCPMux(webrtcNilLogger, ln, 8)
tcpMux = &TCPMuxWrapper{
Mux: webrtc.NewICETCPMux(webrtcNilLogger, ln, 8),
Ln: ln,
}
}
serverPC := &PeerConnection{
@@ -184,21 +240,17 @@ func TestPeerConnectionConnectivity(t *testing.T) {
serverPC.IPsFromInterfaces = true
serverPC.IPsFromInterfacesList = []string{"lo"}
} else {
serverPC.AdditionalHosts = []string{"127.0.0.2"}
serverPC.AdditionalHosts = []string{"127.0.0.1"}
}
err = serverPC.Start()
require.NoError(t, err)
defer serverPC.Close()
_, err = clientPC.CreatePartialOffer()
offer, err := clientPC.CreatePartialOffer()
require.NoError(t, err)
// convert partial offer into full offer
err = clientPC.waitGatheringDone(context.Background())
require.NoError(t, err)
answer, err := serverPC.CreateFullAnswer(context.Background(), clientPC.wr.LocalDescription())
answer, err := serverPC.CreateFullAnswer(context.Background(), offer)
require.NoError(t, err)
require.Equal(t, 2, strings.Count(answer.SDP, "a=candidate:"))
@@ -206,43 +258,28 @@ func TestPeerConnectionConnectivity(t *testing.T) {
err = clientPC.SetAnswer(answer)
require.NoError(t, err)
go func() {
for {
select {
case cd := <-clientPC.NewLocalCandidate():
err2 := serverPC.AddRemoteCandidate(cd)
require.NoError(t, err2)
case <-clientPC.Failed():
return
}
}
}()
err = serverPC.WaitUntilConnected(context.Background())
require.NoError(t, err)
switch mode {
case "passive udp":
if ip == "from interfaces" {
require.Regexp(t, "^host/udp/127\\.0\\.0\\.1/4458$", serverPC.LocalCandidate())
} else {
require.Regexp(t, "^host/udp/127\\.0\\.0\\.2/4458$", serverPC.LocalCandidate())
}
case "passive tcp":
if ip == "from interfaces" {
require.Regexp(t, "^host/tcp/127\\.0\\.0\\.1/4458$", serverPC.LocalCandidate())
} else {
require.Regexp(t, "^host/tcp/127\\.0\\.0\\.2/4458$", serverPC.LocalCandidate())
}
case "active udp":
require.Regexp(t, "^host/udp/127\\.0\\.0\\.1", serverPC.LocalCandidate())
case "active udp + stun":
require.Regexp(t, "^srflx/udp/", serverPC.LocalCandidate())
}
})
}
}
}
func TestPeerConnectionRead(t *testing.T) {
settingsEngine := webrtc.SettingEngine{}
settingsEngine.SetLocalRandomUDP(true)
api := webrtc.NewAPI(
webrtc.WithSettingEngine(settingsEngine))
pub, err := api.NewPeerConnection(webrtc.Configuration{})
pub, err := webrtc.NewPeerConnection(webrtc.Configuration{})
require.NoError(t, err)
defer pub.Close() //nolint:errcheck

View File

@@ -0,0 +1,13 @@
package webrtc
import (
"net"
"github.com/pion/ice/v4"
)
// TCPMuxWrapper is a wrapper around ice.TCPMux.
type TCPMuxWrapper struct {
Mux ice.TCPMux
Ln net.Listener
}

View File

@@ -26,6 +26,7 @@ import (
"github.com/bluenviron/mediamtx/internal/defs"
"github.com/bluenviron/mediamtx/internal/externalcmd"
"github.com/bluenviron/mediamtx/internal/logger"
"github.com/bluenviron/mediamtx/internal/protocols/webrtc"
"github.com/bluenviron/mediamtx/internal/restrictnetwork"
"github.com/bluenviron/mediamtx/internal/stream"
)
@@ -211,7 +212,7 @@ type Server struct {
udpMuxLn net.PacketConn
tcpMuxLn net.Listener
iceUDPMux ice.UDPMux
iceTCPMux ice.TCPMux
iceTCPMux *webrtc.TCPMuxWrapper
sessions map[*session]struct{}
sessionsBySecret map[uuid.UUID]*session
@@ -282,7 +283,10 @@ func (s *Server) Initialize() error {
ctxCancel()
return err
}
s.iceTCPMux = pwebrtc.NewICETCPMux(webrtcNilLogger, s.tcpMuxLn, 8)
s.iceTCPMux = &webrtc.TCPMuxWrapper{
Mux: pwebrtc.NewICETCPMux(webrtcNilLogger, s.tcpMuxLn, 8),
Ln: s.tcpMuxLn,
}
}
str := "listener opened on " + s.Address + " (HTTP)"

View File

@@ -46,7 +46,7 @@ type session struct {
ipsFromInterfacesList []string
additionalHosts []string
iceUDPMux ice.UDPMux
iceTCPMux ice.TCPMux
iceTCPMux *webrtc.TCPMuxWrapper
handshakeTimeout conf.Duration
trackGatherTimeout conf.Duration
stunGatherTimeout conf.Duration