Skip to content

Games: drive the asynchronous audio interface - #153

Closed
sunlollyking wants to merge 1 commit into
garbear:masterfrom
sunlollyking:async-audio-interface
Closed

Games: drive the asynchronous audio interface#153
sunlollyking wants to merge 1 commit into
garbear:masterfrom
sunlollyking:async-audio-interface

Conversation

@sunlollyking

@sunlollyking sunlollyking commented Aug 12, 2026

Copy link
Copy Markdown

Kodi accepts a client's registration for the asynchronous audio interface and then never asks it for audio.

A client on that interface produces no audio of its own accord — it waits to be asked, and writes what it has from the thread it was asked on. Since nothing ever asks, it stays silent for the whole session.

Silence isn't the only symptom. The frame rate is paced against the audio a client delivers, so a client that is never asked also runs as fast as the machine allows rather than at the speed of the console. That's how I found it: a Dreamcast core running at roughly double speed, with no sound.

game.libretro has had the client half implemented for years, with a comment noting "this function is not part of the Game API yet". This adds it to the API and calls it once per frame, alongside RunFrame().

Compatibility

Clients on the ordinary synchronous audio path inherit the default AudioAvailable(), which returns GAME_ERROR_NOT_IMPLEMENTED, and are unaffected — no source change needed in any existing add-on.

Adding an entry to KodiToAddonFuncTable_Game does change the layout of a struct shared with add-on binaries, so this bumps the game instance version to 7.0.0 and the minimum with it. Existing add-ons need a rebuild, not a code change. Happy to split the bump out or sequence it behind whatever else is queued for 7.0.0 if you'd rather batch the ABI breaks.

Testing

Verified against Flycast via game.libretro, on the hardware-rendering branch: the client goes from silent to producing audio, and the pacing follows.

One caveat worth stating plainly — Flycast needed a separate game.libretro fix (answering RETRO_ENVIRONMENT_GET_FASTFORWARDING) before it produced any audio at all, so that core exercised both changes together. The reasoning here stands on its own: the interface is registered and then never driven.

Kodi accepts a client's registration for the asynchronous audio interface and
then never asks it for audio. A client on that interface produces none of its
own accord -- it waits to be asked and writes what it has from the thread it
was asked on -- so it stays silent for the whole session.

Silence is not the only symptom. The frame rate is paced against the audio a
client delivers, so one that is never asked also runs as fast as the machine
allows rather than at the speed of the console.

game.libretro has had the client half of this implemented for years, noting
"this function is not part of the Game API yet". Add it to the API and call it
once per frame, alongside RunFrame(). Clients on the ordinary synchronous audio
path answer GAME_ERROR_NOT_IMPLEMENTED and are unaffected.

Adding an entry to KodiToAddonFuncTable_Game changes the layout of a struct
shared with add-on binaries, so the game instance version goes to 7.0.0 and the
minimum with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sunlollyking
sunlollyking requested a review from garbear as a code owner August 12, 2026 10:48
@garbear

garbear commented Aug 13, 2026

Copy link
Copy Markdown
Owner

This is a small, great, well-contained impactful fix. The only contention is the API bump, as the team wants APIs frozen for B2 release. That said, B2 isn't out yet. And I'm kinda left to my own for game stuff. So any changes to the API we need PRd against master ASAP.

char*(__cdecl* GetImageLabel)(const AddonInstance_Game*, unsigned int);
void(__cdecl* FreeString)(const AddonInstance_Game*, char*);

