Skip to content

Commit 1c33134

Browse files
committed
Remove Asyncify dependency
1 parent 41c06aa commit 1c33134

File tree

7 files changed

+200
-216
lines changed

7 files changed

+200
-216
lines changed

modules/camera/camera_web.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,14 @@ void CameraFeedWeb::_on_denied_callback(void *context) {
7373
bool CameraFeedWeb::activate_feed() {
7474
ERR_FAIL_COND_V_MSG(selected_format == -1, false, "CameraFeed format needs to be set before activating.");
7575

76-
CameraFeed::FeedFormat f = formats[selected_format];
7776
int width = parameters.get(KEY_WIDTH, 0);
7877
int height = parameters.get(KEY_HEIGHT, 0);
79-
width = width > 0 ? width : f.width;
80-
height = height > 0 ? height : f.height;
78+
// Firefox ESR (128.11.0esr) does not implement MediaStreamTrack.getCapabilities(), so 'formats' will be empty.
79+
if (formats.size() > selected_format) {
80+
CameraFeed::FeedFormat f = formats[selected_format];
81+
width = width > 0 ? width : f.width;
82+
height = height > 0 ? height : f.height;
83+
}
8184
CameraDriverWeb::get_singleton()->get_pixel_data(this, device_id, width, height, &_on_get_pixeldata, &_on_denied_callback);
8285
return true;
8386
}
@@ -116,16 +119,11 @@ CameraFeedWeb::CameraFeedWeb(const CameraInfo &info) {
116119
name = info.label;
117120
device_id = info.device_id;
118121

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-
}
122+
FeedFormat feed_format;
123+
feed_format.width = info.capability.width;
124+
feed_format.height = info.capability.height;
125+
feed_format.format = String("RGBA");
126+
formats.append(feed_format);
129127

130128
image.instantiate();
131129
}
@@ -136,18 +134,23 @@ CameraFeedWeb::~CameraFeedWeb() {
136134
}
137135
}
138136

