Skip to content

fix: snap illegal AAC sample rates to 48 kHz on Windows - #2

Closed
My-Denia wants to merge 3 commits into
base/upstream-39524549from
fix/wgc-aac-sample-rate
Closed

fix: snap illegal AAC sample rates to 48 kHz on Windows#2
My-Denia wants to merge 3 commits into
base/upstream-39524549from
fix/wgc-aac-sample-rate

Conversation

@My-Denia

@My-Denia My-Denia commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Summary

Windows WASAPI loopback often reports 96 kHz or 192 kHz. Those rates are legal PCM mix rates but not AAC encoder input rates, so Media Foundation SetInputMediaType fails with MF_E_INVALIDMEDIATYPE (0xc00d36b4). The capture helper now snaps illegal AAC rates to 48 kHz and leaves 8 / 11.025 / 12 / 16 / 22.05 / 24 / 32 / 44.1 / 48 kHz unchanged. The mixer already resamples when the source rate differs.

Related issue

Windows capture AAC sample-rate mismatch. This fork PR does not use a GitHub closing keyword.

Type of change

  • Bug fix
  • Feature
  • Enhancement
  • Documentation
  • Refactor / maintenance
  • Performance
  • Security

Release impact

  • Patch
  • Minor
  • Major / breaking change
  • No release note needed

Desktop impact

  • Windows
  • macOS
  • Linux
  • Installer / packaging
  • Not platform-specific

Screenshots / video

Not applicable (native capture helper).

Testing

On Windows with system audio:

  • Media Foundation SetInputMediaType for 96 kHz PCM into AAC returns 0xc00d36b4; 48 kHz succeeds.
  • With the snap enabled, a helper recording whose encoder source is 96 kHz starts and reports AAC-compatible 48 kHz (recording-started).
  • With the snap disabled for the fail path, helper initialize fails at SetInputMediaType(audio) with 0xc00d36b4.

Copilot AI lite review requested due to automatic review settings September 2, 2026 02:03
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T03:45:34.691912Z 6abf9ad New commits
🔒 Security Review Completed 2026-09-02T02:07:55.206057Z 569c7cb PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

The new Windows-native test executable has multiple early-return failure paths that can leave stray temp files, and there’s a newly introduced comment referencing an incorrect env var name.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adjusts the Windows WGC helper’s AAC audio path so WASAPI loopback/mic formats that report non-AAC-compatible PCM sample rates (e.g., 96 kHz) are snapped to 48 kHz before Media Foundation sink-writer configuration, preventing SetInputMediaType(audio) failures during recording start.

Changes:

  • Introduces explicit AAC sample-rate snapping (keep known-good AAC rates; snap everything else to 48 kHz) in makeAacCompatibleAudioFormat.
  • Adds Media Foundation–backed Windows-native test executable (audio_sample_utils_test) and runs it as part of the WGC helper build script.
  • Adds test-only encoder options/env plumbing to optionally skip snapping and to probe the failing MF code path for diagnostics.
File summaries
File Description
scripts/build-windows-wgc-helper.mjs Runs the new audio_sample_utils_test.exe after building to validate MF behavior.
electron/native/wgc-capture/src/mf_encoder.h Adds test-only encoder options and threads options into audio-stream configuration.
electron/native/wgc-capture/src/mf_encoder.cpp Applies rate snapping earlier (output-type build + input-type set), and adds an optional MF probe for invalid AAC rates.
electron/native/wgc-capture/src/main.cpp Adds env-driven diagnostics to force/disable AAC rate snap and inject the probe; logs these in JSON events.
electron/native/wgc-capture/src/audio_sample_utils.cpp Implements the AAC-compatible sample-rate snapping logic used by the encoder path.
electron/native/wgc-capture/src/audio_sample_utils_test.cpp Adds a Windows-native test harness validating snap behavior, resampling, and actual MF acceptance/rejection of sample rates.
electron/native/wgc-capture/CMakeLists.txt Builds and links the new audio_sample_utils_test executable against MF/COM libs.
Review details

Suppressed comments (2)

electron/native/wgc-capture/src/audio_sample_utils_test.cpp:71

  • trySetAacPcmRate() returns early on MFCreateMediaType(outputType) failure without deleting the temp output file path, which can leave a stray temp file on failure paths.
    Microsoft::WRL::ComPtr<IMFMediaType> outputType;
    hr = MFCreateMediaType(&outputType);
    if (FAILED(hr)) {
        return hr;
    }

electron/native/wgc-capture/src/audio_sample_utils_test.cpp:125

  • trySetAacPcmRateWithVideo() returns early on MFCreateMediaType(videoOut) failure without deleting the temp file path, which can leave stray files on failure paths.
    Microsoft::WRL::ComPtr<IMFMediaType> videoOut;
    hr = MFCreateMediaType(&videoOut);
    if (FAILED(hr)) {
        return hr;
    }
  • Files reviewed: 7/7 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +61 to +65
