Skip to content

Add encoder's AudioContext sampleRate override#1355

Merged
kixelated merged 1 commit into
moq-dev:mainfrom
Qizot:audio-sample-rate-override
Apr 28, 2026
Merged

Add encoder's AudioContext sampleRate override#1355
kixelated merged 1 commit into
moq-dev:mainfrom
Qizot:audio-sample-rate-override

Conversation

@Qizot
Copy link
Copy Markdown
Contributor

@Qizot Qizot commented Apr 28, 2026

This PR adds a manual override of the audio sample rate.

Previously the sample. rate was purely taken from the media source, which works in majority of cases. It happens that is not the case for firefox where the media source can return arbitrary values such as 16Khz or 96Khz, this doesn't work well with WebCodecs and produces a broken stream.

This change is backwards compatible, by default we will always take the source's sample rate.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 28, 2026

Walkthrough

The encoder module adds sample rate override functionality to the audio encoding pipeline. A new sampleRate signal property is introduced to both the EncoderProps type and the Encoder class. During audio source setup, the code determines an effective sample rate by prioritizing the override signal if provided, otherwise falling back to the source's configured sample rate. This effective value is then used when constructing the AudioContext. The import syntax for the Source type is also adjusted in the process.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and specifically describes the main change: adding a sampleRate override to the encoder's AudioContext, which matches the primary modification in the changeset.
Description check ✅ Passed The PR description accurately explains the motivation (Firefox media source returning nonstandard sample rates) and the solution (manual override), which directly relates to the code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

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

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


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 (1)
js/publish/src/audio/encoder.ts (1)

23-40: Document the new public sampleRate API contract.

Please add a short comment/docstring describing expected units, override behavior, and fallback semantics for sampleRate on both EncoderProps and Encoder, since this is now a public surface.

As per coding guidelines "Document public APIs with clear docstrings or comments".

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

In `@js/publish/src/audio/encoder.ts` around lines 23 - 40, Add a short doc
comment for the new public sampleRate on both EncoderProps and the Encoder
class: state the units are in Hertz (number means Hz), explain that a provided
EncoderProps.sampleRate overrides any runtime Signal (i.e. if the prop is set it
forces the encoder sample rate), and describe fallback semantics when undefined
(the encoder will use the source/device sample rate or the library default).
Place the comment above the sampleRate declaration in the EncoderProps type and
above the instance property sampleRate on the Encoder class so callers see the
contract for both the constructor input and the runtime Signal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/publish/src/audio/encoder.ts`:
- Around line 80-86: The sampleRate value coming from
effect.get(this.sampleRate) (assigned to overrideSampleRate and then sampleRate)
must be validated before constructing the AudioContext to avoid opaque
constructor errors; add a guard immediately after computing sampleRate that
checks Number.isFinite(sampleRate) and sampleRate > 0, and if the check fails
throw or return a clear error (e.g., throw new Error("Invalid sampleRate: must
be a finite positive number")) so that the AudioContext(...) call is never
invoked with NaN/Infinity/≤0 values.

---

Nitpick comments:
In `@js/publish/src/audio/encoder.ts`:
- Around line 23-40: Add a short doc comment for the new public sampleRate on
both EncoderProps and the Encoder class: state the units are in Hertz (number
means Hz), explain that a provided EncoderProps.sampleRate overrides any runtime
Signal (i.e. if the prop is set it forces the encoder sample rate), and describe
fallback semantics when undefined (the encoder will use the source/device sample
rate or the library default). Place the comment above the sampleRate declaration
in the EncoderProps type and above the instance property sampleRate on the
Encoder class so callers see the contract for both the constructor input and the
runtime Signal.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e3be641b-633d-40d9-b16e-14b0451e2d4a

📥 Commits

Reviewing files that changed from the base of the PR and between 0331db7 and 84ebce8.

📒 Files selected for processing (1)
  • js/publish/src/audio/encoder.ts

Comment on lines +80 to 86
const overrideSampleRate = effect.get(this.sampleRate);
const sampleRate = overrideSampleRate ?? settings.sampleRate;

const context = new AudioContext({
latencyHint: "interactive",
sampleRate: settings.sampleRate,
sampleRate,
});
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:

# First, let's check if the file exists and examine the relevant section
if [ -f "js/publish/src/audio/encoder.ts" ]; then
  echo "=== File exists, checking lines 70-95 for context ==="
  sed -n '70,95p' "js/publish/src/audio/encoder.ts"
else
  echo "File not found at js/publish/src/audio/encoder.ts"
  # Try to find it
  find . -name "encoder.ts" -type f 2>/dev/null | head -20
fi

Repository: moq-dev/moq

Length of output: 874


🏁 Script executed:

# Also search for where sampleRate is defined as a signal
rg "sampleRate\s*[:=]" js/publish/src/audio/ -A 2 -B 2

Repository: moq-dev/moq

Length of output: 2114


🏁 Script executed:

# Check for any existing validation of sampleRate
rg "sampleRate" js/publish/src/audio/encoder.ts -n -B 2 -A 2

Repository: moq-dev/moq

Length of output: 1501


🏁 Script executed:

# Check what source is and where it comes from
rg "getSettings" js/publish/src/audio/encoder.ts -B 10 -A 5

Repository: moq-dev/moq

Length of output: 588


🏁 Script executed:

# Look at the full context of `#runSource` method to understand source type
sed -n '74,120p' "js/publish/src/audio/encoder.ts"

