Repository navigation
Implement the voice-enhancement audio filter (#652) - #671
Merged
Merged
Conversation
The per-stream voice-enhancement opt-in (discussion #395) was stored and plumbed to the audio transcoder but did nothing. Build a libavfilter graph lazily from the first decoded frame and run PCM audio through it before AAC encoding: abuffer -> highpass=f=100 x2 -> [lowpass=f=8000] -> [afftdn] -> aformat=s16:<rate> -> abuffersink The filtered S16 output feeds the encoder FIFO directly, bypassing swr. Toggling mid-recording builds the graph, or drains and frees it, on the next packet; the final flush drains the filter tail. Build/run failures log once and continue unfiltered. With the option off the existing path is unchanged. Passthrough (AAC/MP3/Opus/AC-3) audio is not filtered. - CMake: ENABLE_AUDIO_FILTERS (default ON when libavfilter is found) and ENABLE_AUDIO_DENOISE (afftdn; OFF in the embedded profile). Builds without libavfilter log that the option is unavailable. - Detection-triggered recordings now pass the opt-in through too. - Add libavfilter-dev to Dockerfile, CI workflows and install docs; add libavfilter10/11 to the Debian package dependencies. - Update the UI help text (en/fil/ko) and document the feature in BUILD.md. - Tests: hum attenuation (>=20 dB at 50 Hz, voice band within 6 dB), exact sample accounting across all PCM formats, and live toggling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Unified detection thread coverage was effectively zero in CI: its two real-code tests were not in the coverage job. - test_udt_recording includes unified_detection_thread.c and drives real fixture packets plus synthetic G.711 through process_packet() against a temporary catalog with a healthy default storage target: detection-, external-trigger- and detection-stream-driven recording cycles with keep-alives, pre-buffer flush and start-time correction, per-codec audio setup (including the voice-enhancement opt-in), blocked placement, the stop fallback, multi-engine config and fan-out, the status/registry API, a real thread lifecycle against the fixture file, and shutdown cleanup. - test_audio_voice_filter_faults wraps the libavfilter/FIFO calls to force every voice-enhancement failure path and checks recording continues unfiltered without losing samples. - Run both, plus test_audio_voice_enhancement, test_detection_current_frame and test_detection_io_recovery, in the coverage and sanitizer jobs. Locally: unified_detection_thread.c 26% -> 78.5% line coverage; all patch lines in mp4_writer_utils.c and unified_detection_thread.c are covered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #652.
Summary
The per-stream Voice Enhancement option (discussion #395) was saved and passed to the audio transcoder, but did nothing. With this PR it filters recorded audio while PCM is transcoded to AAC.
abuffer → highpass=f=100 ×2 → [lowpass=f=8000] → [afftdn=nr=12:nf=-40:tn=1] → aformat=s16:<rate> → abuffersink.Build and packaging
ENABLE_AUDIO_FILTERS(default ON when pkg-config findslibavfilter>=10). Without it the build still succeeds, and turning the option on logs that it is unavailable.ENABLE_AUDIO_DENOISEcontrols afftdn, the CPU-heavy stage. It defaults OFF in the embedded profile.libavfilter-devto the Dockerfile, the CI workflows and the install docs. The Debian package now depends onlibavfilter10(trixie) orlibavfilter11(sid).docs/BUILD.mdand the README describe the feature and the passthrough limitation. The UI help text (en/fil/ko) no longer says "no effect yet".Tests
New cases in
tests/unit/test_audio_transcoder.c:Validation (run locally against FFmpeg 8 / libavfilter 11):
ctestafter building all targets, in a Debug build with ASan/UBSan: 156/156 passed, no leaks reported.-DENABLE_AUDIO_FILTERS=OFF: compiles, does not link avfilter, tests pass, and the option logs that it is unavailable.-DENABLE_AUDIO_DENOISE=OFF: chain runs without afftdn, tests pass.Rollback
Revert this PR and the opt-in goes back to being a no-op.
🤖 Generated with Claude Code