Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit aa6625c

Browse files
authored
perf: Reduce RTC connection times (#341)
1 parent f44c5ca commit aa6625c

File tree

3 files changed

+49
-9
lines changed

3 files changed

+49
-9
lines changed

wsnet/dial.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,16 @@ func (d *Dialer) negotiate() (err error) {
113113

114114
go func() {
115115
defer close(errCh)
116-
err := waitForDataChannelOpen(context.Background(), d.ctrl)
116+
err := waitForConnectionOpen(context.Background(), d.rtc)
117117
if err != nil {
118118
_ = d.conn.Close()
119119
errCh <- err
120120
return
121121
}
122-
d.ctrlrw, err = d.ctrl.Detach()
123-
if err != nil {
124-
errCh <- err
125-
}
126-
_ = d.conn.Close()
122+
go func() {
123+
// Closing this connection took 30ms+.
124+
_ = d.conn.Close()
125+
}()
127126
}()
128127

129128
for {
@@ -179,7 +178,20 @@ func (d *Dialer) Close() error {
179178

180179
// Ping sends a ping through the control channel.
181180
func (d *Dialer) Ping(ctx context.Context) error {
182-
_, err := d.ctrlrw.Write([]byte{'a'})
181+
// Since we control the client and server we could open this
182+
// data channel with `Negotiated` true to reduce traffic being
183+
// sent when the RTC connection is opened.
184+
err := waitForDataChannelOpen(context.Background(), d.ctrl)
185+
if err != nil {
186+
return err
187+
}
188+
if d.ctrlrw == nil {
189+
d.ctrlrw, err = d.ctrl.Detach()
190+
if err != nil {
191+
return err
192+
}
193+
}
194+
_, err = d.ctrlrw.Write([]byte{'a'})
183195
if err != nil {
184196
return fmt.Errorf("write: %w", err)
185197
}

wsnet/listen.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func (l *listener) dial(ctx context.Context) (<-chan error, error) {
103103
// Negotiates the handshake protocol over the connection provided.
104104
// This functions control-flow is important to readability,
105105
// so the cognitive overload linter has been disabled.
106-
// nolint:gocognit
106+
// nolint:gocognit,nestif
107107
func (l *listener) negotiate(conn net.Conn) {
108108
var (
109109
err error
@@ -172,11 +172,17 @@ func (l *listener) negotiate(conn net.Conn) {
172172
closeError(err)
173173
return
174174
}
175+
rtc.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
176+
if pcs == webrtc.PeerConnectionStateConnecting {
177+
return
178+
}
179+
_ = conn.Close()
180+
})
181+
flushCandidates := proxyICECandidates(rtc, conn)
175182
l.connClosersMut.Lock()
176183
l.connClosers = append(l.connClosers, rtc)
177184
l.connClosersMut.Unlock()
178185
rtc.OnDataChannel(l.handle)
179-
flushCandidates := proxyICECandidates(rtc, conn)
180186
err = rtc.SetRemoteDescription(*msg.Offer)
181187
if err != nil {
182188
closeError(fmt.Errorf("apply offer: %w", err))

wsnet/rtc.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ func dialICEURL(server webrtc.ICEServer, rawURL string, options *DialICEOptions)
155155
// Generalizes creating a new peer connection with consistent options.
156156
func newPeerConnection(servers []webrtc.ICEServer) (*webrtc.PeerConnection, error) {
157157
se := webrtc.SettingEngine{}
158+
se.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeUDP4})
159+
se.SetSrflxAcceptanceMinWait(0)
158160
se.DetachDataChannels()
159161
se.SetICETimeouts(time.Second*5, time.Second*5, time.Second*2)
160162

@@ -165,6 +167,7 @@ func newPeerConnection(servers []webrtc.ICEServer) (*webrtc.PeerConnection, erro
165167
if server.Credential != nil && len(server.URLs) == 1 {
166168
url, err := ice.ParseURL(server.URLs[0])
167169
if err == nil && url.Proto == ice.ProtoTypeTCP {
170+
se.SetNetworkTypes([]webrtc.NetworkType{webrtc.NetworkTypeTCP4, webrtc.NetworkTypeTCP6})
168171
se.SetRelayAcceptanceMinWait(0)
169172
}
170173
}
@@ -213,6 +216,25 @@ func proxyICECandidates(conn *webrtc.PeerConnection, w io.Writer) func() {
213216
}
214217
}
215218

219+
// Waits for a PeerConnection to hit the open state.
220+
func waitForConnectionOpen(ctx context.Context, conn *webrtc.PeerConnection) error {
221+
if conn.ConnectionState() == webrtc.PeerConnectionStateConnected {
222+
return nil
223+
}
224+
ctx, cancelFunc := context.WithTimeout(ctx, time.Second*15)
225+
defer cancelFunc()
226+
conn.OnConnectionStateChange(func(pcs webrtc.PeerConnectionState) {
227+
if pcs == webrtc.PeerConnectionStateConnected {
228+
cancelFunc()
229+
}
230+
})
231+
<-ctx.Done()
232+
if ctx.Err() == context.DeadlineExceeded {
233+
return ctx.Err()
234+
}
235+
return nil
236+
}
237+
216238
// Waits for a DataChannel to hit the open state.
217239
func waitForDataChannelOpen(ctx context.Context, channel *webrtc.DataChannel) error {
218240
if channel.ReadyState() == webrtc.DataChannelStateOpen {

0 commit comments

Comments
 (0)