139-
void CameraWeb::_update_feeds() {
140-
for (int i = feeds.size() - 1; i >= 0; i--) {
141-
remove_feed(feeds[i]);
137+
void CameraWeb::_on_get_cameras_callback(void *context, const Vector<CameraInfo> &camera_info) {
138+
CameraWeb *server = static_cast<CameraWeb *>(context);
139+
for (int i = server->feeds.size() - 1; i >= 0; i--) {
140+
server->remove_feed(server->feeds[i]);
142141
}
143-
144-
Vector<CameraInfo> camera_info;
145-
camera_driver_web->get_cameras(&camera_info);
146142
for (int i = 0; i < camera_info.size(); i++) {
147143
CameraInfo info = camera_info[i];
148144
Ref<CameraFeedWeb> feed = memnew(CameraFeedWeb(info));
149-
add_feed(feed);
145+
server->add_feed(feed);
150146
}
147+
server->CameraServer::set_monitoring_feeds(true);
148+
server->activating = false;
149+
}
150+
151+
void CameraWeb::_update_feeds() {
152+
activating = true;
153+
camera_driver_web->get_cameras((void *)this, &_on_get_cameras_callback);
151154
}
152155

153156
void CameraWeb::_cleanup() {
@@ -159,17 +162,17 @@ void CameraWeb::_cleanup() {
159162
}
160163

161164
void CameraWeb::set_monitoring_feeds(bool p_monitoring_feeds) {
162-
if (p_monitoring_feeds == monitoring_feeds) {
165+
if (p_monitoring_feeds == monitoring_feeds || activating) {
163166
return;
164167
}
165168

166-
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
167169
if (p_monitoring_feeds) {
168170
if (camera_driver_web == nullptr) {
169171
camera_driver_web = new CameraDriverWeb();
170172
}
171173
_update_feeds();
172174
} else {
175+
CameraServer::set_monitoring_feeds(p_monitoring_feeds);
173176
_cleanup();
174177
}
175178
}

modules/camera/camera_web.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,16 @@
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

4042
private:
4143
String device_id;
4244
Ref<Image> image;
4345
Vector<uint8_t> data;
44-
static void _on_get_pixeldata(void *, const uint8_t *, const int, const int, const int, const char *error);
46+
static void _on_get_pixeldata(void *context, const uint8_t *rawdata, const int length, const int p_width, const int p_height, const char *error);
4547
static void _on_denied_callback(void *context);
4648

4749
protected:
@@ -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: 76 additions & 100 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,121 +45,105 @@ CameraDriverWeb *CameraDriverWeb::get_singleton() {
5345
return singleton;
5446
}
5547

56-
void CameraDriverWeb::_on_get_cameras_callback(void *context, const char *json_ptr) {
48+
// Helper to extract 'max' from a capability dictionary or use direct value
49+
int CameraDriverWeb::_get_max_or_direct(const Variant &p_val) {
50+
if (p_val.get_type() == Variant::DICTIONARY) {
51+
Dictionary d = p_val;
52+
if (d.has(KEY_MAX)) {
53+
return d[KEY_MAX];
54+
}
55+
} else if (p_val.get_type() == Variant::INT) {
56+
return p_val;
57+
} else if (p_val.get_type() == Variant::FLOAT) {
58+
return static_cast<int>(p_val.operator float());
59+
}
60+
return 0;
61+
}
62+
63+
void CameraDriverWeb::_on_get_cameras_callback(void *context, void *callback, const char *json_ptr) {
5764
if (!json_ptr) {
5865
print_error("CameraDriverWeb::_on_get_cameras_callback: json_ptr is null");
5966
return;
6067
}
6168
String json_string = String::utf8(json_ptr);
6269
Variant json_variant = JSON::parse_string(json_string);
6370

64-
if (json_variant.get_type() == Variant::DICTIONARY) {
65-
Dictionary json_dict = json_variant;
66-
Variant v_error = json_dict[KEY_ERROR];
67-
if (v_error.get_type() == Variant::STRING) {
68-
String error_str = v_error;
69-
ERR_PRINT(vformat("Camera error from JS: %s", error_str));
70-
return;
71-
}
72-
Variant v_devices = json_dict.get(KEY_CAMERAS, Variant());
73-
if (v_devices.get_type() != Variant::ARRAY) {
74-
ERR_PRINT("Camera error: 'cameras' is not an array or missing.");
75-
return;
76-
}
77-
Array devices_array = v_devices;
78-
Vector<CameraInfo> *camera_info = reinterpret_cast<Vector<CameraInfo> *>(context);
79-
camera_info->clear();
80-
for (int i = 0; i < devices_array.size(); i++) {
81-
Variant device_variant = devices_array.get(i);
82-
if (device_variant.get_type() == Variant::DICTIONARY) {
83-
Dictionary device_dict = device_variant;
84-
if (device_dict.has_all(_camera_info_key)) {
85-
CameraInfo info;
86-
info.index = device_dict[KEY_INDEX];
87-
info.device_id = device_dict[KEY_ID];
88-
info.label = device_dict[KEY_LABEL];
89-
camera_info->push_back(info);
90-
} else {
91-
WARN_PRINT("Camera info entry missing required keys (index, id, label).");
92-
}
93-
}
94-
}
95-
} else {
71+
if (json_variant.get_type() != Variant::DICTIONARY) {
9672
ERR_PRINT("CameraDriverWeb::_on_get_cameras_callback: Failed to parse JSON response or response is not a Dictionary.");
73+
return;
9774
}
98-
}
9975

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");
76+
Dictionary json_dict = json_variant;
77+
Variant v_error = json_dict[KEY_ERROR];
78+
if (v_error.get_type() == Variant::STRING) {
79+
String error_str = v_error;
80+
ERR_PRINT(vformat("Camera error from JS: %s", error_str));
10381
return;
10482
}
105-
String json_string = String::utf8(json_ptr);
106-
Variant json_variant = JSON::parse_string(json_string);
10783

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;
84+
Variant v_devices = json_dict.get(KEY_CAMERAS, Variant());
85+
if (v_devices.get_type() != Variant::ARRAY) {
86+
ERR_PRINT("Camera error: 'cameras' is not an array or missing.");
87+
return;
88+
}
89+
90+
Array devices_array = v_devices;
91+
Vector<CameraInfo> camera_info;
92+
for (int i = 0; i < devices_array.size(); i++) {
93+
Variant device_variant = devices_array.get(i);
94+
if (device_variant.get_type() != Variant::DICTIONARY) {
95+
continue;
11596
}
116-
Variant v_caps_data = json_dict.get(KEY_CAPABILITIES, Variant());
97+
98+
Dictionary device_dict = device_variant;
99+
if (!device_dict.has_all(_camera_info_key)) {
100+
WARN_PRINT("Camera info entry missing required keys (index, id, label).");
101+
continue;
102+
}
103+
104+
CameraInfo info;
105+
info.index = device_dict[KEY_INDEX];
106+
info.device_id = device_dict[KEY_ID];
107+
info.label = device_dict[KEY_LABEL];
108+
109+
Variant v_caps_data = device_dict.get(KEY_CAPABILITIES, Variant());
117110
if (v_caps_data.get_type() != Variant::DICTIONARY) {
118-
ERR_PRINT("Camera capabilities error: 'capabilities' data is not a dictionary or missing.");
119-
return;
111+
WARN_PRINT("Camera info entry has no capabilities or capabilities are not a dictionary.");
112+
camera_info.push_back(info);
113+
continue;
120114
}
115+
121116
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 {
117+
if (!caps_dict.has(KEY_WIDTH) || !caps_dict.has(KEY_HEIGHT)) {
158118
WARN_PRINT("Capabilities object does not directly contain top-level width/height keys.");
119+
camera_info.push_back(info);
120+
continue;
159121
}
160-
} else {
161-
ERR_PRINT("CameraDriverWeb::_on_get_capabilities_callback: Failed to parse JSON response or response is not a Dictionary.");
122+
123+
Variant v_width_val = caps_dict.get(KEY_WIDTH, Variant());
124+
Variant v_height_val = caps_dict.get(KEY_HEIGHT, Variant());
125+
126+
int width = _get_max_or_direct(v_width_val);
127+
int height = _get_max_or_direct(v_height_val);
128+
129+
if (width <= 0 || height <= 0) {
130+
WARN_PRINT("Could not extract valid width/height from capabilities structure.");
131+
continue;
132+
}
133+
134+
CapabilityInfo capability;
135+
capability.width = width;
136+
capability.height = height;
137+
info.capability = capability;
138+
camera_info.push_back(info);
162139
}
163-
}
164140

165-
void CameraDriverWeb::get_cameras(Vector<CameraInfo> *r_camera_info) {
166-
godot_js_camera_get_cameras((void *)r_camera_info, &_on_get_cameras_callback);
141+
CameraDriverWeb_OnGetCamerasCallback on_get_cameras_callback = reinterpret_cast<CameraDriverWeb_OnGetCamerasCallback>(callback);
142+
on_get_cameras_callback(context, const_cast<Vector<CameraInfo> &>(camera_info));
167143
}
168144

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);
145+
void CameraDriverWeb::get_cameras(void *context, CameraDriverWeb_OnGetCamerasCallback callback) {
146+
godot_js_camera_get_cameras(context, (void *)callback, &_on_get_cameras_callback);
171147
}
172148

173149
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: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,30 @@
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+
static int _get_max_or_direct(const Variant &p_val);
68+
WASM_EXPORT static void _on_get_cameras_callback(void *context, void *callback, const char *json_ptr);
6669

6770
public:
6871
static CameraDriverWeb *get_singleton();
69-
void get_cameras(Vector<CameraInfo> *camera_info);
70-
void get_capabilities(Vector<CapabilityInfo> *capabilities, const String &p_device_id);
72+
void get_cameras(void *context, CameraDriverWeb_OnGetCamerasCallback callback);
7173
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);
7274
void stop_stream(const String &device_id = String());
7375

0 commit comments

Comments
 (0)