Publish and subscribe over wss://livekit.uni-wh.de:7800 and refuse cleartext ws://. Conference room is uwh-telhai. Includes the uncommitted encoded H.264 publish path, Rally hairpin, and KMS wall overlay.
74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
"""Hop energy gate so neighboring C920s do not publish bleed."""
|
|
import numpy as np
|
|
|
|
from audio_gate import HopGate, gate_enabled_for, rms_dbfs
|
|
|
|
|
|
def _sine(n=1600, amp=8000):
|
|
return (np.sin(2 * np.pi * 440 * np.arange(n) / 16000) * amp).astype(np.int16)
|
|
|
|
|
|
def test_rms_dbfs_silence_is_floor():
|
|
assert rms_dbfs(np.zeros(1600, dtype=np.int16)) <= -120.0
|
|
|
|
|
|
def test_rms_dbfs_sine_is_near_minus_15():
|
|
db = rms_dbfs(_sine())
|
|
assert -16.5 < db < -14.0
|
|
|
|
|
|
def test_gate_silences_quiet_hop():
|
|
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3)
|
|
quiet = (np.random.randn(1600) * 80).astype(np.int16)
|
|
out = g.apply(quiet)
|
|
assert int(np.max(np.abs(out))) == 0
|
|
assert g.open is False
|
|
|
|
|
|
def test_gate_passes_loud_hop():
|
|
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=3)
|
|
loud = _sine()
|
|
out = g.apply(loud)
|
|
assert int(np.max(np.abs(out))) > 1000
|
|
assert g.open is True
|
|
|
|
|
|
def test_gate_hold_then_closes():
|
|
g = HopGate(open_db=-32.0, close_db=-40.0, hold_hops=2)
|
|
g.apply(_sine())
|
|
quiet = np.zeros(1600, dtype=np.int16)
|
|
assert int(np.max(np.abs(g.apply(quiet)))) == 0 or g.open is True
|
|
g.apply(quiet)
|
|
g.apply(quiet)
|
|
assert g.open is False
|
|
assert int(np.max(np.abs(g.apply(quiet)))) == 0
|
|
|
|
|
|
def test_gate_skips_rally():
|
|
assert gate_enabled_for("rally", "rally", True) is False
|
|
assert gate_enabled_for("cam-07", "rally", True) is True
|
|
assert gate_enabled_for("cam-07", "rally", False) is False
|
|
|
|
|
|
def test_cleaner_gates_quiet_after_dsp():
|
|
from audio_cleanup import AudioCleaner
|
|
c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1))
|
|
quiet = (np.random.randn(1600) * 80).astype(np.int16)
|
|
out = c.process(quiet)
|
|
assert out.shape == (1600,)
|
|
assert int(np.max(np.abs(out))) == 0
|
|
loud = _sine(1600, 8000)
|
|
out = c.process(loud)
|
|
assert int(np.max(np.abs(out))) > 1000
|
|
|
|
|
|
def test_cleaner_gate_uses_raw_energy_not_dsp_makeup():
|
|
"""Room floor ~-34 dBFS must stay closed even though DSP makeup is ~+3 dB."""
|
|
from audio_cleanup import AudioCleaner
|
|
c = AudioCleaner(mode="off", beamform="off", gate=HopGate(open_db=-32.0, close_db=-40.0, hold_hops=1))
|
|
# sine RMS -34 dBFS => amplitude ~924
|
|
floor = _sine(1600, 924)
|
|
assert -35.5 < rms_dbfs(floor) < -32.5
|
|
out = c.process(floor)
|
|
assert int(np.max(np.abs(out))) == 0
|