Repository: moq-dev/moq

Length of output: 1383


🏁 Script executed:

# Check if there's any validation of sampleRate elsewhere in the codebase
rg "sampleRate" js/publish/src/audio/ --type ts -B 3 -A 3 | grep -E "(isFinite|Number.is|validate|throw|Error|if.*sample)" -B 3 -A 3

Repository: moq-dev/moq

Length of output: 37


🏁 Script executed:

# Check the types to understand the source parameter better
cat -n js/publish/src/audio/types.ts

Repository: moq-dev/moq

Length of output: 1184


Add validation for sampleRate before AudioContext construction.

The sampleRate signal is externally settable but lacks validation. If set to invalid values (NaN, Infinity, or ≤ 0), the AudioContext constructor will fail with an opaque error instead of a clear validation message. Add a guard clause to validate that the sample rate is a positive finite number.

Proposed fix
		const overrideSampleRate = effect.get(this.sampleRate);
		const sampleRate = overrideSampleRate ?? settings.sampleRate;

+		if (
+			sampleRate !== undefined &&
+			(!Number.isFinite(sampleRate) || sampleRate <= 0)
+		) {
+			throw new RangeError("encoder sampleRate must be a positive finite number");
+		}

		const context = new AudioContext({
			latencyHint: "interactive",
			sampleRate,
		});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const overrideSampleRate = effect.get(this.sampleRate);
const sampleRate = overrideSampleRate ?? settings.sampleRate;
const context = new AudioContext({
latencyHint: "interactive",
sampleRate: settings.sampleRate,
sampleRate,
});
const overrideSampleRate = effect.get(this.sampleRate);
const sampleRate = overrideSampleRate ?? settings.sampleRate;
if (
sampleRate !== undefined &&
(!Number.isFinite(sampleRate) || sampleRate <= 0)
) {
throw new RangeError("encoder sampleRate must be a positive finite number");
}
const context = new AudioContext({
latencyHint: "interactive",
sampleRate,
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/publish/src/audio/encoder.ts` around lines 80 - 86, The sampleRate value
coming from effect.get(this.sampleRate) (assigned to overrideSampleRate and then
sampleRate) must be validated before constructing the AudioContext to avoid
opaque constructor errors; add a guard immediately after computing sampleRate
that checks Number.isFinite(sampleRate) and sampleRate > 0, and if the check
fails throw or return a clear error (e.g., throw new Error("Invalid sampleRate:
must be a finite positive number")) so that the AudioContext(...) call is never
invoked with NaN/Infinity/≤0 values.

@kixelated kixelated merged commit 216c9f1 into moq-dev:main Apr 28, 2026
1 check passed
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.

2 participants