Looking for advice on WebAudio problem on iOS Safari

438 views
Skip to first unread message

Floh

unread,
Dec 6, 2016, 8:16:38 AM12/6/16
to emscripten-discuss
Hi, 

on iOS Safari since iOS9, WebAudio will only work if 'unlocked' from an input event handler connected to a touch input event. Apart from the fact that I think that this is completely stupid and braindead behaviour of Safari, I'm looking for advice on how to best deal with this from the emscripten side (and more specifically, emscripten's SDL Audio wrapper)?

This behaviour has the unfortunate effect in my emulator (http://floooh.github.io/virtualkc/), that the emulator simply 'freezes' on iOS a few thousand cycles into the emulation since the emulator speed is linked to the audio playback (the emulated CPU will wait for or catch up whenever a new audio buffer is requested, but those buffer requests never happen). All my other demos with sound output are completely silent.

There is this issue thread on the topic: https://github.com/emscripten-ports/SDL2/issues/19, but this looks like a hack and is hard to integrate with my code (I'm simply using the SoLoud audio lib with the SDL backend).

So my questions:

- did anybody find a smaller / more elegant workaround which doen't use the SDL event system and is as non-intrusive as possible?

- is this something that should better go into the emscripten SDL wrapper code? (for instance, all SDL code would silently appear to work on iOS without sound output until a touch event happens?)

Thanks & Cheers,
-Floh.

Jukka Jylänki

unread,
Dec 8, 2016, 3:11:54 AM12/8/16
to emscripte...@googlegroups.com
I think the example 2 from https://paulbakaus.com/tutorials/html5/web-audio-on-ios/#How_do_I_know_when_my_context_is_unlocked should be usable with fair ease, e.g. via a --pre-js, or via using the emscripten/html5.h event handler registration functions. Would that work?

This could be done as a runDependency (add/removeRunDependency() functions) to create that kind of "tap to play" type of launcher, which user would need to tap on to make the Emscripten main() actually run. (or if you have another location after main() but before the render loop, that might be a suitable place as well)

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Floh

unread,
Dec 9, 2016, 2:55:00 AM12/9/16
to emscripten-discuss
That link gives a good description of the problem and why Apple is doing this, thanks!

I'll play around with your suggestions, I think I'll the hooking to a touch event first via the emscripten event functions and then use EM_ASM to unlock the WebAudio context. I'd like to avoid to delay main() execution until tapped, instead I'll just let the emulator 'freeze', and if I'm detecting that it is in this frozen state, ask the user to "Tap to Unfreeze" or something.

The emulator is a bit of a special case because of thatl freeze if there's no audio playback, I think most other apps/games would be fine if audio playback is muted until the first tap.

Cheers,
-Floh.

Floh

unread,
Feb 10, 2017, 5:51:44 AM2/10/17
to emscripten-discuss
Ok for future visitors, I finally got around to try it out and here's a solution that seems to work fine:

- I'm using soloud (http://sol.gfxile.net/soloud/) with the sdl_static backend
- I'm skipping soloud init and all calls into it until WebAudio has been 'unlocked'
- in a mousedown / touchstart event handler installed with the emscripten_set_mousedown/touchstart_callback function I have a an inline EM_ASM block which calls SDL.openAudioContext() in the browser module before the SDL_OpenAudio does, and do the things described here (https://paulbakaus.com/tutorials/html5/web-audio-on-ios/ )

This is what the complete input event callback looks like (I'm currently doing the same thing on all browsers):

    // on iOS, WebAudio can only be initialized from a touch event,

    // so we initialize soloud from within here, and tell the soundMgr

    // that it is ok now to play audio 

    //

    // https://paulbakaus.com/tutorials/html5/web-audio-on-ios/

    EM_ASM(

        SDL.openAudioContext();

var buffer = SDL.audioContext.createBuffer(1, 1, 22050);

var source = SDL.audioContext.createBufferSource();

source.buffer = buffer;

source.connect(SDL.audioContext.destination);

source.start(0);

    );


    SoundMgr* self = (SoundMgr*) userData;

    if (!self->audioValid) {

        self->soloud.init();

        self->audioValid = true;

    }

    return false;

Reply all
Reply to author
Forward
0 new messages