Skip to content

fix: pulseaudio sample rate by detecting optimal system value#1456

Open
joshuatam wants to merge 2 commits into
utkarshdalal:masterfrom
joshuatam:fix/pulseaudio-latency-config
Open

fix: pulseaudio sample rate by detecting optimal system value#1456
joshuatam wants to merge 2 commits into
utkarshdalal:masterfrom
joshuatam:fix/pulseaudio-latency-config

Conversation

@joshuatam
Copy link
Copy Markdown
Contributor

@joshuatam joshuatam commented May 19, 2026

Description

The pulseaudio sample rate is now dynamically detected from the Android AudioManager, ensuring the use of the optimal output sample rate for the device. This improves audio compatibility and quality compared to using a fixed rate.

The bundled pulseaudio binary (pulseaudio-gamenative.tzst) has also been updated, removed exclusive stream config for better compatibility.

Recording

None

Type of Change

  • Bug fix
  • Performance / stability improvement
  • Compatibility improvements
  • Other (requires prior approval)

Checklist

  • If I have access to #code-changes, I have discussed this change there and it has been green-lighted. If I do not have access, I have still provided clear context in this PR. If I skip both, I accept that this change may face delays in review, may not be reviewed at all, or may be closed.
  • This change aligns with the current project scope (core functionality, stability, or performance). If not, it has been explicitly approved beforehand.
  • I have attached a recording of the change.
  • I have read and agree to the contribution guidelines in CONTRIBUTING.md.

Summary by cubic

Detects the device’s output sample rate via Android AudioManager and configures PulseAudio to use it instead of a fixed value. This avoids resampling and improves audio compatibility and quality across devices.

  • Bug Fixes
    • Read AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE with a 44100 Hz fallback.
    • Apply the detected rate to module-aaudio-sink in generated default.pa.
    • Removed manual sample rate setter; rate is detected at runtime.
    • Updated bundled pulseaudio-gamenative.tzst to remove exclusive stream config for broader device support.

Written for commit 6c32134. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Audio sample rate is now detected at runtime with a safe fallback to ensure consistent playback.
  • Chores
    • Manual sample-rate configuration option has been removed in favor of automatic detection.
  • New Features
    • Preparatory support for enabling verbose audio logging has been added (optional, disabled by default).

Review Change Stack

@joshuatam joshuatam requested a review from utkarshdalal as a code owner May 19, 2026 08:16
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 19, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e3b4b51-ee5f-49ee-b074-a3e7efb187a4

📥 Commits

Reviewing files that changed from the base of the PR and between 5df39d0 and 6c32134.

📒 Files selected for processing (2)
  • app/src/main/assets/pulseaudio-gamenative.tzst
  • app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java

📝 Walkthrough

Walkthrough

PulseAudioComponent now queries the device's audio output sample rate dynamically via AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE when starting PulseAudio, falling back to 44.1kHz. The manual setSampleRate(int) setter and sampleRate field are removed, and a commented-out -vvv debugging flag is added.

Changes

Dynamic Audio Sample Rate Detection

Layer / File(s) Summary
Sample rate capability detection
app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java
Adds android.media.AudioManager import and introduces isPaused state alongside getOptimalSampleRate() helper that reads the device's output sample rate from AudioManager with a 44.1kHz fallback.
PulseAudio startup integration
app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java
Computes bitRate from getOptimalSampleRate() in execPulseAudio(), updates module-aaudio-sink to use rate=bitRate instead of the removed sampleRate field, and adds a commented-out -vvv option for verbose Pulseaudio logging.

Sequence Diagram(s)

sequenceDiagram
  participant PulseAudioComponent
  participant AndroidAudioManager
  participant PulseAudioProcess
  PulseAudioComponent->>AndroidAudioManager: getProperty(PROPERTY_OUTPUT_SAMPLE_RATE)
  AndroidAudioManager-->>PulseAudioComponent: "48000" or null
  PulseAudioComponent->>PulseAudioProcess: execPulseAudio(rate=bitRate, /* -vvv optional */)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • utkarshdalal/GameNative#534: Also modifies PulseAudioComponent.execPulseAudio() and touches pulseaudio command/verbose logging handling.
  • utkarshdalal/GameNative#1447: Related changes to PulseAudioComponent sample-rate handling (one PR added a setter; this PR removes it and computes rate dynamically).
  • utkarshdalal/GameNative#158: Modifies module-aaudio-sink load-module parameters and startup configuration for PulseAudio.

Suggested reviewers

  • utkarshdalal

Poem

🐰 I hopped into the audio night,
Asked the phone what sounded right,
No hardcoded beats to bind,
The device replied — a rate to find,
Now every note lands soft and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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 summarizes the main change: detecting and using the optimal system sample rate for PulseAudio instead of a fixed value.
Description check ✅ Passed The description covers all required template sections with substantive details: explains what changed and why, specifies bug fix and compatibility improvements, confirms checklist completion, and notes the recording is not applicable.
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

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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java`:
- Around line 35-39: The getOptimalSampleRate method should defensively handle
null or non-numeric values from
AudioManager.getProperty(PROPERTY_OUTPUT_SAMPLE_RATE): check for null/empty,
trim the string, attempt to parse inside a try/catch for NumberFormatException,
and fall back to 44100 on any failure; update the method (referencing
getOptimalSampleRate, AudioManager, environment.getContext(), and
PROPERTY_OUTPUT_SAMPLE_RATE) to return the parsed int when valid, otherwise
return the safe default.
🪄 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: 03f37b5f-48a9-4c0f-a4e0-86b9b46a4278

📥 Commits

Reviewing files that changed from the base of the PR and between 089e177 and 518e205.

📒 Files selected for processing (2)
  • app/src/main/assets/pulseaudio-gamenative.tzst
  • app/src/main/java/com/winlator/xenvironment/components/PulseAudioComponent.java

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

@utkarshdalal
Copy link
Copy Markdown
Owner

Question - the new tzst has been added but will only apply for new games right? It will not fix pulse on existing games?

joshuatam added 2 commits May 19, 2026 20:10
The pulseaudio sample rate is now dynamically detected from the Android AudioManager, ensuring the use of the optimal output sample rate for the device. This improves audio compatibility and quality compared to using a fixed rate.

The bundled pulseaudio binary (`pulseaudio-gamenative.tzst`) has also been updated, removed exclusive stream config for better compatibility.
@joshuatam joshuatam force-pushed the fix/pulseaudio-latency-config branch from 5df39d0 to 6c32134 Compare May 19, 2026 12:14
@joshuatam
Copy link
Copy Markdown
Contributor Author

joshuatam commented May 19, 2026

Question - the new tzst has been added but will only apply for new games right? It will not fix pulse on existing games?

No, whenever updating this tzst, it will always replace the installed files in files dir.

Check this code:

// Always refresh components files
refreshComponentsFiles(context)

and

private fun refreshComponentsFiles(context: Context) {
TarCompressorUtils.extract(TarCompressorUtils.Type.ZSTD, context.assets, "pulseaudio-gamenative.tzst", File(context.filesDir, "pulseaudio"))
}

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