The speaker opens at 44100 while the device runs at 48000, so everything is resampled twice #194
Open
opened 2026-08-21 23:33:53 +00:00 by logan
·
1 comment
No Branch/Tag Specified
main
fix/146-stub-etxtbsy
fix/175-wizard-follows-the-library
fix/231-setter-rollback
fix/197-duplicate-column-label
docs/225-fixtures-wav-tags
docs/220-skill-check-scope
test/217-fixture-names-in-queue-selection
fix/216-riff-parse-allocation
fix/170-queue-header-action-names
fix/210-nav-sheet-scroll-affordance
docs/50-readme-landing-page
feat/65-art-prefetch-ahead
feat/71-more-as-a-bottom-sheet
feat/54-native-touch-feel
feat/67-entity-links-into-menus
test/196-visual-tier-gates
fix/138-ui-test-storage-leak
fix/104-wav-tags-read
fix/207-sheet-scroll-affordance
fix/204-ui-visual-update-filter
pi-agent-backlog-automation
63-touch-model-phase-2
63-android-touch-model
186-touch-targets-settings
186-touch-targets-page-header
187-seek-bar-hit-area
189-190-explore-correctness
135-android-underrun-instrumentation
51-android-small-screens
fix/171-phone-queue-scrim
fix/137-touch-only-affordances
fix/154-nested-css-check
feat/58-mini-player-progress-line
fix/66-album-page-scrolls-as-one
60-context-menu-action-sheet
64-android-system-volume
59-slim-the-mini-player
55-queue-as-a-screen
feat/57-drop-the-android-top-bar
feat/62-jobs-as-a-notification
fix/53-seek-bar-never-moves
fix/159-android-task-app-id
fix/52-android-activity-recreation-restarts-the-process
fix/150-expand-button-under-the-art
feat/42-inline-volume-and-centred-transport
fix/156-queue-selection-fixture-order
fix/151-fuse-the-scroll-guard-and-the-write
fix/43-queue-panel-selection
fix/143-top-bar-fits-its-window
feat/27-jobs-into-settings
feat/25-configurable-sidebar-tabs
feat/6-global-back-forward
fix/72-active-view-broadcast
fix/69-page-header-action-overflow
fix/quick-wins-batch
fix/118-in-library-clear
fix/61-mini-player-plain-text
fix/68-hover-affordances-pointer
fix/119-dev-headless-port
fix/130-issue-claim-user
fix/131-codegen-check-scope
feat/28-autotag-match-on-album
feat/17-demote-version-selector
feat/38-ownership-visibility
ci/115-manual-release
feat/34-icon-language
feat/7-full-tracklist-toggle
fix/16-tagwriter-totals
fix/unclaim-ca-certs
fix/unclaim-shell
ci/unclaim-on-close
docs/closing-keyword
docs/retire-stale-planning-docs
docs/issue-driven-workflow
integration/small-fixes
fix/small-issue-batch
fix/queue-toggle-state
fix/drag-count-badge
fix/album-card-year
fix/album-tracklist-heading
fix/seek-bar-clock-width
fix/explore-art-scanner-requests
chore/workflow-guardrails
v0.7.0
v0.6.0
v0.5.0
v0.4.0
v0.3.1
v0.3.0
v0.2.3
v0.2.2
v0.2.1
v0.2.0
v0.1.0
v0.0.1
v0.0.0
Labels
Clear labels
Area/Design
Area/Downloads
Area/Explore
Area/Library-UI
Area/Metadata
Area/Packaging
Area/Player
Area/Queue
Area/Settings
Area/Shell-Nav
Compat/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Platform/Android
Platform/Desktop
Breaking change that won't be backward compatible
Something is not working
Documentation changes
Improve existing functionality
New functionality
This is security issue
Issue or pull request related to testing
Priority
Critical
1
The priority is critical
Priority
High
2
The priority is high
Priority
Medium
3
The priority is medium
Priority
Low
4
The priority is low
Reviewed
Confirmed
1
Issue has been confirmed
Reviewed
Duplicate
2
This issue or pull request already exists
Reviewed
Invalid
3
Invalid issue
Reviewed
Won't Fix
3
This issue won't be fixed
Status
Blocked
1
Something is blocking this issue or pull request
Status
Need More Info
2
Feedback is required to reproduce issue or to continue work
Status
Abandoned
3
Somebody has started to work on this but abandoned work
Status
In Progress
Somebody is actively working on this right now
Milestone
No items
No Milestone
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: yonlu/yellowjacket#194
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Report
The app opens the speaker at 44100 Hz on every platform. The reference
device's output stream runs at 48000 Hz, so every file is resampled
twice on the way out: once by us into 44100, and once by the platform
back to 48000.
Measured on the device (TLP301, Android 14) with
dumpsys audio, forour own pid, while playing:
backend/player/player.go:48000 is Android's native output rate on essentially every device, and
the library's own files agree: a sample of the test library reports
SampleRate: 48000per track, so the first resampling is oftendownsampling 48k source material only for the platform to put it back.
This is deliberately not #135. That issue asked whether this was
causing audible popping; it was measured, the ring buffer records zero
underruns, and the reporter has listened on the device and confirmed
the symptom is not present. So this is an efficiency and latency
report, not a defect anyone can hear, and it should be judged on those
terms rather than as a bug fix.
Findings
calls
oboe.Play(sampleRate, ...)and the binding always callsbuilder.setSampleRate(sample_rate_)with whatever it is handed(
internal/oboe/binding_android.cpp). Oboe would pick the devicerate if the field were left unset, and there is no path through oto
to leave it unset — so the number has to come from us.
AudioManager.PROPERTY_OUTPUT_SAMPLE_RATEandPROPERTY_OUTPUT_FRAMES_PER_BUFFER. Our Java lives inbuild/android/.../WailsForegroundService.java, and the existingGo↔Java channels are
application.Android.StartForegroundService(JSON out) and
WailsBridge.emitEvent(events back) — neither is asynchronous "call and return a value", and
InitSpeakerruns atstartup, before the WebView could be asked instead.
on its own: Oboe prefers AAudio from API 27 and this device is API
34. Requesting a non-native rate is one of the things that can cost
the fast path, so the two may be the same finding.
speakerSampleRateis a packagevarrather than aconst, whichsuggests it was always meant to be settable.
Direction
Android-only constant of 48000 is enough. The platform-constant
shape is already established here —
platformOwnsVolumeinsystemvolume_{android,other}.go, with the testable half in anuntagged file — and it needs no new JNI channel.
dumpsys audiothat the streamopens at the device rate, and check whether it then takes AAudio
rather than OpenSL ES.
make android-logswill say if it made anything worse: #135'sunderrun counter is silent while playback is healthy and reports
runs, calls and milliseconds of silence when it is not. Any change
to the audio path should be judged against it, since that is the
whole reason it exists.
Worth knowing: the buffer size is the other half of the same
TODOand the other half of #135's candidate 3.
InitSpeaker's comment saysthe speaker buffer is 200 ms; beep halves it, so Oboe gets ~100 ms, and
oto's own documentation for that option suggests raising it to "reduce
noises". It has never been tuned per platform, and a phone can afford
latency a desktop player cannot.
The "not a defect anyone can hear" framing is now contested — see
#203.
This issue asks to be judged as an efficiency and latency report rather
than a bug fix, on the grounds that "it was measured, the ring buffer
records zero underruns, and the reporter has listened on the device and
confirmed the symptom is not present". Both halves of that come from
#135, and both are narrower than they read:
not in
v0.5.0—842fe47landed after the tag, so no releasedbuild reports underruns at all;
screen on.
The reporter has now listened on the release build and popping is still
audible, less obvious than #135's static.
That does not make this a bug — it may still be exactly the efficiency
report it says it is. What it does is remove the reason to rule it
out: the double resampling and the OpenSL ES path are in the layer
whose buffer is being missed, and if #203's re-measurement comes back
at zero underruns again, this becomes the leading candidate rather than
a tidy-up.
Not relabelling on that basis. #203 step 4 is what would decide it, and
it wants ears and the device.