Skip to content

Commit 758475a

Browse files
authored
Quantize offsets diffs (adding deadband) (#749)
* Quantize offsets diffs (adding deadband) Also reuse maxDriftAdjustment for start time adjustment instead of the constant * spelling
1 parent 7d2544c commit 758475a

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

pkg/synchronizer/track.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import (
3434
const (
3535
cStartTimeAdjustWindow = 2 * time.Minute
3636
cStartTimeAdjustThreshold = 5 * time.Second
37-
cStartTimeAdjustStep = 5 * time.Millisecond
3837

3938
cHighDriftLoggingThreshold = 20 * time.Millisecond
4039
)
@@ -646,6 +645,12 @@ func (t *TrackSynchronizer) shouldAdjustPTS() bool {
646645
if t.track.Kind() == webrtc.RTPCodecTypeAudio && !t.rtcpSenderReportRebaseEnabled {
647646
adjustmentEnabled = !t.audioPTSAdjustmentsDisabled
648647
}
648+
// add a deadband of t.maxDriftAdjustment to make sure no PTS adjustment is smaller than that
649+
diff := t.desiredPTSOffset - t.currentPTSOffset
650+
if diff > -t.maxDriftAdjustment && diff < t.maxDriftAdjustment {
651+
return false
652+
}
653+
649654
return adjustmentEnabled && (t.currentPTSOffset != t.desiredPTSOffset)
650655
}
651656

@@ -657,11 +662,11 @@ func (t *TrackSynchronizer) applyQuantizedStartTimeAdvance(deltaTotal time.Durat
657662
// include any prior residual
658663
deltaTotal += t.startTimeAdjustResidual
659664

660-
quanta := deltaTotal / cStartTimeAdjustStep
661-
residual := deltaTotal % cStartTimeAdjustStep
665+
quanta := deltaTotal / t.maxDriftAdjustment
666+
residual := deltaTotal % t.maxDriftAdjustment
662667

663668
if quanta > 0 {
664-
applied := quanta * cStartTimeAdjustStep
669+
applied := quanta * t.maxDriftAdjustment
665670
t.startTime = t.startTime.Add(-applied)
666671
t.totalStartTimeAdjustment += applied
667672
t.startTimeAdjustResidual = residual

pkg/synchronizer/track_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,86 @@ func TestGetPTSWithRebase_PropelsForward(t *testing.T) {
164164
require.NoError(t, err)
165165
require.Equal(t, want, adj2)
166166
}
167+
168+
func TestShouldAdjustPTS_Deadband_Suppresses(t *testing.T) {
169+
clock := uint32(48000)
170+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeVideo) // video avoids audio gating path
171+
ts.maxDriftAdjustment = 5 * time.Millisecond
172+
ts.currentPTSOffset = 100 * time.Millisecond
173+
174+
// within dead-band: +4ms
175+
ts.desiredPTSOffset = 104 * time.Millisecond
176+
177+
// ensure throttle window has elapsed
178+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
179+
180+
require.False(t, ts.shouldAdjustPTS(), "delta < step should suppress adjustment")
181+
}
182+
183+
func TestShouldAdjustPTS_Deadband_BoundaryAdjusts(t *testing.T) {
184+
clock := uint32(48000)
185+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeVideo)
186+
ts.maxDriftAdjustment = 5 * time.Millisecond
187+
ts.currentPTSOffset = 100 * time.Millisecond
188+
189+
// exactly at boundary: +5ms
190+
ts.desiredPTSOffset = 105 * time.Millisecond
191+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
192+
193+
require.True(t, ts.shouldAdjustPTS(), "delta == step should allow adjustment")
194+
}
195+
196+
func TestShouldAdjustPTS_Deadband_AboveAdjusts(t *testing.T) {
197+
clock := uint32(48000)
198+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeVideo)
199+
ts.maxDriftAdjustment = 5 * time.Millisecond
200+
ts.currentPTSOffset = 100 * time.Millisecond
201+
202+
// above dead-band: +12ms
203+
ts.desiredPTSOffset = 112 * time.Millisecond
204+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
205+
206+
require.True(t, ts.shouldAdjustPTS(), "delta > step should allow adjustment")
207+
}
208+
209+
func TestShouldAdjustPTS_Deadband_NegativeDelta_Suppresses(t *testing.T) {
210+
clock := uint32(48000)
211+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeVideo)
212+
ts.maxDriftAdjustment = 5 * time.Millisecond
213+
ts.currentPTSOffset = 100 * time.Millisecond
214+
215+
// within dead-band on negative side: -4ms
216+
ts.desiredPTSOffset = 96 * time.Millisecond
217+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
218+
219+
require.False(t, ts.shouldAdjustPTS(), "negative delta with |delta| < step should suppress adjustment")
220+
}
221+
222+
func TestShouldAdjustPTS_Deadband_NegativeDelta_AboveAdjusts(t *testing.T) {
223+
clock := uint32(48000)
224+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeVideo)
225+
ts.maxDriftAdjustment = 5 * time.Millisecond
226+
ts.currentPTSOffset = 100 * time.Millisecond
227+
228+
// beyond dead-band on negative side: -6ms
229+
ts.desiredPTSOffset = 94 * time.Millisecond
230+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
231+
232+
require.True(t, ts.shouldAdjustPTS(), "negative delta with |delta| > step should allow adjustment")
233+
}
234+
235+
func TestShouldAdjustPTS_AudioGating_DisabledBlocks(t *testing.T) {
236+
clock := uint32(48000)
237+
ts := newTSForTests(t, clock, webrtc.RTPCodecTypeAudio)
238+
239+
// Force the path where audio gating can block adjustments:
240+
ts.rtcpSenderReportRebaseEnabled = false
241+
ts.audioPTSAdjustmentsDisabled = true
242+
243+
ts.maxDriftAdjustment = 5 * time.Millisecond
244+
ts.currentPTSOffset = 100 * time.Millisecond
245+
ts.desiredPTSOffset = 140 * time.Millisecond // large delta
246+
ts.nextPTSAdjustmentAt = mono.Now().Add(-time.Second)
247+
248+
require.False(t, ts.shouldAdjustPTS(), "audio gating should block adjustment when disabled")
249+
}

0 commit comments

Comments
 (0)