diff --git a/pkg/sfu/audio/audiolevel.go b/pkg/sfu/audio/audiolevel.go index 5f56079fe..b97e0a4eb 100644 --- a/pkg/sfu/audio/audiolevel.go +++ b/pkg/sfu/audio/audiolevel.go @@ -51,13 +51,15 @@ var ( // -------------------------------------- type AudioLevelParams struct { - Config AudioLevelConfig ClockRate uint32 } // keeps track of audio level for a participant type AudioLevel struct { params AudioLevelParams + + config AudioLevelConfig + // min duration within an observe duration window to be considered active minActiveDuration uint32 smoothFactor float64 @@ -76,20 +78,26 @@ type AudioLevel struct { } func NewAudioLevel(params AudioLevelParams) *AudioLevel { - l := &AudioLevel{ + return &AudioLevel{ params: params, - minActiveDuration: uint32(params.Config.MinPercentile) * params.Config.UpdateInterval / 100, smoothFactor: 1, - activeThreshold: ConvertAudioLevel(float64(params.Config.ActiveLevel)), loudestObservedLevel: silentAudioLevel, } +} - if l.params.Config.SmoothIntervals > 0 { +func (l *AudioLevel) SetConfig(config AudioLevelConfig) { + l.lock.Lock() + defer l.lock.Unlock() + + l.config = config + l.minActiveDuration = uint32(l.config.MinPercentile) * l.config.UpdateInterval / 100 + if l.config.SmoothIntervals > 0 { // exponential moving average (EMA), same center of mass with simple moving average (SMA) - l.smoothFactor = float64(2) / (float64(l.params.Config.SmoothIntervals + 1)) + l.smoothFactor = float64(2) / (float64(l.config.SmoothIntervals + 1)) + } else { + l.smoothFactor = 1 } - - return l + l.activeThreshold = ConvertAudioLevel(float64(l.config.ActiveLevel)) } // Observes a new frame @@ -101,18 +109,22 @@ func (l *AudioLevel) Observe(level uint8, durationMs uint32, arrivalTime int64) } func (l *AudioLevel) observeLocked(level uint8, durationMs uint32, arrivalTime int64) { + if l.config.UpdateInterval == 0 { + return + } + l.lastObservedAt = arrivalTime l.observedDuration += durationMs - if level <= l.params.Config.ActiveLevel { + if level <= l.config.ActiveLevel { l.activeDuration += durationMs if l.loudestObservedLevel > level { l.loudestObservedLevel = level } } - if l.observedDuration >= l.params.Config.UpdateInterval { + if l.observedDuration >= l.config.UpdateInterval { smoothedLevel := float64(0.0) // compute and reset if l.activeDuration >= l.minActiveDuration { @@ -120,7 +132,7 @@ func (l *AudioLevel) observeLocked(level uint8, durationMs uint32, arrivalTime i // Weight will be 0 if active the entire duration // > 0 if active for longer than observe duration // < 0 if active for less than observe duration - activityWeight := 20 * math.Log10(float64(l.activeDuration)/float64(l.params.Config.UpdateInterval)) + activityWeight := 20 * math.Log10(float64(l.activeDuration)/float64(l.config.UpdateInterval)) adjustedLevel := float64(l.loudestObservedLevel) - activityWeight linearLevel := ConvertAudioLevel(adjustedLevel) @@ -153,13 +165,17 @@ func (l *AudioLevel) GetLevel(now int64) (float64, bool) { l.lock.Lock() defer l.lock.Unlock() + if l.config.UpdateInterval == 0 { + return 0.0, false + } + l.resetIfStaleLocked(now) return l.smoothedLevel, l.smoothedLevel >= l.activeThreshold } func (l *AudioLevel) resetIfStaleLocked(arrivalTime int64) { - if (arrivalTime-l.lastObservedAt)/1e6 < int64(2*l.params.Config.UpdateInterval) { + if (arrivalTime-l.lastObservedAt)/1e6 < int64(2*l.config.UpdateInterval) { return } diff --git a/pkg/sfu/audio/audiolevel_test.go b/pkg/sfu/audio/audiolevel_test.go index 81afd85e6..7876b287b 100644 --- a/pkg/sfu/audio/audiolevel_test.go +++ b/pkg/sfu/audio/audiolevel_test.go @@ -126,14 +126,15 @@ func TestAudioLevel(t *testing.T) { } func createAudioLevel(activeLevel uint8, minPercentile uint8, observeDuration uint32) *AudioLevel { - return NewAudioLevel(AudioLevelParams{ - Config: AudioLevelConfig{ - ActiveLevel: activeLevel, - MinPercentile: minPercentile, - UpdateInterval: observeDuration, - }, + al := NewAudioLevel(AudioLevelParams{ ClockRate: 48000, }) + al.SetConfig(AudioLevelConfig{ + ActiveLevel: activeLevel, + MinPercentile: minPercentile, + UpdateInterval: observeDuration, + }) + return al } func observeSamples(a *AudioLevel, level uint8, count int, baseTime time.Time) { diff --git a/pkg/sfu/buffer/buffer_base.go b/pkg/sfu/buffer/buffer_base.go index 55b7ede68..b288296d2 100644 --- a/pkg/sfu/buffer/buffer_base.go +++ b/pkg/sfu/buffer/buffer_base.go @@ -331,9 +331,9 @@ func (b *BufferBase) BindLocked(rtpParameters webrtc.RTPParameters, codec webrtc case sdp.AudioLevelURI: b.audioLevelExtID = uint8(ext.ID) b.audioLevel = audio.NewAudioLevel(audio.AudioLevelParams{ - Config: b.audioLevelConfig, ClockRate: b.clockRate, }) + b.audioLevel.SetConfig(b.audioLevelConfig) case act.AbsCaptureTimeURI: b.absCaptureTimeExtID = uint8(ext.ID) @@ -434,6 +434,9 @@ func (b *BufferBase) SetAudioLevelConfig(audioLevelConfig audio.AudioLevelConfig defer b.Unlock() b.audioLevelConfig = audioLevelConfig + if b.audioLevel != nil { + b.audioLevel.SetConfig(b.audioLevelConfig) + } } func (b *BufferBase) SetStreamRestartDetection(enable bool) { @@ -512,9 +515,9 @@ func (b *BufferBase) restartStreamLocked(reason string, isDetected bool) { if b.audioLevel != nil { b.audioLevel = audio.NewAudioLevel(audio.AudioLevelParams{ - Config: b.audioLevelConfig, ClockRate: b.clockRate, }) + b.audioLevel.SetConfig(b.audioLevelConfig) } if b.ddExtID != 0 {