mirror of
https://github.com/livekit/livekit.git
synced 2026-03-29 09:19:53 +00:00
Set up audio config in audio level module when config is updated. (#4290)
* Set up audio config in audio level module when config is updated. It is possible to get audio config after bind (bind is where the audio level module is created) for remote tracks. So, split out setting audio level config in audio level module and invoke it when config is updated. * coderabbit review * prevent divide-by-0 * not active before config
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user