/*!

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Drop the doxy here, instead of documenting the C-level function pointers, we document API functions in the C++ header Game.h. If the doc here introduces new info, maybe combine the docs. But the doc in Game.h looks good.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Carried over into the upstream PR, xbmc#28964, which is the one that merged — AudioAvailable sits in the C table with no doxy on it, and the documentation lives on the C++ side in Game.h as you asked. Nothing outstanding here; this PR was superseded rather than abandoned.

@garbear garbear left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

The change here looks great. I haven't confirmed by reading the libretro.h API, but testing in the PR description confirms correctness.

We should also test rewind and fast-forward. But I think RetroPlayer silences audio in these situations.

@garbear

garbear commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Last night I did a round of RetroPlayer test builds that included this change. I haven't runtime tested, but it certainly builds successfully in the RetroPlayer patchset.

Specifically I did a test builds with these PRs:

[PR 153] Game API v7.0.0: Drive the asynchronous audio interface
[PR 152] Games: remember which emulator to open a game with
[PR 150] RetroPlayer: Add RetroAchievements Game API callbacks

I'm kinda swamped with the B2 release and day job, so anything we wanna ship in B2 I'll need help merging upstream. Can you list all PRs with new features or API bumps? (Anything not a fix, which are allowed in RC 1).

If you can list all PRs we want in B2, I'll do a combined build (basically what I did last night but also uploaded to the mirrors for distribution on my Releases page).

If you can make a list of everything we wanna ship in B2, I'll get it all in the release.

@sunlollyking

Copy link
Copy Markdown
Author

Smashing and yep i'll do that in about 12 hours - Morning for me!

@sunlollyking

sunlollyking commented Aug 14, 2026

Copy link
Copy Markdown
Author

Here's the full list, split by what needs to beat the freeze.

Needs to land before B2 — API bump or new feature

PR What Status
#153 Async audio interface. Game API → 7.0.0 Approved by you
#152 Remember which emulator opens a game Feature
#150 RetroAchievements Game API callbacks API additions
kodi-game/game.libretro#162 Move rc_client ownership into game.libretro Pairs with #150

Those four are the ones the freeze actually bites. #153 is the only one that moves the API version number; #150 adds callbacks alongside it.

Fixes — fine for RC1, no rush

PR What
#154 Rumble: request never reaches the peripheral, and nothing ever maps a motor
kodi-game/game.libretro#166 Read core options from SET_CORE_OPTIONS / _INTL / _V2
kodi-game/game.libretro#167 Three audio fixes, incl. GET_FASTFORWARDING (Dreamcast was silent)
kodi-game/game.libretro#168 Per-core system and save directories
xbmc/peripheral.joystick#347 Default the Linux driver to udev (rumble needs it)
kodi-game/game.libretro.flycast#11 Dreamcast triggers mapped to the wrong ids — Crazy Taxi unplayable

xbmc#347 is worth pulling forward despite being a fix — you mentioned wanting the udev switch before B2, and it's a one-line default change.

Not for v22

#151 and kodi-game/game.libretro#164 — hardware rendering. Still experimental, carries its own API bump, and I have open defects on it. Not something to rush into a release.

On the API bump

You said API changes need to go against xbmc/xbmc master ASAP. #153 is the only one of mine that does. Say the word and I'll open it there — it's a clean 45-line diff off master with no dependencies on the rest of this, so it can go in on its own. Same for #152 if you want the feature in, though that one touches no API.

@garbear

garbear commented Aug 14, 2026

Copy link
Copy Markdown
Owner

This late in the B2 cycle, we can get the RA callbacks in because we have to bump anyway due to the audio fix. I can spin the huge RA patch cuz it only affects games. I'll let the team know, and when I get a chance (could be 24hr) we'll plot a path to merge both game API bumps.

@sunlollyking

Copy link
Copy Markdown
Author

Revised list — three additions since my last, and one removal.

Needs to land before B2 — API bump or new feature

PR What Status
#153 Async audio interface. Game API → 7.0.0 Approved by you
#152 Remember which emulator opens a game Feature

Rumble — three PRs, one chain, all fixes

Rumble has never worked for any controller with any emulator. It takes all three of these; each is inert without the others:

PR What
#154 The request never reaches the peripheral, and nothing ever maps a motor
xbmc/peripheral.joystick#347 Default the Linux driver to udev — the joystick API has no force feedback at all
kodi-game/game.libretro#169 Unplugging a controller mid-game can crash the emulator

xbmc#169 isn't strictly rumble, but it came out of the same testing: CInputManager has no locking, so a disconnect can free a device the core is mid-dereference. Flycast took a real SIGSEGV that way and aborted itself. Worth having in B2 on its own merit — "unplug a pad, lose your game" is easy to hit by accident.

Other fixes — fine for RC1

PR What
kodi-game/game.libretro#166 Core options via SET_CORE_OPTIONS / _INTL / _V2
kodi-game/game.libretro#167 Three audio fixes, incl. GET_FASTFORWARDING (Dreamcast was silent)
kodi-game/game.libretro#168 Per-core system and save directories
kodi-game/game.libretro.flycast#11 Dreamcast triggers on the wrong ids — Crazy Taxi unplayable

Removing the achievements work from the B2 list

I had #150 and kodi-game/game.libretro#162 down for B2. On reflection I'd pull both, and I'd rather say why than quietly drop them.

They're a much larger surface than anything else here — a new dependency, network and login handling, memory-map wiring per core — and unlike #153 they haven't been through upstream review. My testing has been good (82/83 achievements active on Dreamcast, 21/21 memory addresses valid) but it's been my testing, on one box, against a handful of cores. Landing that during a freeze is the kind of thing that produces a bad release rather than a good feature.

They'd be much better as the first thing in the next cycle, with room to be reviewed properly.

Entirely your call — if you'd rather have them in B2 they're ready to build, and I'll support whichever way you go.

Still not for v22

#151 and kodi-game/game.libretro#164 — hardware rendering. Experimental, own API bump, open defects.

On the API bump

#153 is still the only PR of mine that touches the API version. Say the word and I'll open it against xbmc/xbmc master — clean 45-line diff, no dependencies on anything else here.

@sunlollyking

Copy link
Copy Markdown
Author

Ignore the removal in my last comment — I wrote it without having read yours first, and argued against a call you'd already made. Apologies for the noise.

You're right that the bump is the expensive part and it's being paid anyway. Here's the corrected list.

B2 — the two Game API bumps

PR What
#153 Async audio interface. Game API → 7.0.0
#150 RetroAchievements Game API callbacks
kodi-game/game.libretro#162 Move rc_client ownership into game.libretro — the add-on half of #150, needs to land with it

xbmc#162 isn't an API bump itself but is the other half of #150; they don't work apart.

B2 — feature

PR What
#152 Remember which emulator opens a game

B2 — rumble, three PRs forming one chain

Rumble has never worked for any controller with any emulator. Each of these is inert without the others:

PR What
#154 The request never reaches the peripheral, and nothing ever maps a motor
xbmc/peripheral.joystick#347 Default the Linux driver to udev — the joystick API has no force feedback at all
kodi-game/game.libretro#169 Unplugging a controller mid-game can crash the emulator

Fixes — fine for RC1

PR What
kodi-game/game.libretro#166 Core options via SET_CORE_OPTIONS / _INTL / _V2
kodi-game/game.libretro#167 Three audio fixes, incl. GET_FASTFORWARDING (Dreamcast was silent)
kodi-game/game.libretro#168 Per-core system and save directories
kodi-game/game.libretro.flycast#11 Dreamcast triggers on the wrong ids — Crazy Taxi unplayable

Not for v22

#151 and kodi-game/game.libretro#164 — hardware rendering. Experimental, own API bump, open defects.

What I'd still flag on the RA work

Not as an argument against shipping it — your call and you've made it — just so it's on the record: my testing has been on one box against a handful of cores (82/83 achievements active on Dreamcast, 21/21 memory addresses valid), and it hasn't had upstream review. If anything bites in B2 it's most likely to be there, and I'll be around to fix it quickly.

Happy to open #153 and #150 against xbmc/xbmc master whenever you want to plot that path.

@garbear

garbear commented Aug 14, 2026

Copy link
Copy Markdown
Owner

We're still plotting, but yeah let's break B2. That's what RC 1 is for, getting in fixes for the cool shit we added in the alpha/beta cycle.

@garbear

garbear commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Completed in xbmc#28964.

@garbear garbear closed this Aug 18, 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