Преглед изворни кода

Merge pull request #94044 from adamscott/fix-web-sample-playback-finished-signal

Fix Web samples finished missing signal
Rémi Verschelde пре 1 година
родитељ
комит
42e5b3ac2d

+ 32 - 0
platform/web/audio_driver_web.cpp

@@ -33,6 +33,8 @@
 #include "godot_audio.h"
 
 #include "core/config/project_settings.h"
+#include "core/object/object.h"
+#include "scene/main/node.h"
 #include "servers/audio/audio_stream.h"
 
 #include <emscripten.h>
@@ -51,6 +53,33 @@ void AudioDriverWeb::_latency_update_callback(float p_latency) {
 	AudioDriverWeb::audio_context.output_latency = p_latency;
 }
 
+void AudioDriverWeb::_sample_playback_finished_callback(const char *p_playback_object_id) {
+	const ObjectID playback_id = ObjectID(String::to_int(p_playback_object_id));
+
+	Object *playback_object = ObjectDB::get_instance(playback_id);
+	if (playback_object == nullptr) {
+		return;
+	}
+	Ref<AudioSamplePlayback> playback = Object::cast_to<AudioSamplePlayback>(playback_object);
+	if (playback.is_null()) {
+		return;
+	}
+
+	Object *player_object = ObjectDB::get_instance(playback->player_id);
+	if (player_object == nullptr) {
+		return;
+	}
+	Node *player = Object::cast_to<Node>(player_object);
+	if (player == nullptr) {
+		return;
+	}
+
+	const StringName finished = SNAME("finished");
+	if (player->has_signal(finished)) {
+		player->emit_signal(finished);
+	}
+}
+
 void AudioDriverWeb::_audio_driver_process(int p_from, int p_samples) {
 	int32_t *stream_buffer = reinterpret_cast<int32_t *>(output_rb);
 	const int max_samples = memarr_len(output_rb);
@@ -132,6 +161,9 @@ Error AudioDriverWeb::init() {
 	if (!input_rb) {
 		return ERR_OUT_OF_MEMORY;
 	}
+
+	godot_audio_sample_set_finished_callback(&_sample_playback_finished_callback);
+
 	return OK;
 }
 

+ 1 - 0
platform/web/audio_driver_web.h

@@ -58,6 +58,7 @@ private:
 
 	WASM_EXPORT static void _state_change_callback(int p_state);
 	WASM_EXPORT static void _latency_update_callback(float p_latency);
+	WASM_EXPORT static void _sample_playback_finished_callback(const char *p_playback_object_id);
 
 	static AudioDriverWeb *singleton;
 

+ 1 - 0
platform/web/godot_audio.h

@@ -57,6 +57,7 @@ extern void godot_audio_sample_set_pause(const char *p_playback_object_id, bool
 extern int godot_audio_sample_is_active(const char *p_playback_object_id);
 extern void godot_audio_sample_update_pitch_scale(const char *p_playback_object_id, float p_pitch_scale);
 extern void godot_audio_sample_set_volumes_linear(const char *p_playback_object_id, int *p_buses_buf, int p_buses_size, float *p_volumes_buf, int p_volumes_size);
+extern void godot_audio_sample_set_finished_callback(void (*p_callback)(const char *));
 
 extern void godot_audio_sample_bus_set_count(int p_count);
 extern void godot_audio_sample_bus_remove(int p_index);

+ 25 - 2
platform/web/js/libs/library_godot_audio.js

@@ -687,9 +687,15 @@ class SampleNode {
 			}
 
 			switch (self.getSample().loopMode) {
-			case 'disabled':
+			case 'disabled': {
+				const id = this.id;
 				self.stop();
-				break;
+				if (GodotAudio.sampleFinishedCallback != null) {
+					const idCharPtr = GodotRuntime.allocString(id);
+					GodotAudio.sampleFinishedCallback(idCharPtr);
+					GodotRuntime.free(idCharPtr);
+				}
+			} break;
 			case 'forward':
 			case 'backward':
 				self.restart();
@@ -1090,6 +1096,12 @@ const _GodotAudio = {
 		busSolo: null,
 		Bus,
 
+		/**
+		 * Callback to signal that a sample has finished.
+		 * @type {(playbackObjectIdPtr: number) => void | null}
+		 */
+		sampleFinishedCallback: null,
+
 		/** @type {AudioContext} */
 		ctx: null,
 		input: null,
@@ -1764,6 +1776,17 @@ const _GodotAudio = {
 	godot_audio_sample_bus_set_mute: function (bus, enable) {
 		GodotAudio.set_sample_bus_mute(bus, Boolean(enable));
 	},
+
+	godot_audio_sample_set_finished_callback__proxy: 'sync',
+	godot_audio_sample_set_finished_callback__sig: 'vi',
+	/**
+	 * Sets the finished callback
+	 * @param {Number} callbackPtr Finished callback pointer
+	 * @returns {void}
+	 */
+	godot_audio_sample_set_finished_callback: function (callbackPtr) {
+		GodotAudio.sampleFinishedCallback = GodotRuntime.get_func(callbackPtr);
+	},
 };
 
 autoAddDeps(_GodotAudio, '$GodotAudio');

+ 1 - 0
scene/audio/audio_stream_player_internal.cpp

@@ -152,6 +152,7 @@ Ref<AudioStreamPlayback> AudioStreamPlayerInternal::play_basic() {
 				Ref<AudioSamplePlayback> sample_playback;
 				sample_playback.instantiate();
 				sample_playback->stream = stream;
+				sample_playback->player_id = node->get_instance_id();
 				stream_playback->set_sample_playback(sample_playback);
 			}
 		} else if (!stream->is_meta_stream()) {

+ 1 - 0
servers/audio/audio_stream.h

@@ -49,6 +49,7 @@ class AudioSamplePlayback : public RefCounted {
 public:
 	Ref<AudioStream> stream;
 
+	ObjectID player_id;
 	float offset = 0.0f;
 	Vector<AudioFrame> volume_vector;
 	StringName bus;