Use dummy driver when JS AudioContext is unavailable.

This commit is contained in:
Fabio Alessandrelli 2020-06-29 18:51:53 +02:00
parent 399e2c1db0
commit 357e99a31e
5 changed files with 45 additions and 10 deletions

View File

@ -36,6 +36,15 @@
AudioDriverJavaScript *AudioDriverJavaScript::singleton = NULL; 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 { const char *AudioDriverJavaScript::get_name() const {
return "JavaScript"; return "JavaScript";
} }
@ -207,12 +216,14 @@ void AudioDriverJavaScript::finish_async() {
/* clang-format off */ /* clang-format off */
EM_ASM({ 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) { Module.async_finish.push(new Promise(function(accept, reject) {
if (!ref) { if (!ref) {
console.log("Ref not found!", $0, Module.IDHandler); console.log("Ref not found!", id, Module.IDHandler);
setTimeout(accept, 0); setTimeout(accept, 0);
} else { } else {
Module.IDHandler.remove(id);
const context = ref['context']; const context = ref['context'];
// Disconnect script and input. // Disconnect script and input.
ref['script'].disconnect(); ref['script'].disconnect();
@ -226,7 +237,6 @@ void AudioDriverJavaScript::finish_async() {
}); });
} }
})); }));
Module.IDHandler.remove($0);
}, id); }, id);
/* clang-format on */ /* clang-format on */
} }

View File

@ -41,6 +41,7 @@ class AudioDriverJavaScript : public AudioDriver {
int buffer_length; int buffer_length;
public: public:
static bool is_available();
void mix_to_js(); void mix_to_js();
void process_capture(float sample); void process_capture(float sample);

View File

@ -74,10 +74,17 @@ void main_loop_callback() {
} }
if (os->main_loop_iterate()) { if (os->main_loop_iterate()) {
emscripten_cancel_main_loop(); // Cancel current loop and wait for finalize_async. emscripten_cancel_main_loop(); // Cancel current loop and wait for finalize_async.
/* clang-format off */
EM_ASM({ EM_ASM({
// This will contain the list of operations that need to complete before cleanup. // 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->get_main_loop()->finish();
os->finalize_async(); // Will add all the async finish functions. os->finalize_async(); // Will add all the async finish functions.
EM_ASM({ EM_ASM({

View File

@ -297,7 +297,7 @@ EM_BOOL OS_JavaScript::keydown_callback(int p_event_type, const EmscriptenKeyboa
} }
os->input->parse_input_event(ev); os->input->parse_input_event(ev);
// Resume audio context after input in case autoplay was denied. // Resume audio context after input in case autoplay was denied.
os->audio_driver_javascript.resume(); os->resume_audio();
return true; 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); os->input->parse_input_event(ev);
// Resume audio context after input in case autoplay was denied. // 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. // Prevent multi-click text selection and wheel-click scrolling anchor.
// Context menu is prevented through contextmenu event. // Context menu is prevented through contextmenu event.
return true; 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); os->input->parse_input_event(ev);
} }
// Resume audio context after input in case autoplay was denied. // Resume audio context after input in case autoplay was denied.
os->audio_driver_javascript.resume(); os->resume_audio();
return true; return true;
} }
@ -1099,6 +1099,12 @@ MainLoop *OS_JavaScript::get_main_loop() const {
return main_loop; return main_loop;
} }
void OS_JavaScript::resume_audio() {
if (audio_driver_javascript) {
audio_driver_javascript->resume();
}
}
bool OS_JavaScript::main_loop_iterate() { bool OS_JavaScript::main_loop_iterate() {
if (is_userfs_persistent() && sync_wait_time >= 0) { if (is_userfs_persistent() && sync_wait_time >= 0) {
@ -1166,7 +1172,9 @@ void OS_JavaScript::finalize_async() {
}); });
Module.listeners = {}; Module.listeners = {};
}); });
audio_driver_javascript.finish_async(); if (audio_driver_javascript) {
audio_driver_javascript->finish_async();
}
} }
void OS_JavaScript::finalize() { void OS_JavaScript::finalize() {
@ -1176,6 +1184,9 @@ void OS_JavaScript::finalize() {
emscripten_webgl_commit_frame(); emscripten_webgl_commit_frame();
memdelete(visual_server); memdelete(visual_server);
emscripten_webgl_destroy_context(webgl_ctx); emscripten_webgl_destroy_context(webgl_ctx);
if (audio_driver_javascript) {
memdelete(audio_driver_javascript);
}
} }
// Miscellaneous // Miscellaneous
@ -1415,11 +1426,15 @@ OS_JavaScript::OS_JavaScript(int p_argc, char *p_argv[]) {
main_loop = NULL; main_loop = NULL;
visual_server = NULL; visual_server = NULL;
audio_driver_javascript = NULL;
idb_available = false; idb_available = false;
sync_wait_time = -1; 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<Logger *> loggers; Vector<Logger *> loggers;
loggers.push_back(memnew(StdLogger)); loggers.push_back(memnew(StdLogger));

View File

@ -66,7 +66,7 @@ class OS_JavaScript : public OS_Unix {
MainLoop *main_loop; MainLoop *main_loop;
int video_driver_index; int video_driver_index;
AudioDriverJavaScript audio_driver_javascript; AudioDriverJavaScript *audio_driver_javascript;
VisualServer *visual_server; VisualServer *visual_server;
bool idb_available; 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); static void file_access_close_callback(const String &p_file, int p_flags);
protected: protected:
void resume_audio();
virtual int get_current_video_driver() const; virtual int get_current_video_driver() const;
virtual void initialize_core(); virtual void initialize_core();