mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 14:55:37 +00:00
fix(recording): normalize native Windows mic loudness
This commit is contained in:
@@ -69,6 +69,32 @@ describe("getAudioSyncAdjustment", () => {
|
||||
"[1:a]apad=pad_dur=120.000,aresample=async=1:first_pts=0,asetpts=PTS-STARTPTS[aout]",
|
||||
]);
|
||||
});
|
||||
|
||||
it("can add a small gain boost before resampling", () => {
|
||||
const filterParts: string[] = [];
|
||||
appendSyncedAudioFilter(
|
||||
filterParts,
|
||||
"[1:a]",
|
||||
"aout",
|
||||
getAudioSyncAdjustment(120, 120),
|
||||
1.4,
|
||||
);
|
||||
|
||||
expect(filterParts).toEqual([
|
||||
"[1:a]volume=1.400,aresample=async=1:first_pts=0,asetpts=PTS-STARTPTS[aout]",
|
||||
]);
|
||||
});
|
||||
|
||||
it("can prepend mic normalization filters before sync handling", () => {
|
||||
const filterParts: string[] = [];
|
||||
appendSyncedAudioFilter(filterParts, "[1:a]", "aout", getAudioSyncAdjustment(120, 120), {
|
||||
preFilters: ["loudnorm=I=-16:TP=-1.5:LRA=11"],
|
||||
});
|
||||
|
||||
expect(filterParts).toEqual([
|
||||
"[1:a]loudnorm=I=-16:TP=-1.5:LRA=11,aresample=async=1:first_pts=0,asetpts=PTS-STARTPTS[aout]",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyRecordedAudioStartDelay", () => {
|
||||
|
||||
@@ -102,8 +102,12 @@ export function appendSyncedAudioFilter(
|
||||
inputLabel: string,
|
||||
outputLabel: string,
|
||||
adjustment: AudioSyncAdjustment,
|
||||
options: number | { volumeMultiplier?: number; preFilters?: string[] } = 1,
|
||||
) {
|
||||
const filters: string[] = [];
|
||||
const volumeMultiplier =
|
||||
typeof options === "number" ? options : (options.volumeMultiplier ?? 1);
|
||||
const preFilters = typeof options === "number" ? [] : (options.preFilters ?? []);
|
||||
const filters: string[] = [...preFilters];
|
||||
|
||||
if (adjustment.mode === "delay" && adjustment.delayMs > 0) {
|
||||
filters.push(`adelay=${adjustment.delayMs}|${adjustment.delayMs}`);
|
||||
@@ -117,6 +121,14 @@ export function appendSyncedAudioFilter(
|
||||
filters.push(`apad=pad_dur=${formatFfmpegSeconds(adjustment.durationDeltaMs)}`);
|
||||
}
|
||||
|
||||
if (
|
||||
Number.isFinite(volumeMultiplier) &&
|
||||
volumeMultiplier > 0 &&
|
||||
Math.abs(volumeMultiplier - 1) > 0.0005
|
||||
) {
|
||||
filters.push(`volume=${volumeMultiplier.toFixed(3)}`);
|
||||
}
|
||||
|
||||
filters.push("aresample=async=1:first_pts=0", "asetpts=PTS-STARTPTS");
|
||||
filterParts.push(`${inputLabel}${filters.join(",")}[${outputLabel}]`);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ import {
|
||||
import { emitRecordingInterrupted } from "./events";
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
// Match the browser path's "usable speech level" intent with a standard
|
||||
// loudness pass on native Windows mic audio instead of a fixed tiny boost.
|
||||
const WINDOWS_NATIVE_MIC_PRE_FILTERS = ["loudnorm=I=-16:TP=-1.5:LRA=11"];
|
||||
|
||||
export async function isNativeWindowsCaptureAvailable(): Promise<boolean> {
|
||||
if (process.platform !== "win32") return false;
|
||||
@@ -266,7 +269,9 @@ export async function muxNativeWindowsVideoWithAudio(
|
||||
const micLabel = micPauseFilter ? "[mic_trimmed]" : "[2:a]";
|
||||
|
||||
appendSyncedAudioFilter(filterParts, systemLabel, "s", systemAdjustment);
|
||||
appendSyncedAudioFilter(filterParts, micLabel, "m", micAdjustment);
|
||||
appendSyncedAudioFilter(filterParts, micLabel, "m", micAdjustment, {
|
||||
preFilters: WINDOWS_NATIVE_MIC_PRE_FILTERS,
|
||||
});
|
||||
filterParts.push("[s][m]amix=inputs=2:duration=longest:normalize=0[aout]");
|
||||
|
||||
await execFileAsync(
|
||||
@@ -312,7 +317,13 @@ export async function muxNativeWindowsVideoWithAudio(
|
||||
filterParts.push(pauseFilter);
|
||||
}
|
||||
const srcLabel = pauseFilter ? "[trimmed_audio]" : "[1:a]";
|
||||
appendSyncedAudioFilter(filterParts, srcLabel, "aout", singleAdjustment);
|
||||
appendSyncedAudioFilter(
|
||||
filterParts,
|
||||
srcLabel,
|
||||
"aout",
|
||||
singleAdjustment,
|
||||
audioInputs[0] === "mic" ? { preFilters: WINDOWS_NATIVE_MIC_PRE_FILTERS } : 1,
|
||||
);
|
||||
|
||||
await execFileAsync(
|
||||
ffmpegPath,
|
||||
|
||||
Reference in New Issue
Block a user