From f03b44d7e07193fe0c808b5061f36187443c27c3 Mon Sep 17 00:00:00 2001 From: Jason Walton Date: Tue, 28 May 2024 09:54:35 -0400 Subject: [PATCH] webrtc: allow configuring timeouts (#3404) --- apidocs/openapi.yaml | 4 +++ internal/conf/conf.go | 4 +++ internal/core/core.go | 2 ++ internal/protocols/webrtc/peer_connection.go | 11 ++++--- .../protocols/webrtc/peer_connection_test.go | 11 ++++--- internal/protocols/webrtc/whip_client.go | 32 ++++++++++++------- internal/servers/webrtc/server.go | 2 ++ internal/servers/webrtc/server_test.go | 14 ++++++-- internal/servers/webrtc/session.go | 4 +++ internal/staticsources/webrtc/source_test.go | 12 ++++--- mediamtx.yml | 4 +++ 11 files changed, 72 insertions(+), 28 deletions(-) diff --git a/apidocs/openapi.yaml b/apidocs/openapi.yaml index d4f6e9f0b60..93802e49ca6 100644 --- a/apidocs/openapi.yaml +++ b/apidocs/openapi.yaml @@ -246,6 +246,10 @@ components: type: string clientOnly: type: boolean + webrtcHandshakeTimeout: + type: string + webrtcTrackGatherTimeout: + type: string # SRT server srt: diff --git a/internal/conf/conf.go b/internal/conf/conf.go index de97c2020b8..e70da0dcb93 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -238,6 +238,8 @@ type Conf struct { WebRTCIPsFromInterfacesList []string `json:"webrtcIPsFromInterfacesList"` WebRTCAdditionalHosts []string `json:"webrtcAdditionalHosts"` WebRTCICEServers2 WebRTCICEServers `json:"webrtcICEServers2"` + WebRTCHandshakeTimeout StringDuration `json:"webrtcHandshakeTimeout"` + WebRTCTrackGatherTimeout StringDuration `json:"webrtcTrackGatherTimeout"` WebRTCICEUDPMuxAddress *string `json:"webrtcICEUDPMuxAddress,omitempty"` // deprecated WebRTCICETCPMuxAddress *string `json:"webrtcICETCPMuxAddress,omitempty"` // deprecated WebRTCICEHostNAT1To1IPs *[]string `json:"webrtcICEHostNAT1To1IPs,omitempty"` // deprecated @@ -392,6 +394,8 @@ func (conf *Conf) setDefaults() { conf.WebRTCIPsFromInterfacesList = []string{} conf.WebRTCAdditionalHosts = []string{} conf.WebRTCICEServers2 = []WebRTCICEServer{} + conf.WebRTCHandshakeTimeout = 10 * StringDuration(time.Second) + conf.WebRTCTrackGatherTimeout = 2 * StringDuration(time.Second) // SRT server conf.SRT = true diff --git a/internal/core/core.go b/internal/core/core.go index 9f5f61353b6..1af8ec55cd9 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -580,6 +580,8 @@ func (p *Core) createResources(initial bool) error { IPsFromInterfacesList: p.conf.WebRTCIPsFromInterfacesList, AdditionalHosts: p.conf.WebRTCAdditionalHosts, ICEServers: p.conf.WebRTCICEServers2, + HandshakeTimeout: p.conf.WebRTCHandshakeTimeout, + TrackGatherTimeout: p.conf.WebRTCTrackGatherTimeout, ExternalCmdPool: p.externalCmdPool, PathManager: p.pathManager, Parent: p, diff --git a/internal/protocols/webrtc/peer_connection.go b/internal/protocols/webrtc/peer_connection.go index ca8b3165601..bb984fd77a2 100644 --- a/internal/protocols/webrtc/peer_connection.go +++ b/internal/protocols/webrtc/peer_connection.go @@ -11,13 +11,12 @@ import ( "github.com/pion/interceptor" "github.com/pion/webrtc/v3" + "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/logger" ) const ( - webrtcHandshakeTimeout = 10 * time.Second - webrtcTrackGatherTimeout = 2 * time.Second - webrtcStreamID = "mediamtx" + webrtcStreamID = "mediamtx" ) func stringInSlice(a string, list []string) bool { @@ -39,6 +38,8 @@ type PeerConnection struct { ICEServers []webrtc.ICEServer ICEUDPMux ice.UDPMux ICETCPMux ice.TCPMux + HandshakeTimeout conf.StringDuration + TrackGatherTimeout conf.StringDuration LocalRandomUDP bool IPsFromInterfaces bool IPsFromInterfacesList []string @@ -312,7 +313,7 @@ func (co *PeerConnection) WaitGatheringDone(ctx context.Context) error { func (co *PeerConnection) WaitUntilConnected( ctx context.Context, ) error { - t := time.NewTimer(webrtcHandshakeTimeout) + t := time.NewTimer(time.Duration(co.HandshakeTimeout)) defer t.Stop() outer: @@ -339,7 +340,7 @@ func (co *PeerConnection) GatherIncomingTracks( ) ([]*IncomingTrack, error) { var tracks []*IncomingTrack - t := time.NewTimer(webrtcTrackGatherTimeout) + t := time.NewTimer(time.Duration(co.TrackGatherTimeout)) defer t.Stop() for { diff --git a/internal/protocols/webrtc/peer_connection_test.go b/internal/protocols/webrtc/peer_connection_test.go index d4d0fa7cb60..b9ed8ba88c6 100644 --- a/internal/protocols/webrtc/peer_connection_test.go +++ b/internal/protocols/webrtc/peer_connection_test.go @@ -4,16 +4,19 @@ import ( "testing" "time" + "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/test" "github.com/stretchr/testify/require" ) func TestPeerConnectionCloseAfterError(t *testing.T) { pc := &PeerConnection{ - LocalRandomUDP: true, - IPsFromInterfaces: true, - Publish: false, - Log: test.NilLogger, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), + LocalRandomUDP: true, + IPsFromInterfaces: true, + Publish: false, + Log: test.NilLogger, } err := pc.Start() require.NoError(t, err) diff --git a/internal/protocols/webrtc/whip_client.go b/internal/protocols/webrtc/whip_client.go index 40511200c77..28c8cd0fc0a 100644 --- a/internal/protocols/webrtc/whip_client.go +++ b/internal/protocols/webrtc/whip_client.go @@ -13,10 +13,16 @@ import ( "github.com/pion/sdp/v3" "github.com/pion/webrtc/v3" + "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/protocols/httpp" ) +const ( + webrtcHandshakeTimeout = 10 * time.Second + webrtcTrackGatherTimeout = 2 * time.Second +) + // WHIPClient is a WHIP client. type WHIPClient struct { HTTPClient *http.Client @@ -48,12 +54,14 @@ func (c *WHIPClient) Publish( } c.pc = &PeerConnection{ - ICEServers: iceServers, - LocalRandomUDP: true, - IPsFromInterfaces: true, - Publish: true, - OutgoingTracks: outgoingTracks, - Log: c.Log, + ICEServers: iceServers, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), + LocalRandomUDP: true, + IPsFromInterfaces: true, + Publish: true, + OutgoingTracks: outgoingTracks, + Log: c.Log, } err = c.pc.Start() if err != nil { @@ -122,11 +130,13 @@ func (c *WHIPClient) Read(ctx context.Context) ([]*IncomingTrack, error) { } c.pc = &PeerConnection{ - ICEServers: iceServers, - LocalRandomUDP: true, - IPsFromInterfaces: true, - Publish: false, - Log: c.Log, + ICEServers: iceServers, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), + LocalRandomUDP: true, + IPsFromInterfaces: true, + Publish: false, + Log: c.Log, } err = c.pc.Start() if err != nil { diff --git a/internal/servers/webrtc/server.go b/internal/servers/webrtc/server.go index ba855eb64c2..a53920322a5 100644 --- a/internal/servers/webrtc/server.go +++ b/internal/servers/webrtc/server.go @@ -192,6 +192,8 @@ type Server struct { IPsFromInterfacesList []string AdditionalHosts []string ICEServers []conf.WebRTCICEServer + HandshakeTimeout conf.StringDuration + TrackGatherTimeout conf.StringDuration ExternalCmdPool *externalcmd.Pool PathManager serverPathManager Parent serverParent diff --git a/internal/servers/webrtc/server_test.go b/internal/servers/webrtc/server_test.go index 197917dba81..38727792bb4 100644 --- a/internal/servers/webrtc/server_test.go +++ b/internal/servers/webrtc/server_test.go @@ -117,6 +117,8 @@ func initializeTestServer(t *testing.T) *Server { IPsFromInterfacesList: []string{}, AdditionalHosts: []string{}, ICEServers: []conf.WebRTCICEServer{}, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), ExternalCmdPool: nil, PathManager: pathManager, Parent: test.NilLogger, @@ -195,9 +197,11 @@ func TestServerOptionsICEServer(t *testing.T) { Username: "myuser", Password: "mypass", }}, - ExternalCmdPool: nil, - PathManager: pathManager, - Parent: test.NilLogger, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), + ExternalCmdPool: nil, + PathManager: pathManager, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -249,6 +253,8 @@ func TestServerPublish(t *testing.T) { IPsFromInterfacesList: []string{}, AdditionalHosts: []string{}, ICEServers: []conf.WebRTCICEServer{}, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), ExternalCmdPool: nil, PathManager: pathManager, Parent: test.NilLogger, @@ -359,6 +365,8 @@ func TestServerRead(t *testing.T) { IPsFromInterfacesList: []string{}, AdditionalHosts: []string{}, ICEServers: []conf.WebRTCICEServer{}, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), ExternalCmdPool: nil, PathManager: pathManager, Parent: test.NilLogger, diff --git a/internal/servers/webrtc/session.go b/internal/servers/webrtc/session.go index cb98580da15..e921a4b098c 100644 --- a/internal/servers/webrtc/session.go +++ b/internal/servers/webrtc/session.go @@ -409,6 +409,8 @@ func (s *session) runPublish() (int, error) { pc := &webrtc.PeerConnection{ ICEServers: iceServers, + HandshakeTimeout: s.parent.HandshakeTimeout, + TrackGatherTimeout: s.parent.TrackGatherTimeout, IPsFromInterfaces: s.ipsFromInterfaces, IPsFromInterfacesList: s.ipsFromInterfacesList, AdditionalHosts: s.additionalHosts, @@ -566,6 +568,8 @@ func (s *session) runRead() (int, error) { pc := &webrtc.PeerConnection{ ICEServers: iceServers, + HandshakeTimeout: s.parent.HandshakeTimeout, + TrackGatherTimeout: s.parent.TrackGatherTimeout, IPsFromInterfaces: s.ipsFromInterfaces, IPsFromInterfacesList: s.ipsFromInterfacesList, AdditionalHosts: s.additionalHosts, diff --git a/internal/staticsources/webrtc/source_test.go b/internal/staticsources/webrtc/source_test.go index ef809dd3133..20edf3e752a 100644 --- a/internal/staticsources/webrtc/source_test.go +++ b/internal/staticsources/webrtc/source_test.go @@ -32,11 +32,13 @@ func TestSource(t *testing.T) { ChannelCount: 2, }}} pc := &webrtc.PeerConnection{ - LocalRandomUDP: true, - IPsFromInterfaces: true, - Publish: true, - OutgoingTracks: outgoingTracks, - Log: test.NilLogger, + LocalRandomUDP: true, + IPsFromInterfaces: true, + Publish: true, + HandshakeTimeout: conf.StringDuration(10 * time.Second), + TrackGatherTimeout: conf.StringDuration(2 * time.Second), + OutgoingTracks: outgoingTracks, + Log: test.NilLogger, } err := pc.Start() require.NoError(t, err) diff --git a/mediamtx.yml b/mediamtx.yml index cdc45cb05dc..29468381336 100644 --- a/mediamtx.yml +++ b/mediamtx.yml @@ -381,6 +381,10 @@ webrtcICEServers2: [] # username: '' # password: '' # clientOnly: false +# Time to wait for the WebRTC handshake to complete. +webrtcHandshakeTimeout: 10s +# Maximum time to gather video tracks. +webrtcTrackGatherTimeout: 2s ############################################### # Global settings -> SRT server