2
0
Эх сурвалжийг харах

Use dummy driver when JS AudioContext is unavailable.

Fabio Alessandrelli 5 жил өмнө
parent
commit
357e99a31e

+ 13 - 3
platform/javascript/audio_driver_javascript.cpp

@@ -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 */
 }
 }

+ 1 - 0
platform/javascript/audio_driver_javascript.h

@@ -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);
 
 

+ 8 - 1
platform/javascript/javascript_main.cpp

@@ -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({

+ 20 - 5
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);
 	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));

+ 3 - 1
platform/javascript/os_javascript.h

@@ -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();