diff --git a/pkg/config/config.go b/pkg/config/config.go index d00ae8060..ce0c0ebf8 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -146,7 +146,7 @@ func NewConfig(confString string, c *cli.Context) (*Config, error) { ActiveLevel: 30, // -30dBov = 0.03 MinPercentile: 40, UpdateInterval: 500, - SmoothIntervals: 4, + SmoothIntervals: 2, }, Redis: RedisConfig{}, Room: RoomConfig{ diff --git a/pkg/rtc/audiolevel.go b/pkg/rtc/audiolevel.go index bb8f5acae..803ab6ea6 100644 --- a/pkg/rtc/audiolevel.go +++ b/pkg/rtc/audiolevel.go @@ -6,8 +6,8 @@ import ( ) const ( - // number of audio frames for observe window - observeFrames = 25 // webrtc default opus frame size 20ms, 25*20=500ms matching default UpdateInterval + // duration of audio frames for observe window + observeDuration = 500 // ms silentAudioLevel = 127 ) @@ -15,49 +15,48 @@ const ( type AudioLevel struct { levelThreshold uint8 currentLevel uint32 - // min frames to be considered active - minActiveFrames uint32 + // min duration to be considered active + minActiveDuration uint32 // for Observe goroutine use // keeps track of current activity - observeLevel uint8 - activeFrames uint32 - numFrames uint32 + observeLevel uint8 + activeDuration uint32 // ms + observedDuration uint32 // ms } func NewAudioLevel(activeLevel uint8, minPercentile uint8) *AudioLevel { l := &AudioLevel{ - levelThreshold: activeLevel, - minActiveFrames: uint32(minPercentile) * observeFrames / 100, - currentLevel: silentAudioLevel, - observeLevel: silentAudioLevel, + levelThreshold: activeLevel, + minActiveDuration: uint32(minPercentile) * observeDuration / 100, + currentLevel: silentAudioLevel, + observeLevel: silentAudioLevel, } return l } // Observes a new frame, must be called from the same thread -func (l *AudioLevel) Observe(level uint8) { - l.numFrames++ +func (l *AudioLevel) Observe(level uint8, durationMs uint32) { + l.observedDuration += durationMs if level <= l.levelThreshold { - l.activeFrames++ + l.activeDuration += durationMs if l.observeLevel > level { l.observeLevel = level } } - if l.numFrames >= observeFrames { + if l.observedDuration >= observeDuration { // compute and reset - if l.activeFrames >= l.minActiveFrames { - const invObserveFrames = 1.0 / observeFrames - level := uint32(l.observeLevel) - uint32(20*math.Log10(float64(l.activeFrames)*invObserveFrames)) + if l.activeDuration >= l.minActiveDuration { + level := uint32(l.observeLevel) - uint32(20*math.Log10(float64(l.activeDuration)/float64(observeDuration))) atomic.StoreUint32(&l.currentLevel, level) } else { atomic.StoreUint32(&l.currentLevel, silentAudioLevel) } l.observeLevel = silentAudioLevel - l.activeFrames = 0 - l.numFrames = 0 + l.activeDuration = 0 + l.observedDuration = 0 } } diff --git a/pkg/rtc/audiolevel_test.go b/pkg/rtc/audiolevel_test.go index a2d7a1b2f..fefc9d40a 100644 --- a/pkg/rtc/audiolevel_test.go +++ b/pkg/rtc/audiolevel_test.go @@ -60,6 +60,6 @@ func TestAudioLevel(t *testing.T) { func observeSamples(a *rtc.AudioLevel, level uint8, count int) { for i := 0; i < count; i++ { - a.Observe(level) + a.Observe(level, 20) } } diff --git a/pkg/rtc/mediatrack.go b/pkg/rtc/mediatrack.go index 67c9af147..d27df1e40 100644 --- a/pkg/rtc/mediatrack.go +++ b/pkg/rtc/mediatrack.go @@ -344,8 +344,8 @@ func (t *MediaTrack) AddReceiver(receiver *webrtc.RTPReceiver, track *webrtc.Tra if t.Kind() == livekit.TrackType_AUDIO { t.audioLevel = NewAudioLevel(t.params.AudioConfig.ActiveLevel, t.params.AudioConfig.MinPercentile) - buff.OnAudioLevel(func(level uint8) { - t.audioLevel.Observe(level) + buff.OnAudioLevel(func(level uint8, duration uint32) { + t.audioLevel.Observe(level, duration) }) } else if t.Kind() == livekit.TrackType_VIDEO { if twcc != nil { diff --git a/pkg/sfu/buffer/buffer.go b/pkg/sfu/buffer/buffer.go index e697e5fcb..f2fa2ba2f 100644 --- a/pkg/sfu/buffer/buffer.go +++ b/pkg/sfu/buffer/buffer.go @@ -88,7 +88,7 @@ type Buffer struct { // callbacks onClose func() - onAudioLevel func(level uint8) + onAudioLevel func(level uint8, durationMs uint32) feedbackCB func([]rtcp.Packet) feedbackTWCC func(sn uint16, timeNS int64, marker bool) @@ -386,7 +386,10 @@ func (b *Buffer) calc(pkt []byte, arrivalTime int64) { if e := p.GetExtension(b.audioExt); e != nil && b.onAudioLevel != nil { ext := rtp.AudioLevelExtension{} if err := ext.Unmarshal(e); err == nil { - b.onAudioLevel(ext.Level) + duration := (int64(p.Timestamp) - int64(latestTimestamp)) * 1e3 / int64(b.clockRate) + if duration > 0 { + b.onAudioLevel(ext.Level, uint32(duration)) + } } } } @@ -607,7 +610,7 @@ func (b *Buffer) OnFeedback(fn func(fb []rtcp.Packet)) { b.feedbackCB = fn } -func (b *Buffer) OnAudioLevel(fn func(level uint8)) { +func (b *Buffer) OnAudioLevel(fn func(level uint8, durationMs uint32)) { b.onAudioLevel = fn }