Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when playing back sound from gdextension using web target #1350

Open
nonameentername opened this issue Jan 6, 2024 · 6 comments
Open
Labels
bug This has been identified as a bug confirmed platform:web
Milestone

Comments

@nonameentername
Copy link

Godot version

4.2.1

godot-cpp version

4.2.1

System information

Ubuntu 23.10, Intel Core i7, NVIDIA GeForce RTX 3050 / Google Chrome Version 120.0.6099.109 (64-bit)

Issue description

I created a project that has a gdextension stream that generates a tone. The class is then attached to an AudioStreamPlayer to generate the sounds. This works in native Linux and Windows builds. When exporting to Web the Chrome console displays the following error message:

example.worker.js:154 Uncaught RuntimeError: null function or function signature mismatch
    at wasm://wasm/00355cda:wasm-function[377]:0x5b69c
    at wasm://wasm/00355cda:wasm-function[294]:0x52065
    at AudioStreamPlayback::mix(AudioFrame*, float, int) (wasm://wasm/0cc285be:wasm-function[68476]:0x2168830)
    at AudioDriver::audio_server_process(int, int*, bool) (wasm://wasm/0cc285be:wasm-function[572]:0x290156)
    at AudioDriverWorklet::_audio_thread_func(void*) (wasm://wasm/0cc285be:wasm-function[570]:0x28f86e)
    at Thread::callback(unsigned long long, Thread::Settings const&, void (*)(void*), void*) (wasm://wasm/0cc285be:wasm-function[72332]:0x23def16)
    at void* std::__2::__thread_proxy[abi:v15007]<std::__2::tuple<std::__2::unique_ptr<std::__2::__thread_struct, std::__2::default_delete<std::__2::__thread_struct>>, void (*)(unsigned long long, Thread::Settings const&, void (*)(void*), void*), unsigned long long, Thread::Settings, void (*)(void*), void*>>(void*) (wasm://wasm/0cc285be:wasm-function[72334]:0x23df05d)
    at Object.invokeEntryPoint (http://127.0.0.1:8060/example.js:4155:37)
    at handleMessage (http://127.0.0.1:8060/example.worker.js:122:35)
$func377 @ 00355cda:0x5b69c
$func294 @ 00355cda:0x52065
$AudioStreamPlayback::mix(AudioFrame*, float, int) @ 0cc285be:0x2168830
$AudioDriver::audio_server_process(int, int*, bool) @ 0cc285be:0x290156
$AudioDriverWorklet::_audio_thread_func(void*) @ 0cc285be:0x28f86e
$Thread::callback(unsigned long long, Thread::Settings const&, void (*)(void*), void*) @ 0cc285be:0x23def16
$void* std::__2::__thread_proxy[abi:v15007]<std::__2::tuple<std::__2::unique_ptr<std::__2::__thread_struct, std::__2::default_delete<std::__2::__thread_struct>>, void (*)(unsigned long long, Thread::Settings const&, void (*)(void*), void*), unsigned long long, Thread::Settings, void (*)(void*), void*>>(void*) @ 0cc285be:0x23df05d
invokeEntryPoint @ example.js:4155

Steps to reproduce

I created an example project that reproduces the error:
godot-custom-audiostream

To reproduce the error compile and export project using web target.
On the browser the error can be viewed using the Google chrome console.

Minimal reproduction project

godot-custom-audiostream

@Faless
Copy link
Contributor

Faless commented Jan 8, 2024

Make sure you are using emscripten version 3.1.39 to build the gdextension (which is what we use in Godot builds).
Emscripten changes its DSO format from time to time, breaking compatibility with older versions, this is a limitation of emscripten itself (and in part of WebAssembly that did not fully standardize it AFAIU).
See also: WebAssembly/tool-conventions#154

@nonameentername
Copy link
Author

I'm using version 3.1.39. I included the build script I'm using in the reproduction project: Link

@dsnopek dsnopek added bug This has been identified as a bug confirmed platform:web labels Apr 9, 2024
@dsnopek dsnopek added this to the 4.x milestone Apr 9, 2024
@dsnopek
Copy link
Contributor

dsnopek commented Apr 9, 2024

Thanks for the MRP!

It took a few little changes, but I got the project generating a tone on Linux. Then built and exported for the web, and I'm getting the exact same errors in the browser console as shown in the issue description, and not getting the tone.

So, I'm able to confirm the issue.

@dsnopek
Copy link
Contributor

dsnopek commented Apr 9, 2024

The error seems to be coming from when AudioStreamPlayback::mix() (on the Godot side) calls into the GDExtension to run AudioStreamPlaybackMyTone::_mix().

This might not mean anything, but I find it interesting that the error is null function or function signature mismatch and it shows AudioStreamPlayback::mix(AudioFrame*, float, int) in the backtrace, however, the 2nd argument of that function is actually a double not a float (on the godot-cpp side). That sounds like a "function signature mismatch"?

In any case, because the word "function" is in the error, it certainly sounds like it's from the act of trying to call the function pointer?

And we know the function pointer isn't null, because it's using the GDVIRTUAL_REQUIRED_CALL() macro, which would have given us a different error if it was null.

@dsnopek
Copy link
Contributor

dsnopek commented Apr 9, 2024

Hm. So, AudioStreamPlayback::_mix() in Godot is actually declared as taking a float for the 2nd argument, and that's what's in the extension_api.json.

But for some reason, in binding_generator.py the correct_type() function changes float into double. This seems suspicious. While we do encode all types as 64-bit when making the ptrcall into GDExtension, we should be casting it into the type declared on the Godot side before actually calling the function. Switching float for double also makes the API different for GDExtension than in Godot, which goes contrary to our usual goal...

I'm still not sure this is the source of the problem, but it certainly seems suspicious.

@dsnopek
Copy link
Contributor

dsnopek commented Apr 9, 2024

I think the next steps here are probably to narrow down if some part of the function signature is causing the issue here. I think I'll try declaring a virtual method on the Godot side that takes only a float, implement it on the GDExtension side and call that, to see if it's the float. It could certainly also be the AudioFrame *, since I'm not sure how much we've tested passing native structs into GDExtensions when building for the web.

However, I think I need to put this down for now :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This has been identified as a bug confirmed platform:web
Projects
None yet
Development

No branches or pull requests

3 participants