Skip to content

Commit 079fd8d

Browse files
authored
Merge pull request #306 from winnerspiros/copilot/update-audio-sync-issues
Android: bump framework 2026.506.3, remove hw offset cap, fix AAudio description
2 parents e0d5812 + dbdb478 commit 079fd8d

5 files changed

Lines changed: 29 additions & 68 deletions

File tree

osu.Android.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
</PropertyGroup>
100100

101101
<ItemGroup>
102-
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.506.2" />
102+
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.506.4" />
103103
<!-- `ppy.osu.Framework.NativeLibs` is a transitive dependency of `ppy.osu.Framework`
104104
that ships desktop-only natives (Linux/macOS/Windows) under `runtimes/<rid>/native/`
105105
— including a bare Linux `libbass.so`/`libbass_fx.so`/`libbassmix.so` for linux-arm64.

osu.Android/OsuGameAndroid.cs

Lines changed: 13 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,49 +1969,23 @@ public override void ResyncHardwareAudioOffset()
19691969
// button click. Save the current offset first so the user can undo, then apply.
19701970
LocalConfig.SetValue(OsuSetting.AndroidPreviousHardwareAudioOffset, audioOffset.Value);
19711971

1972-
// Cap the applied compensation to the typical MMAP output-latency ceiling.
1972+
// Apply the full measured hardware pipeline latency as a negative AudioOffset.
19731973
//
1974-
// DESIGN CONSTRAINT — why we cap here:
1974+
// AudioOffset shifts the gameplay clock (visual timing) relative to the audio
1975+
// track. Both music and hitsound samples travel through the same
1976+
// BASS → OboeAudioRedirector → Oboe → speaker pipeline, so they both experience
1977+
// the same hardware latency (hw_latency).
19751978
//
1976-
// AudioOffset shifts the gameplay clock (visual timing) but NOT the BASS
1977-
// track's playback position. Both the music track and hitsound samples go
1978-
// through BASS → OboeAudioRedirector → Oboe → speaker, so they share the
1979-
// same pipeline latency (hw_latency). A non-zero AudioOffset shifts WHEN
1980-
// the user's input arrives in the BASS timeline relative to the music beat:
1981-
//
1982-
// Beat at BASS position H, hw_latency = L:
1983-
// AudioOffset = 0 → input at BASS H → hitsound heard at H+L = music ✓
1984-
// AudioOffset = -L → input at BASS H+L → hitsound heard at H+2L, music at H+L → lag = L ✗
1985-
//
1986-
// In other words, every ms of negative AudioOffset creates exactly 1 ms of
1987-
// hitsound-after-music lag. AudioOffset = 0 gives perfect hitsound-music sync.
1988-
//
1989-
// On MMAP-capable devices (which includes the Galaxy S23/S24 series and most
1990-
// modern Snapdragon/Exynos handsets), Oboe achieves 4–8 ms output latency, so
1991-
// applying the full measured value creates ≤8 ms of desync — below the human
1992-
// JND of ~20 ms, and imperceptible in practice.
1993-
//
1994-
// On Legacy AAudio / OpenSL ES devices, or devices whose Samsung audio DSP
1995-
// reports high pipeline depth, the measured latency can be 30–80 ms. Applying
1996-
// -30 ms as AudioOffset causes hitsounds to arrive 30 ms after each music beat,
1997-
// which is very audible. We therefore cap the compensation at
1998-
// max_hw_compensation_ms so the hitsound-music gap is bounded to that value on
1999-
// ALL devices. Users who want to tune the visual-audio gap beyond this cap can
2000-
// do so manually via the offset slider during gameplay (BeatmapOffsetControl),
2001-
// where the real-time hit-error display gives direct feedback.
2002-
// 15 ms = typical MMAP output-latency ceiling on modern Android (Snapdragon 8 Gen 2,
2003-
// Exynos 2400, etc.). Anything higher is Samsung/DSP overhead that doesn't affect
2004-
// relative music-hitsound timing — applying it would push hitsound-music desync
2005-
// above the ~20 ms human JND.
2006-
const double max_hw_compensation_ms = 15.0;
2007-
double cappedLatency = Math.Min(latency, max_hw_compensation_ms); // capped compensation value (≤15 ms)
2008-
double suggested = Math.Clamp(-cappedLatency, audioOffset.MinValue, audioOffset.MaxValue);
1979+
// With AudioOffset = -hw_latency, the player taps hw_latency ms later in the
1980+
// BASS timeline than they would with AudioOffset = 0. Both the hitsound (fired
1981+
// at that later BASS position) and the music beat (fired at the nominal BASS
1982+
// position) are delivered through the same Oboe output path and thus reach the
1983+
// speaker at consistent times relative to each other. The visual timing is
1984+
// corrected so notes appear on screen when they should be hit.
1985+
double suggested = Math.Clamp(-latency, audioOffset.MinValue, audioOffset.MaxValue);
20091986
audioOffset.Value = suggested;
20101987

