Skip to content

Commit 42e5b3a

Browse files
committed
Merge pull request godotengine#94044 from adamscott/fix-web-sample-playback-finished-signal
Fix Web samples finished missing signal
2 parents 56df419 + a38f30f commit 42e5b3a

File tree

6 files changed

+61
-2
lines changed

6 files changed

+61
-2
lines changed

platform/web/audio_driver_web.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#include "godot_audio.h"
3434

3535
#include "core/config/project_settings.h"
36+
#include "core/object/object.h"
37+
#include "scene/main/node.h"
3638
#include "servers/audio/audio_stream.h"
3739

3840
#include <emscripten.h>
@@ -51,6 +53,33 @@ void AudioDriverWeb::_latency_update_callback(float p_latency) {
5153
AudioDriverWeb::audio_context.output_latency = p_latency;
5254
}
5355

56+
void AudioDriverWeb::_sample_playback_finished_callback(const char *p_playback_object_id) {
57+
const ObjectID playback_id = ObjectID(String::to_int(p_playback_object_id));
58+
59+
Object *playback_object = ObjectDB::get_instance(playback_id);
60+
if (playback_object == nullptr) {
61+
return;
62+
}
63+
Ref<AudioSamplePlayback> playback = Object::cast_to<AudioSamplePlayback>(playback_object);
64+
if (playback.is_null()) {
65+
return;
66+
}
67+
68+
Object *player_object = ObjectDB::get_instance(playback->player_id);
69+
if (player_object == nullptr) {
70+
return;
71+
}
72+
Node *player = Object::cast_to<Node>(player_object);
73+
if (player == nullptr) {
74+
return;
75+
}
76+
77+
const StringName finished = SNAME("finished");
78+
if (player->has_signal(finished)) {
79+
player->emit_signal(finished);
80+
}
81+
}
82+
5483
void AudioDriverWeb::_audio_driver_process(int p_from, int p_samples) {
5584
int32_t *stream_buffer = reinterpret_cast<int32_t *>(output_rb);
5685
const int max_samples = memarr_len(output_rb);
@@ -132,6 +161,9 @@ Error AudioDriverWeb::init() {
132161
if (!input_rb) {
133162
return ERR_OUT_OF_MEMORY;
134163
}
164+
165+
godot_audio_sample_set_finished_callback(&_sample_playback_finished_callback);
166+
135167
return OK;
136168
}
137169

platform/web/audio_driver_web.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class AudioDriverWeb : public AudioDriver {
5858

5959
WASM_EXPORT static void _state_change_callback(int p_state);
6060
WASM_EXPORT static void _latency_update_callback(float p_latency);
61+
WASM_EXPORT static void _sample_playback_finished_callback(const char *p_playback_object_id);
6162

6263
static AudioDriverWeb *singleton;
6364

platform/web/godot_audio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ extern void godot_audio_sample_set_pause(const char *p_playback_object_id, bool
5757
extern int godot_audio_sample_is_active(const char *p_playback_object_id);
5858
extern void godot_audio_sample_update_pitch_scale(const char *p_playback_object_id, float p_pitch_scale);
5959
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);
60+
extern void godot_audio_sample_set_finished_callback(void (*p_callback)(const char *));
6061

6162
extern void godot_audio_sample_bus_set_count(int p_count);
6263
extern void godot_audio_sample_bus_remove(int p_index);

platform/web/js/libs/library_godot_audio.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -687,9 +687,15 @@ class SampleNode {
687687
}
688688

689689
switch (self.getSample().loopMode) {
690-
case 'disabled':
690+
case 'disabled': {
691+
const id = this.id;
691692
self.stop();
692-
break;
693+
if (GodotAudio.sampleFinishedCallback != null) {
694+
const idCharPtr = GodotRuntime.allocString(id);
695+
GodotAudio.sampleFinishedCallback(idCharPtr);
696+
GodotRuntime.free(idCharPtr);
697+
}
698+
} break;
693699
case 'forward':
694700
case 'backward':
695701
self.restart();
@@ -1090,6 +1096,12 @@ const _GodotAudio = {
10901096
busSolo: null,
10911097
Bus,
10921098

1099+
/**
1100+
* Callback to signal that a sample has finished.
1101+
* @type {(playbackObjectIdPtr: number) => void | null}
1102+
*/
1103+
sampleFinishedCallback: null,
1104+
10931105
/** @type {AudioContext} */
10941106
ctx: null,
10951107
input: null,
@@ -1764,6 +1776,17 @@ const _GodotAudio = {
17641776
godot_audio_sample_bus_set_mute: function (bus, enable) {
17651777
GodotAudio.set_sample_bus_mute(bus, Boolean(enable));
17661778
},
1779+
1780+
godot_audio_sample_set_finished_callback__proxy: 'sync',
1781+
godot_audio_sample_set_finished_callback__sig: 'vi',
1782+
/**
1783+
* Sets the finished callback
1784+
* @param {Number} callbackPtr Finished callback pointer
1785+
* @returns {void}
1786+
*/
1787+
godot_audio_sample_set_finished_callback: function (callbackPtr) {
1788+
GodotAudio.sampleFinishedCallback = GodotRuntime.get_func(callbackPtr);
1789+
},
17671790
};
17681791

17691792
autoAddDeps(_GodotAudio, '$GodotAudio');

scene/audio/audio_stream_player_internal.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ Ref<AudioStreamPlayback> AudioStreamPlayerInternal::play_basic() {
152152
Ref<AudioSamplePlayback> sample_playback;
153153
sample_playback.instantiate();
154154
sample_playback->stream = stream;
155+
sample_playback->player_id = node->get_instance_id();
155156
stream_playback->set_sample_playback(sample_playback);
156157
}
157158
} else if (!stream->is_meta_stream()) {

servers/audio/audio_stream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class AudioSamplePlayback : public RefCounted {
4949
public:
5050
Ref<AudioStream> stream;
5151

52+
ObjectID player_id;
5253
float offset = 0.0f;
5354
Vector<AudioFrame> volume_vector;
5455
StringName bus;

0 commit comments

Comments
 (0)