fix: use the fast debounce for the first negotiation (#4936)

* fix: use the fast debounce for the first negotiation

A new transport set lastNegotiate to its creation time. A non-forced
Negotiate soon after creation then waited for the 150 ms debounce
instead of 10 ms, although nothing was negotiated yet. Start from the
zero time so that the first offer uses the fast debounce.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: check the first negotiation condition without a deadline

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: check that the first offer goes out before a debounced one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Raja Subramanian
2026-10-05 15:11:42 +05:30
committed by GitHub
co-authored by Claude Opus 5.5
parent 4c3f8432f5
commit af2959d2f8
2 changed files with 44 additions and 1 deletions
-1
View File
@@ -566,7 +566,6 @@ func NewPCTransport(params TransportParams) (*PCTransport, error) {
previousTrackDescription: make(map[string]*trackDescription),
canReuseTransceiver: true,
connectionDetails: types.NewICEConnectionDetails(params.Transport, params.Logger),
lastNegotiate: time.Now(),
}
t.localOfferId.Store(uint32(rand.Intn(1<<8) + 1))
+44
View File
@@ -207,6 +207,50 @@ func TestNegotiationTiming(t *testing.T) {
transportB.Close()
}
func TestFirstNegotiationUsesFastDebounce(t *testing.T) {
offered := make(chan string, 2)
newOfferer := func(name string) *PCTransport {
handler := &transportfakes.FakeHandler{}
handler.OnOfferCalls(func(webrtc.SessionDescription, uint32, map[string]string) error {
select {
case offered <- name:
default:
}
return nil
})
transport, err := NewPCTransport(TransportParams{
Config: &WebRTCConfig{},
IsOfferer: true,
Handler: handler,
})
require.NoError(t, err)
t.Cleanup(transport.Close)
_, err = transport.pc.CreateDataChannel(ReliableDataChannel, nil)
require.NoError(t, err)
return transport
}
// a transport that negotiated just now waits for the full debounce
recent := newOfferer("recent")
recent.lock.Lock()
recent.updateLastNegotiateLocked()
recent.lock.Unlock()
recent.Negotiate(false)
// a new transport starts later, but its first offer uses the fast debounce and goes out first
time.Sleep(20 * time.Millisecond)
newOfferer("fresh").Negotiate(false)
for _, want := range []string{"fresh", "recent"} {
select {
case got := <-offered:
require.Equal(t, want, got)
case <-time.After(5 * time.Second):
t.Fatalf("no offer from %s", want)
}
}
}
func TestFirstOfferMissedDuringICERestart(t *testing.T) {
params := TransportParams{
Config: &WebRTCConfig{},