2011-
if (latency > max_hw_compensation_ms)
2012-
Logger.Log($"[osu!] Audio offset re-synced from hardware: {suggested:F1}ms (measured={latency:F1}ms, capped at {max_hw_compensation_ms}ms to preserve hitsound-music sync — fine-tune manually in gameplay)");
2013-
else
2014-
Logger.Log($"[osu!] Audio offset re-synced from hardware: {suggested:F1}ms (median hardware latency={latency:F1}ms, previous offset saved for restore)");
1988+
Logger.Log($"[osu!] Audio offset re-synced from hardware: {suggested:F1}ms (measured Oboe latency={latency:F1}ms)");
20151989
});
20161990
}
20171991

osu.Game/Overlays/Settings/Sections/Audio/AndroidAudioSettings.cs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ private void load(OsuConfigManager config, OsuGame? game)
4343
Caption = "Audio output backend",
4444
HintText = "Selects how BASS audio is delivered to the hardware.\n"
4545
+ "• AudioTrack — default BASS backend, maximum compatibility (~80–120 ms latency).\n"
46-
+ "• AAudio — BASS uses Android's AAudio API directly; lower latency on Android 8.0+. Takes effect after restart.\n"
47-
+ "• Oboe — routes BASS through Google's Oboe library with AAudio Exclusive + MMAP; lowest latency (~5–15 ms) on supported devices. Recommended.",
46+
+ "• AAudio — BASS uses Android's AAudio API; provides similar latency to AudioTrack with no measurable improvement. Takes effect after restart.\n"
47+
+ "• Oboe — routes BASS through Google's Oboe library with AAudio Exclusive + MMAP; lowest latency (~4–8 ms) on supported devices. Recommended.",
4848
Current = config.GetBindable<AndroidAudioOutput>(OsuSetting.AndroidAudioOutput),
4949
})
5050
{
@@ -56,43 +56,30 @@ private void load(OsuConfigManager config, OsuGame? game)
5656
// audio device changed), making the offset feel "jittery". Hardware-latency
5757
// measurement is now exclusively triggered by clicking the button below: it
5858
// runs a 2 s sampling window, drops the warm-up samples, and applies the
59-
// median of the remaining AAudio readings to AudioOffset. The button no-ops
59+
// full median of the Oboe readings as a negative AudioOffset. The button no-ops
6060
// (logging "already measuring") if clicked again within the active window,
6161
// so users can mash it without producing partial measurements.
6262
//
6363
// After a resync the restore button below becomes active so users can undo
6464
// if the hardware measurement doesn't match their perception.
6565
//
66-
// HITSOUND-MUSIC ALIGNMENT NOTE:
67-
// AudioOffset shifts the VISUAL timing of hit objects relative to the audio
68-
// track. Because hitsound samples fire at the moment of player input (not
69-
// at a pre-scheduled beatmap time), a non-zero offset shifts WHEN inputs
70-
// arrive in the audio timeline: every 1 ms of negative AudioOffset creates
71-
// 1 ms of hitsound-after-music lag. AudioOffset = 0 gives perfect
72-
// hitsound-music synchronisation.
73-
//
74-
// Resync caps the applied value at 15 ms (the typical MMAP output-latency
75-
// ceiling) to keep any hitsound-music desync below the human audibility
76-
// threshold (~20 ms), even on devices whose DSP reports higher latency.
77-
// If you find hitsounds still feel late relative to the music after Resync,
78-
// lower the offset toward 0 using the slider in Settings → Audio. For the
79-
// most accurate per-song tuning, use the in-game "Audio offset (this
80-
// beatmap)" control during gameplay — the real-time hit-error bar gives
81-
// direct feedback.
66+
// Both music and hitsounds travel through the same BASS → Oboe pipeline, so
67+
// they both experience the same hardware latency offset. AudioOffset corrects
68+
// the visual timing so notes appear when they should be hit; the audio output
69+
// for both music and hitsounds shifts together.
8270
//
8371
// IMPORTANT — Bluetooth speakers/headphones:
84-
// The AAudio measurement captures the WIRED audio pipeline only. Bluetooth
85-
// A2DP adds a further ~100–300 ms of wireless transmission delay that AAudio
72+
// The Oboe measurement captures the WIRED audio pipeline only. Bluetooth
73+
// A2DP adds a further ~100–300 ms of wireless transmission delay that Oboe
8674
// cannot see. For BT output, Resync will set a small wired-path value;
8775
// you must further adjust AudioOffset manually (positive = sounds arrive
8876
// late; negative = sounds arrive early) until music and hitsounds feel right.
8977
new SettingsButtonV2
9078
{
9179
Text = "Resync hardware audio offset",
92-
TooltipText = "Measures the device's AAudio pipeline latency over 2 s and applies the result (capped at 15 ms) to the audio offset. "
93-
+ "Shifts VISUAL hit-object timing to match when you hear the music. "
94-
+ "HITSOUND NOTE: any non-zero offset creates an equal hitsound-after-music lag; AudioOffset = 0 keeps hitsounds perfectly in sync with the music. "
95-
+ "If hitsounds feel off after Resync, lower the offset toward 0 manually. "
80+
TooltipText = "Measures the device's Oboe pipeline latency over 2 s and applies the full result as a negative AudioOffset. "
81+
+ "Shifts VISUAL hit-object timing so notes appear on screen when they should be hit. "
82+
+ "Both music and hitsounds travel through the same BASS → Oboe pipeline, so audio timing shifts together. "
9683
+ "For per-song tuning, use the in-game beatmap offset control during gameplay. "
9784
+ "Does NOT include Bluetooth A2DP delay (~100–300 ms extra) — fine-tune manually for BT output.",
9885
Action = () => game?.ResyncHardwareAudioOffset(),

osu.Game/osu.Game.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@
3838
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
3939
</PackageReference>
4040
<PackageReference Include="Realm" Version="20.1.0" />
41-
<PackageReference Include="ppy.osu.Framework" Version="2026.506.2" />
41+
<PackageReference Include="ppy.osu.Framework" Version="2026.506.4" />
4242
<!--
4343
Explicitly pin `ppy.Veldrid.SPIRV` to the winnerspiros fork build that
44-
`ppy.osu.Framework 2026.506.2` was compiled against.This version is the only
44+
`ppy.osu.Framework 2026.506.4` was compiled against.This version is the only
4545
one whose `runtimes/android-arm64/native/libveldrid-spirv.so` is aligned to 16 KB
4646
pages (required by Android 16+). It lives only as a release asset on
4747
<https://github.com/winnerspiros/veldrid-spirv/releases/tag/1.0> and is vendored

osu.iOS.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@
3333
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
3434
</PropertyGroup>
3535
<ItemGroup>
36-
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.506.2" />
36+
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.506.4" />
3737
</ItemGroup>
3838
</Project>

0 commit comments

Comments
 (0)