mirror of
https://github.com/livekit/livekit.git
synced 2026-07-28 18:39:41 +00:00
* Fix issue #159 use timestamp for AudeioLevel observer change smoothinterval default to 2 for more sensitive
This commit is contained in:
@@ -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{
|
||||
|
||||
+19
-20
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user