Retro_audio_callback busy waiting

hi,

i’m writing a core and atm im trying to get retro_audio_callback to work.

the problem I have is that my retro_audio_callback gets called 30000 times between each retro_run, which means retroarch is basically busy waiting on one CPU core with my callback.

my guess would be that that is because retroarch thinks i’m not feeding it enough audio samples.

here is how I calculate how many samples to send:

static constexpr size_t CHANNELS = 2;
static constexpr uint64_t MICROSECONDS_PER_SECOND = 1000000ul;
static constexpr uint64_t AUDIO_SAMPLING_RATE = 48000;
uint64_t samplesCount = (microseconds * AUDIO_SAMPLING_RATE) + leftOversampleRateMicroseconds;
leftOversampleRateMicroseconds = samplesCount % MICROSECONDS_PER_SECOND;
samplesCount /= MICROSECONDS_PER_SECOND;
samplesCount *= CHANNELS;

where

leftOversampleRateMicroseconds

is a member variable, so its value carries over to the next iteration and

microseconds

is the last value from retro_frame_time_callback.

the audio sounds perfectly fine so the values can’t be too far off and I don’t see how I could possibly make this any more exact.

is there a better way to know how many samples retroarch expects? or have i completely misdiagnosed the problem?

i’m using retroarch 1.2.2 on arch linux, in case it matters

Calling anything 30000 times per frame does indeed sound like a good way to blow things up.

My guess: Both RetroArch and your core are trying to handle the timing, and the two timers start fighting somehow. To fix, leave the timing to RetroArch: render five milliseconds or whatever for each call. The audio drivers should block if they’re overflowed.

The comments in libretro.h say you should use the frame time callback, but I can’t figure out what they’re useful for. Maybe the comments are wrong. It’s worth a try, at least.

If that doesn’t help, double check the following:

  • Do all parts of your code agree whether the sample count counts one {l,r} pair as one sample or two? Your math says two, as does libretro itself, but maybe your audio core doesn’t.
  • Are you actually calling the audio callback?
  • If you end up rendering zero samples, do you call the audio callback? I don’t know if they like blank inputs.
  • Does retro_system_timing::sample_rate have the correct value?
  • If retro_audio_callback::callback is called twice between two calls to retro_frame_time_callback::callback, does it do something sensible? What if the frame time callback is the one that comes twice in a row?

If the above doesn’t help either, post your entire source code somewhere and I’ll take a look.

[QUOTE=Alcaro;29747]My guess: Both RetroArch and your core are trying to handle the timing, and the two timers start fighting somehow. To fix, leave the timing to RetroArch: render five milliseconds or whatever for each call. The audio drivers should block if they’re overflowed.

The comments in libretro.h say you should use the frame time callback, but I can’t figure out what they’re useful for. Maybe the comments are wrong. It’s worth a try, at least.[/QUOTE] you’re right, that solved it. thank you!

those comments in libretro.h are really misleading, because of them I assumed it is expected that the core keeps track of “audio time”. now that I think about it, it actually makes a lot more sense to to it the way you suggested because it’s supposed to be completely asynchronous anyway so the exact amount sent per call shouldn’t matter.

now i’ve noticed something else thats strange:

when i slow down the gameplay the audio is handled correcly but when I speed it up, the audio continues to run at normal speed.

is this intentional? is the core supposed to skip over audio when the game is running too fast?

Only the frontend knows whether slowdown is going on and how slow it is, so the frontend should be the one to apply slowdown effects. Sounds like a RetroArch bug to me.

That frame time env is weird. The only use I’ve found for it is cores that don’t need a fixed framerate, like our 2048 core.

Actually, maybe that’s exactly the intended use for the async audio env too - cores with variable framerate, with fixed-rate cores expected to use the non-threaded interface. If the monitor is slightly too fast or slow, the Dynamic Rate Control will smooth that over.

So either it’s a RetroArch bug, or your core should use the non-threaded audio instead. Or maybe both. Unfortunately, the only one who knows is long gone.

[QUOTE=Alcaro;29767]That frame time env is weird. The only use I’ve found for it is cores that don’t need a fixed framerate, like our 2048 core.

Actually, maybe that’s exactly the intended use for the async audio env too - cores with variable framerate, with fixed-rate cores expected to use the non-threaded interface. If the monitor is slightly too fast or slow, the Dynamic Rate Control will smooth that over.[/QUOTE] the frame time env is very useful. I would argue that all games (as opposed to emulators) that are written against libretro should use it to allow for variable frame rates.

I’ve created an issue for the speed up problem here