Microsoft::WRL::ComPtr<IMFSinkWriter> writer;
HRESULT hr = MFCreateSinkWriterFromURL(path.c_str(), nullptr, attributes, &writer);
if (FAILED(hr)) {
return hr;
}
Comment on lines +115 to +119
Microsoft::WRL::ComPtr<IMFSinkWriter> writer;
HRESULT hr = MFCreateSinkWriterFromURL(path.c_str(), nullptr, nullptr, &writer);
if (FAILED(hr)) {
return hr;
}
Comment thread electron/native/wgc-capture/src/mf_encoder.h

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 569c7cb5a7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (!fs.existsSync(audioUtilsTestPath)) {
throw new Error(`WGC helper build completed but ${audioUtilsTestPath} was not found.`);
}
await run(audioUtilsTestPath, [], { cwd: BUILD_DIR });

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not gate native builds on the builder's codecs

Running this executable unconditionally makes npm run build:native:win depend on the Media Foundation transforms installed on the build host, rather than only on compilation. On Windows N/KN or Server installations without the Media Feature Pack, the test's required 48 kHz AAC/H.264 setup fails; conversely, a registered third-party AAC transform that accepts 96 kHz makes the required rejection fail. Either case aborts an otherwise successful helper build, so this runtime codec probe should not be part of the mandatory packaging command unless it explicitly activates the intended transform or skips unsupported hosts.

Useful? React with 👍 / 👎.

AudioInputFormat format{};
format.subtype = MFAudioFormat_PCM;
format.sampleRate = source.sampleRate > 0 ? source.sampleRate : 48000;
format.sampleRate = aacCompatibleSampleRate(source.sampleRate);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resample high-rate input instead of decimating it

When a 96 or 192 kHz WASAPI source is snapped here, AudioMixer::append now sends every packet through convertAudioWithGain, whose rate conversion selects one nearest source frame per output frame without a low-pass filter. Downsampling therefore aliases source energy above 24 kHz into the audible 48 kHz recording—for example, 30 kHz microphone noise becomes an 18 kHz tone—so the newly supported high-rate-device path can produce audible artifacts. Use an anti-aliased, stateful resampler when the rate changes.

Useful? React with 👍 / 👎.

AudioInputFormat format{};
format.subtype = MFAudioFormat_PCM;
format.sampleRate = source.sampleRate > 0 ? source.sampleRate : 48000;
format.sampleRate = aacCompatibleSampleRate(source.sampleRate);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Record the required Windows native smoke test

This changes the Windows native capture and audio-encoding path, but the commit does not append a Windows capture-to-export result to technical-documentation/testing/manual-e2e-checklist.md. The repository requires that pass after every native-capture change and says the run does not count until its platform, build, coverage, and skipped checks are recorded, so add the corresponding results-log row before treating this fix as validated.

AGENTS.md reference: AGENTS.md:L84-L90

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff60bdb240

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

targetFormat,
targetFrame,
channel,
(sum / static_cast<double>(factor)) * gain);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use a real anti-alias filter before decimation

On 96/192 kHz devices with energy above the 24 kHz output Nyquist frequency, averaging only each 2- or 4-frame group is a box filter, not sufficient anti-alias filtering. For example, a 30 kHz component at 96 kHz retains about 56% amplitude through this average and then aliases to an audible 18 kHz component in the 48 kHz recording. The fresh follow-up replaces nearest-neighbor sampling with this box average, but that new code therefore does not resolve the previously reported aliasing; use a proper low-pass resampler before decimation.

Useful? React with 👍 / 👎.

if (sourceFormat.sampleRate > targetFormat.sampleRate &&
sourceFormat.sampleRate % targetFormat.sampleRate == 0) {
const UINT32 factor = sourceFormat.sampleRate / targetFormat.sampleRate;
const size_t targetFrames = sourceFrames / factor;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve partial frames across capture packets

When a 96 kHz WASAPI packet has an odd frame count, or a 192 kHz packet has a count not divisible by four, this integer division discards the packet's remaining source frames. AudioMixer::append invokes this conversion independently for every GetBuffer result and retains no remainder or resampling phase, so repeated non-aligned packets lose samples and introduce discontinuities or accumulated timing error in the captured audio. Carry the unused frames into the next callback instead of truncating each packet independently.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 0d458fed-7875-4e2e-9f1a-b390cf16515e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@My-Denia

My-Denia commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the upstream pull request getopenscreen#565

@My-Denia My-Denia closed this Sep 2, 2026
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