From 357e99a31e00f4193f218dd6d10e808717a6420f Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 29 Jun 2020 18:51:53 +0200 Subject: [PATCH] Use dummy driver when JS AudioContext is unavailable. --- .../javascript/audio_driver_javascript.cpp | 16 +++++++++--- platform/javascript/audio_driver_javascript.h | 1 + platform/javascript/javascript_main.cpp | 9 ++++++- platform/javascript/os_javascript.cpp | 25 +++++++++++++++---- platform/javascript/os_javascript.h | 4 ++- 5 files changed, 45 insertions(+), 10 deletions(-) diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index 620135e1e17..51939ee824e 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -36,6 +36,15 @@ AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL; +bool AudioDriverJavaScript::is_available() { + return EM_ASM_INT({ + if (!(window.AudioContext || window.webkitAudioContext)) { + return 0; + } + return 1; + }) != 0; +} + const char *AudioDriverJavaScript::get_name() const { return "JavaScript"; } @@ -207,12 +216,14 @@ void AudioDriverJavaScript::finish_async() { /* clang-format off */ EM_ASM({ - var ref = Module.IDHandler.get($0); + const id = $0; + var ref = Module.IDHandler.get(id); Module.async_finish.push(new Promise(function(accept, reject) { if (!ref) { - console.log("Ref not found!", $0, Module.IDHandler); + console.log("Ref not found!", id, Module.IDHandler); setTimeout(accept, 0); } else { + Module.IDHandler.remove(id); const context = ref['context']; // Disconnect script and input. ref['script'].disconnect(); @@ -226,7 +237,6 @@ void AudioDriverJavaScript::finish_async() { }); } })); - Module.IDHandler.remove($0); }, id); /* clang-format on */ } diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index c23d46fd191..6c9a9dbbeb8 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -41,6 +41,7 @@ class AudioDriverJavaScript : public AudioDriver { int buffer_length; public: + static bool is_available(); void mix_to_js(); void process_capture(float sample); diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 33a7343eccf..87699271a02 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -74,10 +74,17 @@ void main_loop_callback() { } if (os->main_loop_iterate()) { emscripten_cancel_main_loop(); // Cancel current loop and wait for finalize_async. + /* clang-format off */ EM_ASM({ // This will contain the list of operations that need to complete before cleanup. - Module.async_finish = []; + Module.async_finish = [ + // Always contains at least one async promise, to avoid firing immediately if nothing is added. + new Promise(function(accept, reject) { + setTimeout(accept, 0); + }) + ]; }); + /* clang-format on */ os->get_main_loop()->finish(); os->finalize_async(); // Will add all the async finish functions. EM_ASM({ diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 3508639a4e8..d6b806a8f79 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -297,7 +297,7 @@ EM_BOOL OS_JavaScript::keydown_callback(int p_event_type, const EmscriptenKeyboa } os->input->parse_input_event(ev); // Resume audio context after input in case autoplay was denied. - os->audio_driver_javascript.resume(); + os->resume_audio(); return true; } @@ -390,7 +390,7 @@ EM_BOOL OS_JavaScript::mouse_button_callback(int p_event_type, const EmscriptenM os->input->parse_input_event(ev); // Resume audio context after input in case autoplay was denied. - os->audio_driver_javascript.resume(); + os->resume_audio(); // Prevent multi-click text selection and wheel-click scrolling anchor. // Context menu is prevented through contextmenu event. return true; @@ -742,7 +742,7 @@ EM_BOOL OS_JavaScript::touch_press_callback(int p_event_type, const EmscriptenTo os->input->parse_input_event(ev); } // Resume audio context after input in case autoplay was denied. - os->audio_driver_javascript.resume(); + os->resume_audio(); return true; } @@ -1099,6 +1099,12 @@ MainLoop *OS_JavaScript::get_main_loop() const { return main_loop; } +void OS_JavaScript::resume_audio() { + if (audio_driver_javascript) { + audio_driver_javascript->resume(); + } +} + bool OS_JavaScript::main_loop_iterate() { if (is_userfs_persistent() && sync_wait_time >= 0) { @@ -1166,7 +1172,9 @@ void OS_JavaScript::finalize_async() { }); Module.listeners = {}; }); - audio_driver_javascript.finish_async(); + if (audio_driver_javascript) { + audio_driver_javascript->finish_async(); + } } void OS_JavaScript::finalize() { @@ -1176,6 +1184,9 @@ void OS_JavaScript::finalize() { emscripten_webgl_commit_frame(); memdelete(visual_server); emscripten_webgl_destroy_context(webgl_ctx); + if (audio_driver_javascript) { + memdelete(audio_driver_javascript); + } } // Miscellaneous @@ -1415,11 +1426,15 @@ OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) { main_loop = NULL; visual_server = NULL; + audio_driver_javascript = NULL; idb_available = false; sync_wait_time = -1; - AudioDriverManager::add_driver(&audio_driver_javascript); + if (AudioDriverJavaScript::is_available()) { + audio_driver_javascript = memnew(AudioDriverJavaScript); + AudioDriverManager::add_driver(audio_driver_javascript); + } Vector loggers; loggers.push_back(memnew(StdLogger)); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index acfe14343e2..d27d9958e3d 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -66,7 +66,7 @@ class OS_JavaScript : public OS_Unix { MainLoop *main_loop; int video_driver_index; - AudioDriverJavaScript audio_driver_javascript; + AudioDriverJavaScript *audio_driver_javascript; VisualServer *visual_server; bool idb_available; @@ -93,6 +93,8 @@ class OS_JavaScript : public OS_Unix { static void file_access_close_callback(const String &p_file, int p_flags); protected: + void resume_audio(); + virtual int get_current_video_driver() const; virtual void initialize_core();