Skip to content

refactor(web): add runtime audio encoder capability negotiation for mp4 exports#757

Open
chinhkrb113 wants to merge 1 commit intoOpenCut-app:mainfrom
chinhkrb113:improve/quality/add-runtime-audio-encoder-capability-neg
Open

refactor(web): add runtime audio encoder capability negotiation for mp4 exports#757
chinhkrb113 wants to merge 1 commit intoOpenCut-app:mainfrom
chinhkrb113:improve/quality/add-runtime-audio-encoder-capability-neg

Conversation

@chinhkrb113
Copy link
Copy Markdown

@chinhkrb113 chinhkrb113 commented Apr 2, 2026

Code Quality

Problem

Introduce a dedicated utility that probes browser support for AAC/WebCodecs audio settings instead of assuming a single hardcoded configuration (mp4a.40.2, 192 kbps, stereo, 44.1 kHz). This file should centralize support detection and fallback selection so ChromeOS/Chrome variants that reject the current config can still export with audio.

Severity: high
File: apps/web/src/lib/export/audio-codec-support.ts

Solution

Implement a resolveSupportedMp4AudioConfig() function that:

Changes

  • apps/web/src/lib/export/audio-codec-support.ts (new)

⚠️ READ BEFORE SUBMITTING ⚠️

We are not currently accepting PRs except for critical bugs.

If this is a bug fix:

  • I've opened an issue first
  • This was approved by a maintainer

If this is a feature:

This PR will be closed. Please open an issue to discuss first.Contributed by Lê Thành Chỉnh
Code is a tool. Mindset is the real value.

Closes #718

Summary by CodeRabbit

  • New Features
    • Audio codec support detection has been implemented, enabling the application to automatically identify and select compatible audio encoding configurations for export operations.

…p4 exports

Introduce a dedicated utility that probes browser support for AAC/WebCodecs audio settings instead of assuming a single hardcoded configuration (`mp4a.40.2`, 192 kbps, stereo, 44.1 kHz). This file should centralize support detection and fallback selection so ChromeOS/Chrome variants that reject the current config can still export with audio.

Affected files: audio-codec-support.ts

Signed-off-by: ChinhLee <76194645+chinhkrb113@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 2, 2026

@chinhkrb113 is attempting to deploy a commit to the OpenCut OSS Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

A new utility module was added that exports a function to dynamically discover supported MP4 audio encoder configurations. The function iterates through candidate AAC codec configurations and uses the Web Audio API's AudioEncoder.isConfigSupported() to find a compatible setting, returning the first supported config or null.

Changes

Cohort / File(s) Summary
Audio Codec Support
apps/web/src/lib/export/audio-codec-support.ts
New module introducing resolveSupportedMp4AudioConfig() function that dynamically probes browser-supported AAC audio encoder configurations (bitrates, channels, sample rates) for MP4 export, falling back gracefully when configs are unsupported or the API is unavailable.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A codec quest through browsers wide,
We test each config side by side,
When Chrome says "nope, not for me,"
We try the next one, gracefully!
No more crashes at export time,
Just audio configs so sublime! 🎵

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding runtime audio encoder capability negotiation for MP4 exports.
Description check ✅ Passed The description explains the problem and solution, though it includes template checklist items that appear incomplete or misaligned with the PR type.
Linked Issues check ✅ Passed The PR directly addresses issue #718 by implementing runtime audio encoder capability detection with fallback selection to avoid export crashes on unsupported configurations.
Out of Scope Changes check ✅ Passed All changes are scoped to adding a new utility module for audio codec support detection as required by issue #718.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/web/src/lib/export/audio-codec-support.ts (2)

1-26: Prefer satisfies over explicit literal type annotation (Line 1).

const CANDIDATE_CONFIGS: AudioEncoderConfig[] = ... adds a redundant annotation on a literal-initialized variable. Use satisfies to keep structural validation while preserving better literal inference.

♻️ Proposed change
-const CANDIDATE_CONFIGS: AudioEncoderConfig[] = [
+const CANDIDATE_CONFIGS = [
 	{
 		codec: "mp4a.40.2",
 		sampleRate: 44100,
 		numberOfChannels: 2,
 		bitrate: 192000,
 	},
 	{
 		codec: "mp4a.40.2",
 		sampleRate: 44100,
 		numberOfChannels: 2,
 		bitrate: 128000,
 	},
 	{
 		codec: "mp4a.40.2",
 		sampleRate: 44100,
 		numberOfChannels: 1,
 		bitrate: 128000,
 	},
 	{
 		codec: "mp4a.40.2",
 		sampleRate: 48000,
 		numberOfChannels: 2,
 		bitrate: 128000,
 	},
-];
+] satisfies AudioEncoderConfig[];

