aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/video-audio-recording-capture.el24
-rw-r--r--tests/test-video-audio-recording--build-audio-command.el13
-rw-r--r--tests/test-video-audio-recording-command-structure.el6
-rw-r--r--tests/test-video-audio-recording-ffmpeg-functions.el6
4 files changed, 29 insertions, 20 deletions
diff --git a/modules/video-audio-recording-capture.el b/modules/video-audio-recording-capture.el
index 069975bc..ea0d687c 100644
--- a/modules/video-audio-recording-capture.el
+++ b/modules/video-audio-recording-capture.el
@@ -229,7 +229,12 @@ On X11: ffmpeg captures screen directly via x11grab with PulseAudio audio."
(defun cj/recording--build-audio-command (mic-device system-device filename)
"Build the ffmpeg shell command string for audio-only recording.
MIC-DEVICE and SYSTEM-DEVICE are PulseAudio device names. FILENAME is
-the output .m4a path. Mixes mic + system monitor into a single AAC file."
+the output .flac path. Mixes mic + system monitor into a single lossless
+FLAC file. FLAC is used instead of AAC/M4A for two reasons: it is
+lossless (no encoder-quality loss, which matters for transcription
+accuracy), and its frames are self-contained so an abruptly stopped
+recording is still decodable -- unlike MP4, which needs a moov trailer
+written at close."
(format (concat "ffmpeg "
"-f pulse -i %s " ; Input 0: microphone
"-f pulse -i %s " ; Input 1: system audio monitor
@@ -238,8 +243,7 @@ the output .m4a path. Mixes mic + system monitor into a single AAC file."
"[1:a]volume=%.1f[sys];"
"[mic][sys]amix=inputs=2:duration=longest[out]\" "
"-map \"[out]\" "
- "-c:a aac "
- "-b:a 64k "
+ "-c:a flac "
"%s")
(shell-quote-argument mic-device)
(shell-quote-argument system-device)
@@ -287,10 +291,10 @@ Uses wf-recorder on Wayland, x11grab on X11."
(defun cj/ffmpeg-record-audio (directory)
"Start an audio recording, saving output to DIRECTORY.
Records from microphone and system audio monitor (configured device),
-mixing them together into a single M4A/AAC file.
+mixing them together into a single lossless FLAC file.
The filter graph mixes two PulseAudio inputs:
- [mic] → volume boost → amerge → AAC encoder → .m4a
+ [mic] → volume boost → amix → FLAC encoder → .flac
[sys] → volume boost ↗"
(cj/recording-check-ffmpeg)
(unless cj/audio-recording-ffmpeg-process
@@ -299,7 +303,7 @@ The filter graph mixes two PulseAudio inputs:
(system-device (cdr devices))
(location (expand-file-name directory))
(name (format-time-string "%Y-%m-%d-%H-%M-%S"))
- (filename (expand-file-name (concat name ".m4a") location))
+ (filename (expand-file-name (concat name ".flac") location))
(ffmpeg-command
(cj/recording--build-audio-command mic-device system-device filename)))
(message "Recording from mic: %s + ALL system outputs" mic-device)
@@ -370,7 +374,7 @@ for ffmpeg to write container metadata before giving up."
(defun cj/audio-recording-stop ()
"Stop the audio recording, waiting for ffmpeg to finalize the file.
Sends SIGINT to the process group and waits up to 3 seconds for ffmpeg
-to flush audio frames and write the M4A container trailer."
+to flush audio frames and finalize the FLAC stream."
(interactive)
(if (not cj/audio-recording-ffmpeg-process)
(message "No audio recording in progress.")
@@ -379,8 +383,10 @@ to flush audio frames and write the M4A container trailer."
(let ((pid (process-id proc)))
(when pid
(signal-process (- pid) 2)))
- ;; M4A finalization is faster than MKV, but still needs time to write
- ;; the AAC trailer and flush the output buffer.
+ ;; On a clean stop ffmpeg seeks back and backfills the FLAC STREAMINFO
+ ;; (total samples, MD5) so duration reads correctly. Even a hard
+ ;; truncation leaves a decodable file, since FLAC frames are
+ ;; self-contained -- there is no end-of-file trailer to miss.
(let ((exited (cj/recording--wait-for-exit proc 3)))
(unless exited
(message "Warning: recording process did not exit within 3 seconds")))
diff --git a/tests/test-video-audio-recording--build-audio-command.el b/tests/test-video-audio-recording--build-audio-command.el
index 54e5f56c..9577899b 100644
--- a/tests/test-video-audio-recording--build-audio-command.el
+++ b/tests/test-video-audio-recording--build-audio-command.el
@@ -3,8 +3,8 @@
;;; Commentary:
;; Unit tests for cj/recording--build-audio-command.
;; Verifies correct ffmpeg command construction for audio-only recording
-;; (mic + system monitor mixed to M4A/AAC), including shell quoting of
-;; device names and output paths.
+;; (mic + system monitor mixed to lossless FLAC), including shell quoting
+;; of device names and output paths.
;;; Code:
@@ -19,14 +19,17 @@
;;; Normal Cases
(ert-deftest test-video-audio-recording--build-audio-command-normal-uses-ffmpeg-pulse ()
- "Normal: audio command uses ffmpeg with two PulseAudio inputs mixed to AAC."
+ "Normal: audio command uses ffmpeg with two PulseAudio inputs mixed to FLAC."
(let ((cj/recording-mic-boost 2.0)
(cj/recording-system-volume 1.0))
- (let ((cmd (cj/recording--build-audio-command "mic" "sys" "/tmp/out.m4a")))
+ (let ((cmd (cj/recording--build-audio-command "mic" "sys" "/tmp/out.flac")))
(should (string-match-p "ffmpeg" cmd))
(should (string-match-p "-f pulse -i" cmd))
(should (string-match-p "amix=inputs=2" cmd))
- (should (string-match-p "-c:a aac" cmd)))))
+ (should (string-match-p "-c:a flac" cmd))
+ ;; Lossless: no lossy bitrate cap should be emitted.
+ (should-not (string-match-p "-b:a" cmd))
+ (should-not (string-match-p "-c:a aac" cmd)))))
(ert-deftest test-video-audio-recording--build-audio-command-normal-devices-in-command ()
"Normal: both mic and system device names appear in the command."
diff --git a/tests/test-video-audio-recording-command-structure.el b/tests/test-video-audio-recording-command-structure.el
index f4c24c39..41bd3b6a 100644
--- a/tests/test-video-audio-recording-command-structure.el
+++ b/tests/test-video-audio-recording-command-structure.el
@@ -260,8 +260,8 @@
(should (string-match-p "-f pulse" command))))
(test-command-structure-teardown)))
-(ert-deftest test-audio-recording-command-outputs-m4a ()
- "Test that audio recording outputs to .m4a file."
+(ert-deftest test-audio-recording-command-outputs-flac ()
+ "Test that audio recording outputs to .flac file."
(test-command-structure-setup)
(unwind-protect
(let ((command nil))
@@ -272,7 +272,7 @@
((symbol-function 'cj/recording--validate-system-audio)
(lambda () nil)))
(cj/ffmpeg-record-audio audio-recordings-dir)
- (should (string-match-p "\\.m4a" command))))
+ (should (string-match-p "\\.flac" command))))
(test-command-structure-teardown)))
;;; Common Command Structure (Both Video and Audio)
diff --git a/tests/test-video-audio-recording-ffmpeg-functions.el b/tests/test-video-audio-recording-ffmpeg-functions.el
index 4b3570a2..3a38d00a 100644
--- a/tests/test-video-audio-recording-ffmpeg-functions.el
+++ b/tests/test-video-audio-recording-ffmpeg-functions.el
@@ -164,8 +164,8 @@
(should update-called)))
(test-ffmpeg-teardown)))
-(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-creates-m4a-file ()
- "Test that audio recording creates .m4a file."
+(ert-deftest test-video-audio-recording-ffmpeg-record-audio-normal-creates-flac-file ()
+ "Test that audio recording creates .flac file."
(test-ffmpeg-setup)
(unwind-protect
(let ((command nil))
@@ -176,7 +176,7 @@
((symbol-function 'cj/recording--validate-system-audio)
(lambda () nil)))
(cj/ffmpeg-record-audio audio-recordings-dir)
- (should (string-match-p "\\.m4a" command))))
+ (should (string-match-p "\\.flac" command))))
(test-ffmpeg-teardown)))
;;; Stop Functions - Normal Cases