|
| 1 | +import os |
| 2 | +import wave |
| 3 | +import numpy as np |
| 4 | + |
| 5 | +from livekit.rtc import AudioProcessingModule, AudioFrame |
| 6 | + |
| 7 | +FIXTURES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures") |
| 8 | + |
| 9 | + |
| 10 | +def test_agc_modifies_audio(): |
| 11 | + num_channels = 1 |
| 12 | + |
| 13 | + input_wav = os.path.join(FIXTURES_DIR, "test_audio.wav") |
| 14 | + output_wav = os.path.join(FIXTURES_DIR, "test_processed.wav") |
| 15 | + |
| 16 | + apm = AudioProcessingModule(auto_gain_control=True) |
| 17 | + |
| 18 | + any_frame_modified = False |
| 19 | + |
| 20 | + with wave.open(input_wav, "rb") as wf_in: |
| 21 | + assert wf_in.getnchannels() == num_channels, "Input file must be mono." |
| 22 | + sample_rate = wf_in.getframerate() |
| 23 | + sampwidth = wf_in.getsampwidth() |
| 24 | + frames_per_chunk = sample_rate // 100 |
| 25 | + |
| 26 | + with wave.open(output_wav, "wb") as wf_out: |
| 27 | + wf_out.setnchannels(num_channels) |
| 28 | + wf_out.setsampwidth(sampwidth) |
| 29 | + wf_out.setframerate(sample_rate) |
| 30 | + |
| 31 | + while True: |
| 32 | + raw_bytes = wf_in.readframes(frames_per_chunk) |
| 33 | + if not raw_bytes: |
| 34 | + break |
| 35 | + |
| 36 | + data = np.frombuffer(raw_bytes, dtype=np.int16) |
| 37 | + if len(data) < frames_per_chunk: |
| 38 | + data = np.pad(data, (0, frames_per_chunk - len(data))) |
| 39 | + |
| 40 | + original = data.copy() |
| 41 | + |
| 42 | + frame = AudioFrame( |
| 43 | + data=data.tobytes(), |
| 44 | + sample_rate=sample_rate, |
| 45 | + num_channels=num_channels, |
| 46 | + samples_per_channel=frames_per_chunk, |
| 47 | + ) |
| 48 | + |
| 49 | + apm.process_stream(frame) |
| 50 | + |
| 51 | + processed = np.frombuffer(frame.data, dtype=np.int16) |
| 52 | + if not np.array_equal(original, processed): |
| 53 | + any_frame_modified = True |
| 54 | + |
| 55 | + wf_out.writeframes(frame.data.tobytes()) |
| 56 | + |
| 57 | + assert any_frame_modified, ( |
| 58 | + "APM did not modify any audio frames — processing may be a no-op. " |
| 59 | + "With AGC enabled, output should differ from input." |
| 60 | + ) |
0 commit comments