Skip to content

Commit f5fd45b

Browse files
committed
Remove Asyncify dependency
1 parent bfc816c commit f5fd45b

File tree

7 files changed

+136
-157
lines changed

7 files changed

+136
-157
lines changed

modules/camera/camera_web.cpp

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
#include "core/io/json.h"
3434

35+
#include <functional>
36+
3537
void CameraFeedWeb::_on_get_pixeldata(void *context, const uint8_t *rawdata, const int length, const int p_width, const int p_height, const char *error) {
3638
CameraFeedWeb *feed = reinterpret_cast<CameraFeedWeb *>(context);
3739
if (error) {
@@ -73,11 +75,14 @@ void CameraFeedWeb::_on_denied_callback(void *context) {
7375
bool CameraFeedWeb::activate_feed() {
7476
ERR_FAIL_COND_V_MSG(selected_format == -1, false, "CameraFeed format needs to be set before activating.");
7577

76-
CameraFeed::FeedFormat f = formats[selected_format];
7778
int width = parameters.get(KEY_WIDTH, 0);
7879
int height = parameters.get(KEY_HEIGHT, 0);
79-
width = width > 0 ? width : f.width;
80-
height = height > 0 ? height : f.height;
80+
// Firefox ESR (128.11.0esr) does not implement MediaStreamTrack.getCapabilities(), so 'formats' will be empty.
81+
if (formats.size() > selected_format) {
82+
CameraFeed::FeedFormat f = formats[selected_format];
83+
width = width > 0 ? width : f.width;
84+
height = height > 0 ? height : f.height;
85+
}
8186
CameraDriverWeb::get_singleton()->get_pixel_data(this, device_id, width, height, &_on_get_pixeldata, &_on_denied_callback);
8287
return true;
8388
}
@@ -116,16 +121,11 @@ CameraFeedWeb::CameraFeedWeb(const CameraInfo &info) {
116121
name = info.label;
117122
device_id = info.device_id;
118123

119-
Vector<CapabilityInfo> capabilities;
120-
CameraDriverWeb::get_singleton()->get_capabilities(&capabilities, device_id);
121-
for (int i = 0; i < capabilities.size(); i++) {
122-
CapabilityInfo capability = capabilities[i];
123-
FeedFormat feed_format;
124-
feed_format.width = capability.width;
125-
feed_format.height = capability.height;
126-
feed_format.format = String("RGBA");
127-
formats.append(feed_format);
128-
}
124+
FeedFormat feed_format;
125+
feed_format.width = info.capability.width;
126+
feed_format.height = info.capability.height;
127+
feed_format.format = String("RGBA");
128+
formats.append(feed_format);
129129

130130
image.instantiate();
131131
}
@@ -136,18 +136,23 @@ CameraFeedWeb::~CameraFeedWeb() {
136136
}
137137
}
138138

139-
void CameraWeb::_update_feeds() {
140-
for (int i = feeds.size() - 1; i >= 0; i--) {
141-
remove_feed(feeds[i]);
139+
void CameraWeb::_on_get_cameras_callback(void *context, const Vector<CameraInfo> &camera_info) {
140+
CameraWeb *server = static_cast<CameraWeb *>(context);
141+
for (int i = server->feeds.size() - 1; i >= 0; i--) {
142+
server->remove_feed(server->feeds[i]);
142143
}
143-
144-
Vector<CameraInfo> camera_info;
145-
camera_driver_web->get_cameras(&camera_info);
146144
for (int i = 0; i < camera_info.size(); i++) {
147145
CameraInfo info = camera_info[i];
148146
Ref<CameraFeedWeb> feed = memnew(CameraFeedWeb(info));
149-
add_feed(feed);
147+
server->add_feed(feed);
150148
}
149+
server->CameraServer::set_monitoring_feeds(true);
150+
server->activating = false;
151+
}
152+
153+
void CameraWeb::_update_feeds() {
154+
activating = true;
155+
camera_driver_web->get_cameras((void *)this, &_on_get_cameras_callback);
151156
}
152157

153158
void CameraWeb::_cleanup() {
@@ -159,17 +164,17 @@ void CameraWeb::_cleanup() {
159164
}
160165

161166
void CameraWeb::set_monitoring_feeds(bool p_monitoring_feeds) {
162-
if (p_monitoring_feeds == monitoring_feeds) {
167+
if (p_monitoring_feeds == monitoring_feeds || activating) {
163168
return;
164169
}
165170

166-
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
167171
if (p_monitoring_feeds) {
168172
if (camera_driver_web == nullptr) {
169173
camera_driver_web = new CameraDriverWeb();
170174
}
171175
_update_feeds();
172176
} else {
177+
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
173178
_cleanup();
174179
}
175180
}

modules/camera/camera_web.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include "servers/camera/camera_feed.h"
3535
#include "servers/camera_server.h"
3636

37+
#include <atomic>
38+
3739
class CameraFeedWeb : public CameraFeed {
3840
GDCLASS(CameraFeedWeb, CameraFeed);
3941

@@ -61,8 +63,10 @@ class CameraWeb : public CameraServer {
6163

6264
private:
6365
CameraDriverWeb *camera_driver_web = nullptr;
66+
std::atomic<bool> activating;
6467
void _cleanup();
6568
void _update_feeds();
69+
static void _on_get_cameras_callback(void *context, const Vector<CameraInfo> &camera_info);
6670

6771
protected:
6872
public:

platform/web/SCsub

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,6 @@ else:
111111
sys_env.Append(LIBS=["idbfs.js"])
112112
build = sys_env.add_program(build_targets, web_files + ["web_runtime.cpp"])
113113

114-
sys_env.Append(LINKFLAGS=["-s", "ASYNCIFY=2"])
115-
sys_env.Append(LINKFLAGS=["-s", "ASYNCIFY_IMPORTS=['godot_js_camera_get_cameras', 'godot_js_camera_get_capabilities']"])
116-
117114
sys_env.Depends(build[0], sys_env["JS_LIBS"])
118115
sys_env.Depends(build[0], sys_env["JS_PRE"])
119116
sys_env.Depends(build[0], sys_env["JS_POST"])

platform/web/camera_driver_web.cpp

Lines changed: 48 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,6 @@
3434

3535
#include <cstdlib>
3636

37-
EM_ASYNC_JS(void, godot_js_camera_get_cameras, (void *context, CameraLibrary_OnGetCamerasCallback p_callback_ptr), {
38-
await GodotCamera.api.getCameras(context, p_callback_ptr);
39-
});
40-
41-
EM_ASYNC_JS(void, godot_js_camera_get_capabilities, (void *context, const char *p_device_id_ptr, CameraLibrary_OnGetCapabilitiesCallback p_callback_ptr), {
42-
await GodotCamera.api.getCameraCapabilities(p_device_id_ptr, context, p_callback_ptr);
43-
});
44-
4537
CameraDriverWeb *CameraDriverWeb::singleton = nullptr;
4638
Array CameraDriverWeb::_camera_info_key;
4739

@@ -53,7 +45,7 @@ CameraDriverWeb *CameraDriverWeb::get_singleton() {
5345
return singleton;
5446
}
5547

56-
void CameraDriverWeb::_on_get_cameras_callback(void *context, const char *json_ptr) {
48+
void CameraDriverWeb::_on_get_cameras_callback(void *context, void *callback, const char *json_ptr) {
5749
if (!json_ptr) {
5850
print_error("CameraDriverWeb::_on_get_cameras_callback: json_ptr is null");
5951
return;
@@ -75,8 +67,7 @@ void CameraDriverWeb::_on_get_cameras_callback(void *context, const char *json_p
7567
return;
7668
}
7769
Array devices_array = v_devices;
78-
Vector<CameraInfo> *camera_info = reinterpret_cast<Vector<CameraInfo> *>(context);
79-
camera_info->clear();
70+
Vector<CameraInfo> camera_info;
8071
for (int i = 0; i < devices_array.size(); i++) {
8172
Variant device_variant = devices_array.get(i);
8273
if (device_variant.get_type() == Variant::DICTIONARY) {
@@ -86,88 +77,62 @@ void CameraDriverWeb::_on_get_cameras_callback(void *context, const char *json_p
8677
info.index = device_dict[KEY_INDEX];
8778
info.device_id = device_dict[KEY_ID];
8879
info.label = device_dict[KEY_LABEL];
89-
camera_info->push_back(info);
80+
Variant v_caps_data = device_dict.get(KEY_CAPABILITIES, Variant());
81+
if (v_caps_data.get_type() == Variant::DICTIONARY) {
82+
Dictionary caps_dict = v_caps_data;
83+
if (caps_dict.has(KEY_WIDTH) && caps_dict.has(KEY_HEIGHT)) {
84+
Variant v_width_val = caps_dict.get(KEY_WIDTH, Variant());
85+
Variant v_height_val = caps_dict.get(KEY_HEIGHT, Variant());
86+
int width = 0;
87+
int height = 0;
88+
89+
// Helper to extract 'max' from a capability dictionary or use direct value
90+
auto get_max_or_direct = [](const Variant &p_val) -> int {
91+
if (p_val.get_type() == Variant::DICTIONARY) {
92+
Dictionary d = p_val;
93+
if (d.has(KEY_MAX)) {
94+
return d[KEY_MAX];
95+
}
96+
} else if (p_val.get_type() == Variant::INT) {
97+
return p_val;
98+
} else if (p_val.get_type() == Variant::FLOAT) {
99+
return static_cast<int>(p_val.operator float());
100+
}
101+
return 0;
102+
};
103+
104+
width = get_max_or_direct(v_width_val);
105+
height = get_max_or_direct(v_height_val);
106+
107+
if (width > 0 && height > 0) {
108+
CapabilityInfo capability;
109+
capability.width = width;
110+
capability.height = height;
111+
info.capability = capability;
112+
} else {
113+
WARN_PRINT("Could not extract valid width/height from capabilities structure.");
114+
}
115+
} else {
116+
WARN_PRINT("Capabilities object does not directly contain top-level width/height keys.");
117+
}
118+
} else {
119+
WARN_PRINT("Camera info entry has no capabilities or capabilities are not a dictionary.");
120+
}
121+
camera_info.push_back(info);
90122
} else {
91123
WARN_PRINT("Camera info entry missing required keys (index, id, label).");
92124
}
93125
}
94126
}
127+
CameraDriverWeb_OnGetCamerasCallback on_get_cameras_callback = reinterpret_cast<CameraDriverWeb_OnGetCamerasCallback>(callback);
128+
on_get_cameras_callback(context, const_cast<Vector<CameraInfo> &>(camera_info));
95129
} else {
96130
ERR_PRINT("CameraDriverWeb::_on_get_cameras_callback: Failed to parse JSON response or response is not a Dictionary.");
97131
}
98132
}
99133

100-
void CameraDriverWeb::_on_get_capabilities_callback(void *context, const char *json_ptr) {
101-
if (!json_ptr) {
102-
ERR_PRINT("CameraDriverWeb::_on_get_capabilities_callback: json_ptr is null");
103-
return;
104-
}
105-
String json_string = String::utf8(json_ptr);
106-
Variant json_variant = JSON::parse_string(json_string);
107-
108-
if (json_variant.get_type() == Variant::DICTIONARY) {
109-
Dictionary json_dict = json_variant;
110-
Variant v_error = json_dict[KEY_ERROR];
111-
if (v_error.get_type() == Variant::STRING) {
112-
String error_str = v_error;
113-
ERR_PRINT(vformat("Camera capabilities error from JS: %s", error_str));
114-
return;
115-
}
116-
Variant v_caps_data = json_dict.get(KEY_CAPABILITIES, Variant());
117-
if (v_caps_data.get_type() != Variant::DICTIONARY) {
118-
ERR_PRINT("Camera capabilities error: 'capabilities' data is not a dictionary or missing.");
119-
return;
120-
}
121-
Dictionary caps_dict = v_caps_data;
122-
Vector<CapabilityInfo> *capabilities = reinterpret_cast<Vector<CapabilityInfo> *>(context);
123-
capabilities->clear();
124-
125-
if (caps_dict.has(KEY_WIDTH) && caps_dict.has(KEY_HEIGHT)) {
126-
Variant v_width_val = caps_dict.get(KEY_WIDTH, Variant());
127-
Variant v_height_val = caps_dict.get(KEY_HEIGHT, Variant());
128-
int width = 0;
129-
int height = 0;
130-
131-
// Helper to extract 'max' from a capability dictionary or use direct value
132-
auto get_max_or_direct = [](const Variant &p_val) -> int {
133-
if (p_val.get_type() == Variant::DICTIONARY) {
134-
Dictionary d = p_val;
135-
if (d.has(KEY_MAX)) {
136-
return d[KEY_MAX];
137-
}
138-
} else if (p_val.get_type() == Variant::INT) {
139-
return p_val;
140-
} else if (p_val.get_type() == Variant::FLOAT) {
141-
return static_cast<int>(p_val.operator float());
142-
}
143-
return 0;
144-
};
145-
146-
width = get_max_or_direct(v_width_val);
147-
height = get_max_or_direct(v_height_val);
148-
149-
if (width > 0 && height > 0) {
150-
CapabilityInfo info;
151-
info.width = width;
152-
info.height = height;
153-
capabilities->push_back(info);
154-
} else {
155-
WARN_PRINT("Could not extract valid width/height from capabilities structure.");
156-
}
157-
} else {
158-
WARN_PRINT("Capabilities object does not directly contain top-level width/height keys.");
159-
}
160-
} else {
161-
ERR_PRINT("CameraDriverWeb::_on_get_capabilities_callback: Failed to parse JSON response or response is not a Dictionary.");
162-
}
163-
}
164-
165-
void CameraDriverWeb::get_cameras(Vector<CameraInfo> *r_camera_info) {
166-
godot_js_camera_get_cameras((void *)r_camera_info, &_on_get_cameras_callback);
167-
}
168-
169-
void CameraDriverWeb::get_capabilities(Vector<CapabilityInfo> *r_capabilities, const String &p_device_id) {
170-
godot_js_camera_get_capabilities((void *)r_capabilities, p_device_id.utf8().get_data(), &_on_get_capabilities_callback);
134+
void CameraDriverWeb::get_cameras(void *context, CameraDriverWeb_OnGetCamerasCallback callback) {
135+
godot_js_camera_get_cameras(context, (void *)callback, &_on_get_cameras_callback);
171136
}
172137

173138
void CameraDriverWeb::get_pixel_data(void *context, const String &p_device_id, const int width, const int height, CameraLibrary_OnGetPixelDataCallback p_callback, CameraLibrary_OnDeniedCallback p_denied_callback) {

platform/web/camera_driver_web.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,29 @@
4646
#define KEY_MAX String("max")
4747
#define KEY_WIDTH String("width")
4848

49+
struct CapabilityInfo {
50+
int width;
51+
int height;
52+
};
53+
4954
struct CameraInfo {
5055
int index;
5156
String device_id;
5257
String label;
58+
CapabilityInfo capability;
5359
};
5460

55-
struct CapabilityInfo {
56-
int width;
57-
int height;
58-
};
61+
using CameraDriverWeb_OnGetCamerasCallback = void (*)(void *context, const Vector<CameraInfo> &caremra_info);
5962

6063
class CameraDriverWeb {
6164
private:
6265
static CameraDriverWeb *singleton;
6366
static Array _camera_info_key;
64-
WASM_EXPORT static void _on_get_cameras_callback(void *context, const char *json_ptr);
65-
WASM_EXPORT static void _on_get_capabilities_callback(void *context, const char *json_ptr);
67+
WASM_EXPORT static void _on_get_cameras_callback(void *context, void *callback, const char *json_ptr);
6668

6769
public:
6870
static CameraDriverWeb *get_singleton();
69-
void get_cameras(Vector<CameraInfo> *camera_info);
70-
void get_capabilities(Vector<CapabilityInfo> *capabilities, const String &p_device_id);
71+
void get_cameras(void *context, CameraDriverWeb_OnGetCamerasCallback callback);
7172
void get_pixel_data(void *context, const String &p_device_id, const int width, const int height, CameraLibrary_OnGetPixelDataCallback p_callback, CameraLibrary_OnDeniedCallback p_denied_callback);
7273
void stop_stream(const String &device_id = String());
7374

platform/web/godot_camera.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@
3737
extern "C" {
3838
#endif
3939

40-
using CameraLibrary_OnGetCamerasCallback = void (*)(void *, const char *);
40+
using CameraLibrary_OnGetCamerasCallback = void (*)(void *context, void *callback, const char *result);
4141

42-
using CameraLibrary_OnGetCapabilitiesCallback = void (*)(void *, const char *);
42+
using CameraLibrary_OnGetPixelDataCallback = void (*)(void *context, const uint8_t *, const int size, const int width, const int height, const char *error);
4343

44-
using CameraLibrary_OnGetPixelDataCallback = void (*)(void *, const uint8_t *, const int, const int, const int, const char *);
44+
using CameraLibrary_OnDeniedCallback = void (*)(void *context);
4545

46-
using CameraLibrary_OnDeniedCallback = void (*)(void *);
46+
extern void godot_js_camera_get_cameras(
47+
void *context,
48+
void *callback,
49+
CameraLibrary_OnGetCamerasCallback p_callback_ptr);
4750

4851
extern void godot_js_camera_get_pixel_data(
4952
void *context,

0 commit comments

Comments
 (0)