diff --git a/src/lib/exporter/audioProcessorShared.ts b/src/lib/exporter/audioProcessorShared.ts index a48062a7..261615df 100644 --- a/src/lib/exporter/audioProcessorShared.ts +++ b/src/lib/exporter/audioProcessorShared.ts @@ -5,7 +5,8 @@ import type { SourceAudioTrackSettings, TrimRegion, } from "@/components/video-editor/types"; -import type { SourceTrackId } from "@/lib/exporter/audioRoutingEngine"; + +export type SourceTrackId = "mic" | "system" | "mixed"; export const AUDIO_BITRATE = 128_000; export const DECODE_BACKPRESSURE_LIMIT = 20; diff --git a/src/lib/exporter/audioRoutingEngine.test.ts b/src/lib/exporter/audioRoutingEngine.test.ts new file mode 100644 index 00000000..a915c787 --- /dev/null +++ b/src/lib/exporter/audioRoutingEngine.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from "vitest"; +import { buildResolvedAudioPlan, getSourceTrackIdFromPath } from "./audioRoutingEngine"; + +describe("getSourceTrackIdFromPath", () => { + it.each([ + ["/recordings/recording-mic.wav", "mic"], + ["/recordings/recording-system.wav", "system"], + ["/recordings/system.mp4", "system"], + ["/recordings/mic.wav", "mic"], + ])("classifies companion path %s as %s", (path, trackId) => { + expect(getSourceTrackIdFromPath(path)).toBe(trackId); + }); + + it("routes mic and system companions onto their dedicated playback tracks", () => { + const plan = buildResolvedAudioPlan({ + videoResource: "/recordings/recording.mp4", + sourceAudioFallbackPaths: [ + "/recordings/recording.mp4", + "/recordings/recording-mic.wav", + "/recordings/system.mp4", + ], + }); + + expect(plan.pathsByTrack).toEqual({ + mic: "/recordings/recording-mic.wav", + system: "/recordings/system.mp4", + }); + expect(plan.playbackPaths).toEqual([ + "/recordings/system.mp4", + "/recordings/recording-mic.wav", + ]); + }); +}); diff --git a/src/lib/exporter/audioRoutingEngine.ts b/src/lib/exporter/audioRoutingEngine.ts index 8f9c7421..7bf618ea 100644 --- a/src/lib/exporter/audioRoutingEngine.ts +++ b/src/lib/exporter/audioRoutingEngine.ts @@ -1,8 +1,12 @@ -import type { AudioRegion } from "@/components/video-editor/types"; import { SOURCE_AUDIO_NORMALIZE_GAIN } from "@/components/video-editor/audio/audioTypes"; +import type { AudioRegion } from "@/components/video-editor/types"; +import { getSourceTrackIdFromPath } from "./audioProcessorShared"; +import type { SourceTrackId } from "./audioProcessorShared"; import { resolveSourceAudioFallbackPaths } from "./sourceAudioFallback"; -export type SourceTrackId = "mic" | "system" | "mixed"; +export { getSourceTrackIdFromPath }; +export type { SourceTrackId }; + export type ResolvedAudioTrackKind = "user" | "system" | "mic" | "mixed" | "embedded"; export interface ResolvedAudioTrack { @@ -29,13 +33,6 @@ export interface ResolvedAudioPlan { masterGain: number; } -export function getSourceTrackIdFromPath(audioPath: string): SourceTrackId { - const normalized = audioPath.toLowerCase(); - if (normalized.includes(".mic.")) return "mic"; - if (normalized.includes(".system.")) return "system"; - return "mixed"; -} - function clampGain(value: number, max: number) { if (!Number.isFinite(value)) return 1; return Math.max(0, Math.min(max, value));