As per coding guidelines, "Don't add type annotations to variables, parameters, and class properties that are initialized with literal expressions".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/lib/export/audio-codec-support.ts` around lines 1 - 26, The
CANDIDATE_CONFIGS constant is annotated with an explicit type
(AudioEncoderConfig[]) which is redundant for a literal-initialized value;
change the declaration to use the TypeScript `satisfies` operator so the array
still validates against AudioEncoderConfig but preserves better literal type
inference (replace the explicit type annotation on CANDIDATE_CONFIGS with a
`satisfies AudioEncoderConfig[]` form while keeping the same array contents).

39-40: Remove redundant continue in catch (Line 40).

continue is unnecessary here because the loop naturally proceeds to the next iteration after the catch block ends.

🧹 Proposed simplification
 		} catch {
-			continue;
+			// try next candidate
 		}

As per coding guidelines, "Don't use unnecessary continue statements".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/lib/export/audio-codec-support.ts` around lines 39 - 40, Remove
the redundant "continue" inside the catch block of the loop that iterates over
codecs (the for/while loop containing the try { ... } catch { continue; }
pattern) in audio-codec-support.ts; simply delete the "continue;" so the catch
block is empty (or only handles logging if needed) and allow the loop to
naturally proceed to the next iteration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/web/src/lib/export/audio-codec-support.ts`:
- Around line 28-45: Replace the hardcoded AAC probe in the MP4 export flow with
the new helper: call resolveSupportedMp4AudioConfig() from the export logic (the
place currently calling AudioEncoder.isConfigSupported with codec "mp4a.40.2"
and sampleRate/numberOfChannels) and use the returned AudioEncoderConfig (or
null) instead of the inline probe; if it returns null, proceed with the existing
fallback/no-audio path. Update the code path that currently expects { supported
} from AudioEncoder.isConfigSupported to await resolveSupportedMp4AudioConfig()
and branch on its result so codec negotiation is centralized.

---

Nitpick comments:
In `@apps/web/src/lib/export/audio-codec-support.ts`:
- Around line 1-26: The CANDIDATE_CONFIGS constant is annotated with an explicit
type (AudioEncoderConfig[]) which is redundant for a literal-initialized value;
change the declaration to use the TypeScript `satisfies` operator so the array
still validates against AudioEncoderConfig but preserves better literal type
inference (replace the explicit type annotation on CANDIDATE_CONFIGS with a
`satisfies AudioEncoderConfig[]` form while keeping the same array contents).
- Around line 39-40: Remove the redundant "continue" inside the catch block of
the loop that iterates over codecs (the for/while loop containing the try { ...
} catch { continue; } pattern) in audio-codec-support.ts; simply delete the
"continue;" so the catch block is empty (or only handles logging if needed) and
allow the loop to naturally proceed to the next iteration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3cf63b8a-3467-440d-ab4f-fdb76f444a08

📥 Commits

Reviewing files that changed from the base of the PR and between 3516bd6 and 0314087.

📒 Files selected for processing (1)
  • apps/web/src/lib/export/audio-codec-support.ts

Comment on lines +28 to +45
export async function resolveSupportedMp4AudioConfig(): Promise<AudioEncoderConfig | null> {
if (typeof AudioEncoder === "undefined") {
return null;
}

for (const config of CANDIDATE_CONFIGS) {
try {
const support = await AudioEncoder.isConfigSupported(config);
if (support.supported) {
return config;
}
} catch {
continue;
}
}

return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify helper adoption and detect remaining hardcoded probing in exporter flow.

set -euo pipefail

echo "== locate new helper usages =="
rg -nP --type=ts '\bresolveSupportedMp4AudioConfig\s*\(' -C2

echo
echo "== locate direct AudioEncoder probing still in renderer/export paths =="
rg -nP --type=ts '\bAudioEncoder\.isConfigSupported\s*\(' -C3 apps/web/src/services/renderer/scene-exporter.ts apps/web/src/lib/export/audio-codec-support.ts || true

echo
echo "Expected:"
echo "1) scene-exporter path references resolveSupportedMp4AudioConfig()."
echo "2) hardcoded AAC probe logic is removed or delegated to the utility."

Repository: OpenCut-app/OpenCut

Length of output: 1930


Integrate the new helper into the MP4 export path.

The resolveSupportedMp4AudioConfig() function is defined but never called. scene-exporter.ts (lines 107–110) still contains the hardcoded AAC probe logic that should delegate to this utility:

const { supported } = await AudioEncoder.isConfigSupported({
    codec: "mp4a.40.2",
    sampleRate: this.audioBuffer.sampleRate,
    numberOfChannels: this.audioBuffer.numberOfChannels,

Replace this with resolveSupportedMp4AudioConfig() to centralize codec negotiation and achieve the PR's runtime-fallback objective.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/src/lib/export/audio-codec-support.ts` around lines 28 - 45, Replace
the hardcoded AAC probe in the MP4 export flow with the new helper: call
resolveSupportedMp4AudioConfig() from the export logic (the place currently
calling AudioEncoder.isConfigSupported with codec "mp4a.40.2" and
sampleRate/numberOfChannels) and use the returned AudioEncoderConfig (or null)
instead of the inline probe; if it returns null, proceed with the existing
fallback/no-audio path. Update the code path that currently expects { supported
} from AudioEncoder.isConfigSupported to await resolveSupportedMp4AudioConfig()
and branch on its result so codec negotiation is centralized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Audio Issues during export

1 participant