diff --git a/audio.py b/audio.py index 39bceb2..0ef5038 100644 --- a/audio.py +++ b/audio.py @@ -27,6 +27,7 @@ CHANNELS = 1 SAMPLE_WIDTH = 2 # s16 CHUNK_FRAMES = 1024 CHUNK_BYTES = CHUNK_FRAMES * SAMPLE_WIDTH * CHANNELS +CHUNK_LATENCY_MS = round(CHUNK_FRAMES / RATE * 1000) MIN_FRAMES = int(RATE * 0.25) @@ -184,6 +185,12 @@ def recording_command(target=""): cmd = [ "parec", "--record", "--raw", f"--rate={RATE}", f"--channels={CHANNELS}", "--format=s16le", + # Left alone, parec holds about two seconds before handing anything + # over, and then hands over all of it at once: the level meter sits + # still and jumps, and the tail of a recording can be lost on the + # way out. A chunk of the meter is the unit the rest of this file + # is measured in, so ask for that. + f"--latency-msec={CHUNK_LATENCY_MS}", ] if target: cmd.append(f"--device={target}") diff --git a/tests/test_audio.py b/tests/test_audio.py index 52f2f54..7595d1b 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -243,6 +243,18 @@ class RecordingCommand(DikteTest): self.assertIn(str(audio.CHANNELS), joined) self.assertIn("s16", joined) + def test_parec_is_asked_for_the_level_meter_s_own_chunk(self): + """Left alone it buffers about two seconds, which the waveform shows as + a still bar that jumps once a second, and which can cost the tail of a + recording when the process is asked to stop.""" + with only_these_tools("parec"): + self.assertIn(f"--latency-msec={audio.CHUNK_LATENCY_MS}", + audio.recording_command()) + + def test_the_latency_asked_for_is_the_chunk_the_meter_reads(self): + self.assertEqual(audio.CHUNK_LATENCY_MS, + round(audio.CHUNK_FRAMES / audio.RATE * 1000)) + def test_a_chosen_microphone_reaches_either_one(self): with only_these_tools("parec"): self.assertIn("--device=alsa_input.usb", audio.recording_command(