• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TEN-framework / ten-framework / 20358357829

19 Dec 2025 03:00AM UTC coverage: 57.587% (+0.2%) from 57.34%
20358357829

push

github

web-flow
fix: coveralls remove container for all test jobs (#1878)

* chore: calculate coverage in debug mode

* Revert "chore: calculate coverage in debug mode"

This reverts commit f68a031af.

* Reapply "chore: calculate coverage in debug mode"

This reverts commit bc27f2c1c.

* fix: remove container for test jobs

* fix: add C++ toolchain, go builder, sanitizer support, nodejs env

* fix: compiler version incompatible

* Revert "fix: compiler version incompatible"

This reverts commit 23f5c3f7d.

* fix: set PATH so that clang-21 is find earlier than older versions

* fix: uninstall older versions of clang

* Revert "fix: set PATH so that clang-21 is find earlier than older versions"

This reverts commit b66e56c08.

* fix: uninstall old clang first then install clang21

* fix: supplement test jobs deps according to tools Dockerfile

* fix: install libasan5 for all jobs and remove unecessary deps

* chore: refine codes and output clang version before every test

* fix: go back to clang 18 to detect __lsan_do_leak_check

* Revert "fix: go back to clang 18 to detect __lsan_do_leak_check"

This reverts commit d247818a8.

* fix: upgrade libasan5 to libasan8 to match clang 21

* fix: install libclang-rt-21-dev

* Revert "fix: install libclang-rt-21-dev"

This reverts commit 39b96e030.

* fix: ten_enable_go_app_leak_check

* chore: uninstall useless dep libasan8

* chore: refine codes and uninstall unecessary dep clang-tool-21

54480 of 94605 relevant lines covered (57.59%)

682622.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.01
/core/src/ten_runtime/binding/nodejs/native/extension/extension.c
1
//
2
// Copyright © 2025 Agora
3
// This file is part of TEN Framework, an open source project.
4
// Licensed under the Apache License, Version 2.0, with certain conditions.
5
// Refer to the "LICENSE" file in the root directory for more information.
6
//
7
#include "include_internal/ten_runtime/binding/nodejs/extension/extension.h"
8

9
#include "include_internal/ten_runtime/binding/nodejs/common/common.h"
10
#include "include_internal/ten_runtime/binding/nodejs/msg/audio_frame.h"
11
#include "include_internal/ten_runtime/binding/nodejs/msg/cmd/cmd.h"
12
#include "include_internal/ten_runtime/binding/nodejs/msg/data.h"
13
#include "include_internal/ten_runtime/binding/nodejs/msg/video_frame.h"
14
#include "include_internal/ten_runtime/binding/nodejs/ten_env/ten_env.h"
15
#include "js_native_api.h"
16
#include "js_native_api_types.h"
17
#include "ten_runtime/extension/extension.h"
18
#include "ten_runtime/ten_env/ten_env.h"
19
#include "ten_utils/lib/signature.h"
20
#include "ten_utils/lib/smart_ptr.h"
21
#include "ten_utils/lib/string.h"
22
#include "ten_utils/log/log.h"
23
#include "ten_utils/macro/check.h"
24
#include "ten_utils/macro/mark.h"
25
#include "ten_utils/macro/memory.h"
26

27
typedef struct extension_on_xxx_call_info_t {
28
  ten_nodejs_extension_t *extension_bridge;
29
  ten_nodejs_ten_env_t *ten_env_bridge;
30
  ten_env_t *ten_env;
31
  ten_env_proxy_t *ten_env_proxy;
32
} extension_on_xxx_call_info_t;
33

34
typedef struct extension_on_msg_call_info_t {
35
  ten_nodejs_extension_t *extension_bridge;
36
  ten_nodejs_ten_env_t *ten_env_bridge;
37
  ten_shared_ptr_t *msg;
38
} extension_on_msg_call_info_t;
39

40
bool ten_nodejs_extension_check_integrity(ten_nodejs_extension_t *self,
41
                                          bool check_thread) {
264✔
42
  TEN_ASSERT(self, "Should not happen.");
264✔
43

44
  if (ten_signature_get(&self->signature) != TEN_NODEJS_EXTENSION_SIGNATURE) {
264✔
45
    return false;
×
46
  }
×
47

48
  if (check_thread &&
264✔
49
      !ten_sanitizer_thread_check_do_check(&self->thread_check)) {
264✔
50
    return false;
×
51
  }
×
52

53
  return true;
264✔
54
}
264✔
55

56
static void ten_nodejs_extension_detach_callbacks(
57
    ten_nodejs_extension_t *self) {
16✔
58
  TEN_ASSERT(self && ten_nodejs_extension_check_integrity(self, true),
16✔
59
             "Should not happen.");
16✔
60

61
  ten_nodejs_tsfn_dec_rc(self->js_on_configure);
16✔
62
  ten_nodejs_tsfn_dec_rc(self->js_on_init);
16✔
63
  ten_nodejs_tsfn_dec_rc(self->js_on_start);
16✔
64
  ten_nodejs_tsfn_dec_rc(self->js_on_stop);
16✔
65
  ten_nodejs_tsfn_dec_rc(self->js_on_deinit);
16✔
66
  ten_nodejs_tsfn_dec_rc(self->js_on_cmd);
16✔
67
  ten_nodejs_tsfn_dec_rc(self->js_on_data);
16✔
68
  ten_nodejs_tsfn_dec_rc(self->js_on_audio_frame);
16✔
69
  ten_nodejs_tsfn_dec_rc(self->js_on_video_frame);
16✔
70
}
16✔
71

72
static void ten_nodejs_extension_finalize(napi_env env, void *data,
73
                                          TEN_UNUSED void *hint) {
16✔
74
  TEN_LOGI("TEN JS extension is finalized");
16✔
75

76
  ten_nodejs_extension_t *extension_bridge = data;
16✔
77
  TEN_ASSERT(extension_bridge, "Should not happen.");
16✔
78

79
  napi_status status = napi_ok;
16✔
80
  status = napi_delete_reference(env, extension_bridge->bridge.js_instance_ref);
16✔
81
  TEN_ASSERT(status == napi_ok, "Failed to delete JS extension reference.");
16✔
82

83
  ten_nodejs_extension_detach_callbacks(extension_bridge);
16✔
84

85
  // Unreference the JS extension instance to allow it to be garbage collected.
86

87
  ten_extension_destroy(extension_bridge->c_extension);
16✔
88

89
  ten_sanitizer_thread_check_deinit(&extension_bridge->thread_check);
16✔
90

91
  TEN_FREE(extension_bridge);
16✔
92
}
16✔
93

94
static void ten_nodejs_invoke_extension_js_on_configure(
95
    napi_env env, napi_value fn, TEN_UNUSED void *context, void *data) {
16✔
96
  extension_on_xxx_call_info_t *call_info = data;
16✔
97
  TEN_ASSERT(call_info, "Should not happen.");
16✔
98

99
  TEN_ASSERT(
16✔
100
      call_info->extension_bridge && ten_nodejs_extension_check_integrity(
16✔
101
                                         call_info->extension_bridge, true),
16✔
102
      "Should not happen.");
16✔
103

104
  // Export the C ten_env object to the JS world.
105
  ten_nodejs_ten_env_t *ten_env_bridge = NULL;
16✔
106
  napi_value js_ten_env = ten_nodejs_ten_env_create_new_js_object_and_wrap(
16✔
107
      env, call_info->ten_env, &ten_env_bridge);
16✔
108
  TEN_ASSERT(js_ten_env, "Should not happen.");
16✔
109

110
  ten_env_bridge->c_ten_env_proxy = call_info->ten_env_proxy;
16✔
111
  TEN_ASSERT(ten_env_bridge->c_ten_env_proxy, "Should not happen.");
16✔
112

113
  // Increase the reference count of the JS ten_env object to prevent it from
114
  // being garbage collected.
115
  uint32_t js_ten_env_ref_count = 0;
16✔
116
  napi_reference_ref(env, ten_env_bridge->bridge.js_instance_ref,
16✔
117
                     &js_ten_env_ref_count);
16✔
118

119
  napi_status status = napi_ok;
16✔
120

121
  {
16✔
122
    // Call on_configure() of the TEN JS extension.
123

124
    // Get the TEN JS extension.
125
    napi_value js_extension = NULL;
16✔
126
    status = napi_get_reference_value(
16✔
127
        env, call_info->extension_bridge->bridge.js_instance_ref,
16✔
128
        &js_extension);
16✔
129
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
16✔
130
                            "Failed to get JS extension: %d", status);
16✔
131

132
    napi_value result = NULL;
16✔
133
    napi_value argv[] = {js_ten_env};
16✔
134
    status = napi_call_function(env, js_extension, fn, 1, argv, &result);
16✔
135
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
136
                            "Failed to call JS extension on_configure(): %d",
16✔
137
                            status);
16✔
138
  }
16✔
139

140
  goto done;
16✔
141

142
error:
16✔
143
  TEN_LOGE("Failed to call JS extension on_configure()");
×
144

145
done:
16✔
146
  TEN_FREE(call_info);
16✔
147
}
16✔
148

149
static void ten_nodejs_invoke_extension_js_on_init(napi_env env, napi_value fn,
150
                                                   TEN_UNUSED void *context,
151
                                                   void *data) {
16✔
152
  extension_on_xxx_call_info_t *call_info = data;
16✔
153
  TEN_ASSERT(call_info, "Should not happen.");
16✔
154

155
  ten_nodejs_extension_t *extension_bridge = call_info->extension_bridge;
16✔
156
  TEN_ASSERT(extension_bridge, "Should not happen.");
16✔
157
  TEN_ASSERT(ten_nodejs_extension_check_integrity(extension_bridge, true),
16✔
158
             "Should not happen.");
16✔
159

160
  ten_nodejs_ten_env_t *ten_env_bridge = call_info->ten_env_bridge;
16✔
161
  TEN_ASSERT(ten_env_bridge, "Should not happen.");
16✔
162
  TEN_ASSERT(ten_nodejs_ten_env_check_integrity(ten_env_bridge, true),
16✔
163
             "Should not happen.");
16✔
164

165
  napi_status status = napi_ok;
16✔
166

167
  {
16✔
168
    // Call on_init() of the TEN JS extension.
169

170
    // Get the TEN JS extension.
171
    napi_value js_extension = NULL;
16✔
172
    status = napi_get_reference_value(
16✔
173
        env, extension_bridge->bridge.js_instance_ref, &js_extension);
16✔
174
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
16✔
175
                            "Failed to get JS extension: %d", status);
16✔
176

177
    napi_value js_ten_env = NULL;
16✔
178
    status = napi_get_reference_value(
16✔
179
        env, ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
16✔
180
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
16✔
181
                            "Failed to get JS ten_env: %d", status);
16✔
182

183
    // Call on_init().
184
    napi_value result = NULL;
16✔
185
    napi_value argv[] = {js_ten_env};
16✔
186
    status = napi_call_function(env, js_extension, fn, 1, argv, &result);
16✔
187
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
188
                            "Failed to call JS extension on_init(): %d",
16✔
189
                            status);
16✔
190
  }
16✔
191

192
  goto done;
16✔
193

194
error:
16✔
195
  TEN_LOGE("Failed to call JS extension on_init()");
×
196

197
done:
16✔
198
  TEN_FREE(call_info);
16✔
199
}
16✔
200

201
static void ten_nodejs_invoke_extension_js_on_start(napi_env env, napi_value fn,
202
                                                    TEN_UNUSED void *context,
203
                                                    void *data) {
16✔
204
  extension_on_xxx_call_info_t *call_info = data;
16✔
205
  TEN_ASSERT(call_info, "Should not happen.");
16✔
206

207
  TEN_ASSERT(
16✔
208
      call_info->extension_bridge && ten_nodejs_extension_check_integrity(
16✔
209
                                         call_info->extension_bridge, true),
16✔
210
      "Should not happen.");
16✔
211

212
  TEN_ASSERT(call_info->ten_env_bridge && ten_nodejs_ten_env_check_integrity(
16✔
213
                                              call_info->ten_env_bridge, true),
16✔
214
             "Should not happen.");
16✔
215

216
  napi_status status = napi_ok;
16✔
217

218
  {
16✔
219
    // Call on_start() of the TEN JS extension.
220

221
    // Get the TEN JS extension.
222
    napi_value js_extension = NULL;
16✔
223
    status = napi_get_reference_value(
16✔
224
        env, call_info->extension_bridge->bridge.js_instance_ref,
16✔
225
        &js_extension);
16✔
226
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
16✔
227
                            "Failed to get JS extension: %d", status);
16✔
228

229
    napi_value js_ten_env = NULL;
16✔
230
    status = napi_get_reference_value(
16✔
231
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
16✔
232
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
16✔
233
                            "Failed to get JS ten_env: %d", status);
16✔
234

235
    // Call on_start().
236
    napi_value result = NULL;
16✔
237
    napi_value argv[] = {js_ten_env};
16✔
238
    status = napi_call_function(env, js_extension, fn, 1, argv, &result);
16✔
239
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
240
                            "Failed to call JS extension on_start(): %d",
16✔
241
                            status);
16✔
242
  }
16✔
243

244
  goto done;
16✔
245

246
error:
16✔
247
  TEN_LOGE("Failed to call JS extension on_start()");
×
248

249
done:
16✔
250
  TEN_FREE(call_info);
16✔
251
}
16✔
252

253
static void ten_nodejs_invoke_extension_js_on_stop(napi_env env, napi_value fn,
254
                                                   TEN_UNUSED void *context,
255
                                                   void *data) {
16✔
256
  extension_on_xxx_call_info_t *call_info = data;
16✔
257
  TEN_ASSERT(call_info, "Should not happen.");
16✔
258

259
  TEN_ASSERT(
16✔
260
      call_info->extension_bridge && ten_nodejs_extension_check_integrity(
16✔
261
                                         call_info->extension_bridge, true),
16✔
262
      "Should not happen.");
16✔
263

264
  TEN_ASSERT(call_info->ten_env_bridge && ten_nodejs_ten_env_check_integrity(
16✔
265
                                              call_info->ten_env_bridge, true),
16✔
266
             "Should not happen.");
16✔
267

268
  napi_status status = napi_ok;
16✔
269

270
  {
16✔
271
    // Call on_stop() of the TEN JS extension.
272

273
    // Get the TEN JS extension.
274
    napi_value js_extension = NULL;
16✔
275
    status = napi_get_reference_value(
16✔
276
        env, call_info->extension_bridge->bridge.js_instance_ref,
16✔
277
        &js_extension);
16✔
278
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
16✔
279
                            "Failed to get JS extension: %d", status);
16✔
280

281
    napi_value js_ten_env = NULL;
16✔
282
    status = napi_get_reference_value(
16✔
283
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
16✔
284
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
16✔
285
                            "Failed to get JS ten_env: %d", status);
16✔
286

287
    // Call on_stop().
288
    napi_value result = NULL;
16✔
289
    napi_value argv[] = {js_ten_env};
16✔
290
    status = napi_call_function(env, js_extension, fn, 1, argv, &result);
16✔
291
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
292
                            "Failed to call JS extension on_stop(): %d",
16✔
293
                            status);
16✔
294
  }
16✔
295

296
  goto done;
16✔
297

298
error:
16✔
299
  TEN_LOGE("Failed to call JS extension on_stop()");
×
300

301
done:
16✔
302
  TEN_FREE(call_info);
16✔
303
}
16✔
304

305
static void ten_nodejs_invoke_extension_js_on_deinit(napi_env env,
306
                                                     napi_value fn,
307
                                                     TEN_UNUSED void *context,
308
                                                     void *data) {
16✔
309
  extension_on_xxx_call_info_t *call_info = data;
16✔
310
  TEN_ASSERT(call_info, "Should not happen.");
16✔
311

312
  TEN_ASSERT(
16✔
313
      call_info->extension_bridge && ten_nodejs_extension_check_integrity(
16✔
314
                                         call_info->extension_bridge, true),
16✔
315
      "Should not happen.");
16✔
316

317
  TEN_ASSERT(call_info->ten_env_bridge && ten_nodejs_ten_env_check_integrity(
16✔
318
                                              call_info->ten_env_bridge, true),
16✔
319
             "Should not happen.");
16✔
320

321
  napi_status status = napi_ok;
16✔
322

323
  {
16✔
324
    // Call on_deinit() of the TEN JS extension.
325

326
    // Get the TEN JS extension.
327
    napi_value js_extension = NULL;
16✔
328
    status = napi_get_reference_value(
16✔
329
        env, call_info->extension_bridge->bridge.js_instance_ref,
16✔
330
        &js_extension);
16✔
331
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
16✔
332
                            "Failed to get JS extension: %d", status);
16✔
333

334
    napi_value js_ten_env = NULL;
16✔
335
    status = napi_get_reference_value(
16✔
336
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
16✔
337
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
16✔
338
                            "Failed to get JS ten_env: %d", status);
16✔
339

340
    // Call on_deinit().
341
    napi_value result = NULL;
16✔
342
    napi_value argv[] = {js_ten_env};
16✔
343
    status = napi_call_function(env, js_extension, fn, 1, argv, &result);
16✔
344
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
345
                            "Failed to call JS extension on_deinit(): %d",
16✔
346
                            status);
16✔
347
  }
16✔
348

349
  goto done;
16✔
350

351
error:
16✔
352
  TEN_LOGE("Failed to call JS extension on_deinit()");
×
353

354
done:
16✔
355
  TEN_FREE(call_info);
16✔
356
}
16✔
357

358
static void ten_nodejs_invoke_extension_js_on_cmd(napi_env env, napi_value fn,
359
                                                  TEN_UNUSED void *context,
360
                                                  void *data) {
2✔
361
  extension_on_msg_call_info_t *call_info = data;
2✔
362
  TEN_ASSERT(call_info, "Should not happen.");
2✔
363

364
  napi_status status = napi_ok;
2✔
365

366
  {
2✔
367
    // Call on_cmd() of the TEN JS extension.
368

369
    // Get the TEN JS extension.
370
    napi_value js_extension = NULL;
2✔
371
    status = napi_get_reference_value(
2✔
372
        env, call_info->extension_bridge->bridge.js_instance_ref,
2✔
373
        &js_extension);
2✔
374
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
2✔
375
                            "Failed to get JS extension: %d", status);
2✔
376

377
    // Get the TEN JS ten_env.
378
    napi_value js_ten_env = NULL;
2✔
379
    status = napi_get_reference_value(
2✔
380
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
2✔
381
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
2✔
382
                            "Failed to get JS ten_env: %d", status);
2✔
383

384
    napi_value js_cmd = ten_nodejs_cmd_wrap(env, call_info->msg);
2✔
385
    GOTO_LABEL_IF_NAPI_FAIL(error, js_cmd != NULL, "Failed to wrap JS Cmd.");
2✔
386

387
    // Call on_cmd().
388
    napi_value result = NULL;
2✔
389
    napi_value argv[] = {js_ten_env, js_cmd};
2✔
390
    status = napi_call_function(env, js_extension, fn, 2, argv, &result);
2✔
391
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
2✔
392
                            "Failed to call JS extension on_cmd(): %d", status);
2✔
393
  }
2✔
394

395
  goto done;
2✔
396

397
error:
2✔
398
  TEN_LOGE("Failed to call JS extension on_cmd()");
×
399

400
done:
2✔
401
  ten_shared_ptr_destroy(call_info->msg);
2✔
402
  TEN_FREE(call_info);
2✔
403
}
2✔
404

405
static void ten_nodejs_invoke_extension_js_on_data(napi_env env, napi_value fn,
406
                                                   TEN_UNUSED void *context,
407
                                                   void *data) {
2✔
408
  extension_on_msg_call_info_t *call_info = data;
2✔
409
  TEN_ASSERT(call_info, "Should not happen.");
2✔
410

411
  napi_status status = napi_ok;
2✔
412

413
  {
2✔
414
    // Call on_data() of the TEN JS extension.
415

416
    // Get the TEN JS extension.
417
    napi_value js_extension = NULL;
2✔
418
    status = napi_get_reference_value(
2✔
419
        env, call_info->extension_bridge->bridge.js_instance_ref,
2✔
420
        &js_extension);
2✔
421
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
2✔
422
                            "Failed to get JS extension: %d", status);
2✔
423

424
    // Get the TEN JS ten_env.
425
    napi_value js_ten_env = NULL;
2✔
426
    status = napi_get_reference_value(
2✔
427
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
2✔
428
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
2✔
429
                            "Failed to get JS ten_env: %d", status);
2✔
430

431
    napi_value js_data = ten_nodejs_data_wrap(env, call_info->msg);
2✔
432
    GOTO_LABEL_IF_NAPI_FAIL(error, js_data != NULL, "Failed to wrap JS Data.");
2✔
433

434
    // Call on_data().
435
    napi_value result = NULL;
2✔
436
    napi_value argv[] = {js_ten_env, js_data};
2✔
437
    status = napi_call_function(env, js_extension, fn, 2, argv, &result);
2✔
438
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
2✔
439
                            "Failed to call JS extension on_data(): %d",
2✔
440
                            status);
2✔
441
  }
2✔
442

443
  goto done;
2✔
444

445
error:
2✔
446
  TEN_LOGE("Failed to call JS extension on_data()");
×
447

448
done:
2✔
449
  ten_shared_ptr_destroy(call_info->msg);
2✔
450
  TEN_FREE(call_info);
2✔
451
}
2✔
452

453
static void ten_nodejs_invoke_extension_js_on_audio_frame(
454
    napi_env env, napi_value fn, TEN_UNUSED void *context, void *data) {
2✔
455
  extension_on_msg_call_info_t *call_info = data;
2✔
456
  TEN_ASSERT(call_info, "Should not happen.");
2✔
457

458
  napi_status status = napi_ok;
2✔
459

460
  {
2✔
461
    // Call on_audio_frame() of the TEN JS extension.
462

463
    // Get the TEN JS extension.
464
    napi_value js_extension = NULL;
2✔
465
    status = napi_get_reference_value(
2✔
466
        env, call_info->extension_bridge->bridge.js_instance_ref,
2✔
467
        &js_extension);
2✔
468
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
2✔
469
                            "Failed to get JS extension: %d", status);
2✔
470

471
    // Get the TEN JS ten_env.
472
    napi_value js_ten_env = NULL;
2✔
473
    status = napi_get_reference_value(
2✔
474
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
2✔
475
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
2✔
476
                            "Failed to get JS ten_env: %d", status);
2✔
477

478
    napi_value js_audio_frame =
2✔
479
        ten_nodejs_audio_frame_wrap(env, call_info->msg);
2✔
480
    GOTO_LABEL_IF_NAPI_FAIL(error, js_audio_frame != NULL,
2✔
481
                            "Failed to wrap JS Data.");
2✔
482

483
    // Call on_audio_frame().
484
    napi_value result = NULL;
2✔
485
    napi_value argv[] = {js_ten_env, js_audio_frame};
2✔
486
    status = napi_call_function(env, js_extension, fn, 2, argv, &result);
2✔
487
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
2✔
488
                            "Failed to call JS extension on_audio_frame(): %d",
2✔
489
                            status);
2✔
490
  }
2✔
491

492
  goto done;
2✔
493

494
error:
2✔
495
  TEN_LOGE("Failed to call JS extension on_audio_frame()");
×
496

497
done:
2✔
498
  ten_shared_ptr_destroy(call_info->msg);
2✔
499
  TEN_FREE(call_info);
2✔
500
}
2✔
501

502
static void ten_nodejs_invoke_extension_js_on_video_frame(
503
    napi_env env, napi_value fn, TEN_UNUSED void *context, void *data) {
2✔
504
  extension_on_msg_call_info_t *call_info = data;
2✔
505
  TEN_ASSERT(call_info, "Should not happen.");
2✔
506

507
  napi_status status = napi_ok;
2✔
508

509
  {
2✔
510
    // Call on_video_frame() of the TEN JS extension.
511

512
    // Get the TEN JS extension.
513
    napi_value js_extension = NULL;
2✔
514
    status = napi_get_reference_value(
2✔
515
        env, call_info->extension_bridge->bridge.js_instance_ref,
2✔
516
        &js_extension);
2✔
517
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_extension != NULL,
2✔
518
                            "Failed to get JS extension: %d", status);
2✔
519

520
    // Get the TEN JS ten_env.
521
    napi_value js_ten_env = NULL;
2✔
522
    status = napi_get_reference_value(
2✔
523
        env, call_info->ten_env_bridge->bridge.js_instance_ref, &js_ten_env);
2✔
524
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok && js_ten_env != NULL,
2✔
525
                            "Failed to get JS ten_env: %d", status);
2✔
526

527
    napi_value js_video_frame =
2✔
528
        ten_nodejs_video_frame_wrap(env, call_info->msg);
2✔
529
    GOTO_LABEL_IF_NAPI_FAIL(error, js_video_frame != NULL,
2✔
530
                            "Failed to wrap JS Data.");
2✔
531

532
    // Call on_video_frame().
533
    napi_value result = NULL;
2✔
534
    napi_value argv[] = {js_ten_env, js_video_frame};
2✔
535
    status = napi_call_function(env, js_extension, fn, 2, argv, &result);
2✔
536
    GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
2✔
537
                            "Failed to call JS extension on_video_frame(): %d",
2✔
538
                            status);
2✔
539
  }
2✔
540

541
  goto done;
2✔
542

543
error:
2✔
544
  TEN_LOGE("Failed to call JS extension on_video_frame()");
×
545

546
done:
2✔
547
  ten_shared_ptr_destroy(call_info->msg);
2✔
548
  TEN_FREE(call_info);
2✔
549
}
2✔
550

551
static void ten_nodejs_extension_create_and_attach_callbacks(
552
    napi_env env, ten_nodejs_extension_t *extension_bridge) {
16✔
553
  TEN_ASSERT(env, "Should not happen.");
16✔
554
  TEN_ASSERT(extension_bridge, "Should not happen.");
16✔
555
  TEN_ASSERT(ten_nodejs_extension_check_integrity(extension_bridge, true),
16✔
556
             "Should not happen.");
16✔
557

558
  napi_value js_extension = NULL;
16✔
559
  napi_status status = napi_get_reference_value(
16✔
560
      env, extension_bridge->bridge.js_instance_ref, &js_extension);
16✔
561
  ASSERT_IF_NAPI_FAIL(status == napi_ok && js_extension != NULL,
16✔
562
                      "Failed to get JS extension instance.");
16✔
563

564
  napi_value js_on_configure_proxy =
16✔
565
      ten_nodejs_get_property(env, js_extension, "onConfigureProxy");
16✔
566
  CREATE_JS_CB_TSFN(extension_bridge->js_on_configure, env,
16✔
567
                    "[TSFN] extension::onConfigure", js_on_configure_proxy,
16✔
568
                    ten_nodejs_invoke_extension_js_on_configure);
16✔
569

570
  napi_value js_on_init_proxy =
16✔
571
      ten_nodejs_get_property(env, js_extension, "onInitProxy");
16✔
572
  CREATE_JS_CB_TSFN(extension_bridge->js_on_init, env,
16✔
573
                    "[TSFN] extension::onInit", js_on_init_proxy,
16✔
574
                    ten_nodejs_invoke_extension_js_on_init);
16✔
575

576
  napi_value js_on_start_proxy =
16✔
577
      ten_nodejs_get_property(env, js_extension, "onStartProxy");
16✔
578
  CREATE_JS_CB_TSFN(extension_bridge->js_on_start, env,
16✔
579
                    "[TSFN] extension::onStart", js_on_start_proxy,
16✔
580
                    ten_nodejs_invoke_extension_js_on_start);
16✔
581

582
  napi_value js_on_stop_proxy =
16✔
583
      ten_nodejs_get_property(env, js_extension, "onStopProxy");
16✔
584
  CREATE_JS_CB_TSFN(extension_bridge->js_on_stop, env,
16✔
585
                    "[TSFN] extension::onStop", js_on_stop_proxy,
16✔
586
                    ten_nodejs_invoke_extension_js_on_stop);
16✔
587

588
  napi_value js_on_deinit_proxy =
16✔
589
      ten_nodejs_get_property(env, js_extension, "onDeinitProxy");
16✔
590
  CREATE_JS_CB_TSFN(extension_bridge->js_on_deinit, env,
16✔
591
                    "[TSFN] extension::onDeinit", js_on_deinit_proxy,
16✔
592
                    ten_nodejs_invoke_extension_js_on_deinit);
16✔
593

594
  napi_value js_on_cmd_proxy =
16✔
595
      ten_nodejs_get_property(env, js_extension, "onCmdProxy");
16✔
596
  CREATE_JS_CB_TSFN(extension_bridge->js_on_cmd, env, "[TSFN] extension::onCmd",
16✔
597
                    js_on_cmd_proxy, ten_nodejs_invoke_extension_js_on_cmd);
16✔
598

599
  napi_value js_on_data_proxy =
16✔
600
      ten_nodejs_get_property(env, js_extension, "onDataProxy");
16✔
601
  CREATE_JS_CB_TSFN(extension_bridge->js_on_data, env,
16✔
602
                    "[TSFN] extension::onData", js_on_data_proxy,
16✔
603
                    ten_nodejs_invoke_extension_js_on_data);
16✔
604

605
  napi_value js_on_audio_frame_proxy =
16✔
606
      ten_nodejs_get_property(env, js_extension, "onAudioFrameProxy");
16✔
607
  CREATE_JS_CB_TSFN(extension_bridge->js_on_audio_frame, env,
16✔
608
                    "[TSFN] extension::onAudioFrame", js_on_audio_frame_proxy,
16✔
609
                    ten_nodejs_invoke_extension_js_on_audio_frame);
16✔
610

611
  napi_value js_on_video_frame_proxy =
16✔
612
      ten_nodejs_get_property(env, js_extension, "onVideoFrameProxy");
16✔
613
  CREATE_JS_CB_TSFN(extension_bridge->js_on_video_frame, env,
16✔
614
                    "[TSFN] extension::onVideoFrame", js_on_video_frame_proxy,
16✔
615
                    ten_nodejs_invoke_extension_js_on_video_frame);
16✔
616
}
16✔
617

618
void ten_nodejs_extension_release_js_on_xxx_tsfn(ten_nodejs_extension_t *self) {
16✔
619
  TEN_ASSERT(self && ten_nodejs_extension_check_integrity(self, true),
16✔
620
             "Should not happen.");
16✔
621

622
  ten_nodejs_tsfn_release(self->js_on_configure);
16✔
623
  ten_nodejs_tsfn_release(self->js_on_init);
16✔
624
  ten_nodejs_tsfn_release(self->js_on_start);
16✔
625
  ten_nodejs_tsfn_release(self->js_on_stop);
16✔
626
  ten_nodejs_tsfn_release(self->js_on_deinit);
16✔
627
  ten_nodejs_tsfn_release(self->js_on_cmd);
16✔
628
  ten_nodejs_tsfn_release(self->js_on_data);
16✔
629
  ten_nodejs_tsfn_release(self->js_on_audio_frame);
16✔
630
  ten_nodejs_tsfn_release(self->js_on_video_frame);
16✔
631
}
16✔
632

633
static void proxy_on_configure(ten_extension_t *self, ten_env_t *ten_env) {
16✔
634
  TEN_LOGI("extension proxy_on_configure");
16✔
635

636
  TEN_ASSERT(self, "Should not happen.");
16✔
637
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
16✔
638
  TEN_ASSERT(ten_env, "Should not happen.");
16✔
639
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
16✔
640

641
  ten_nodejs_extension_t *extension_bridge =
16✔
642
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
16✔
643
  TEN_ASSERT(extension_bridge &&
16✔
644
                 // TEN_NOLINTNEXTLINE(thread-check)
645
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
16✔
646
             "Should not happen.");
16✔
647

648
  extension_on_xxx_call_info_t *call_info =
16✔
649
      TEN_MALLOC(sizeof(extension_on_xxx_call_info_t));
16✔
650
  TEN_ASSERT(call_info, "Failed to allocate memory.");
16✔
651

652
  call_info->extension_bridge = extension_bridge;
16✔
653
  call_info->ten_env_bridge = NULL;
16✔
654
  call_info->ten_env = ten_env;
16✔
655
  call_info->ten_env_proxy = ten_env_proxy_create(ten_env, 1, NULL);
16✔
656

657
  bool rc =
16✔
658
      ten_nodejs_tsfn_invoke(extension_bridge->js_on_configure, call_info);
16✔
659
  if (!rc) {
16✔
660
    TEN_LOGE("Failed to call extension on_configure()");
×
661
    TEN_FREE(call_info);
×
662

663
    // Failed to call JS on_configure(), so that we need to call
664
    // on_configure_done() here to let TEN runtime proceed.
665
    ten_env_on_configure_done(ten_env, NULL);
×
666
  }
×
667
}
16✔
668

669
static void proxy_on_init(ten_extension_t *self, ten_env_t *ten_env) {
16✔
670
  TEN_LOGI("extension proxy_on_init");
16✔
671

672
  TEN_ASSERT(self, "Should not happen.");
16✔
673
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
16✔
674
  TEN_ASSERT(ten_env, "Should not happen.");
16✔
675
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
16✔
676

677
  ten_nodejs_extension_t *extension_bridge =
16✔
678
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
16✔
679
  TEN_ASSERT(extension_bridge &&
16✔
680
                 // TEN_NOLINTNEXTLINE(thread-check)
681
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
16✔
682
             "Should not happen.");
16✔
683

684
  ten_nodejs_ten_env_t *ten_env_bridge =
16✔
685
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
16✔
686
  TEN_ASSERT(ten_env_bridge &&
16✔
687
                 // TEN_NOLINTNEXTLINE(thread-check)
688
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
16✔
689
             "Should not happen.");
16✔
690

691
  extension_on_xxx_call_info_t *call_info =
16✔
692
      TEN_MALLOC(sizeof(extension_on_xxx_call_info_t));
16✔
693
  TEN_ASSERT(call_info, "Failed to allocate memory.");
16✔
694

695
  call_info->extension_bridge = extension_bridge;
16✔
696
  call_info->ten_env_bridge = ten_env_bridge;
16✔
697

698
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_init, call_info);
16✔
699
  if (!rc) {
16✔
700
    TEN_LOGE("Failed to call extension on_init()");
×
701
    TEN_FREE(call_info);
×
702

703
    // Failed to call JS on_init(), so that we need to call on_init_done() here
704
    // to let TEN runtime proceed.
705
    ten_env_on_init_done(ten_env, NULL);
×
706
  }
×
707
}
16✔
708

709
static void proxy_on_start(ten_extension_t *self, ten_env_t *ten_env) {
16✔
710
  TEN_LOGI("extension proxy_on_start");
16✔
711

712
  TEN_ASSERT(self, "Should not happen.");
16✔
713
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
16✔
714
  TEN_ASSERT(ten_env, "Should not happen.");
16✔
715
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
16✔
716

717
  ten_nodejs_extension_t *extension_bridge =
16✔
718
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
16✔
719
  TEN_ASSERT(extension_bridge &&
16✔
720
                 // TEN_NOLINTNEXTLINE(thread-check)
721
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
16✔
722
             "Should not happen.");
16✔
723

724
  ten_nodejs_ten_env_t *ten_env_bridge =
16✔
725
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
16✔
726
  TEN_ASSERT(ten_env_bridge &&
16✔
727
                 // TEN_NOLINTNEXTLINE(thread-check)
728
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
16✔
729
             "Should not happen.");
16✔
730

731
  extension_on_xxx_call_info_t *call_info =
16✔
732
      TEN_MALLOC(sizeof(extension_on_xxx_call_info_t));
16✔
733
  TEN_ASSERT(call_info, "Failed to allocate memory.");
16✔
734

735
  call_info->extension_bridge = extension_bridge;
16✔
736
  call_info->ten_env_bridge = ten_env_bridge;
16✔
737

738
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_start, call_info);
16✔
739
  if (!rc) {
16✔
740
    TEN_LOGE("Failed to call extension on_start()");
×
741
    TEN_FREE(call_info);
×
742

743
    // Failed to call JS on_start(), so that we need to call on_start_done()
744
    // here to let TEN runtime proceed.
745
    ten_env_on_start_done(ten_env, NULL);
×
746
  }
×
747
}
16✔
748

749
static void proxy_on_stop(ten_extension_t *self, ten_env_t *ten_env) {
16✔
750
  TEN_LOGI("extension proxy_on_stop");
16✔
751

752
  TEN_ASSERT(self, "Should not happen.");
16✔
753
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
16✔
754
  TEN_ASSERT(ten_env, "Should not happen.");
16✔
755
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
16✔
756

757
  ten_nodejs_extension_t *extension_bridge =
16✔
758
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
16✔
759
  TEN_ASSERT(extension_bridge &&
16✔
760
                 // TEN_NOLINTNEXTLINE(thread-check)
761
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
16✔
762
             "Should not happen.");
16✔
763

764
  ten_nodejs_ten_env_t *ten_env_bridge =
16✔
765
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
16✔
766
  TEN_ASSERT(ten_env_bridge &&
16✔
767
                 // TEN_NOLINTNEXTLINE(thread-check)
768
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
16✔
769
             "Should not happen.");
16✔
770

771
  extension_on_xxx_call_info_t *call_info =
16✔
772
      TEN_MALLOC(sizeof(extension_on_xxx_call_info_t));
16✔
773
  TEN_ASSERT(call_info, "Failed to allocate memory.");
16✔
774

775
  call_info->extension_bridge = extension_bridge;
16✔
776
  call_info->ten_env_bridge = ten_env_bridge;
16✔
777

778
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_stop, call_info);
16✔
779
  if (!rc) {
16✔
780
    TEN_LOGE("Failed to call extension on_stop()");
×
781
    TEN_FREE(call_info);
×
782

783
    // Failed to call JS on_stop(), so that we need to call on_stop_done() here
784
    // to let TEN runtime proceed.
785
    ten_env_on_stop_done(ten_env, NULL);
×
786
  }
×
787
}
16✔
788

789
static void proxy_on_deinit(ten_extension_t *self, ten_env_t *ten_env) {
16✔
790
  TEN_LOGI("extension proxy_on_deinit");
16✔
791

792
  TEN_ASSERT(self, "Should not happen.");
16✔
793
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
16✔
794
  TEN_ASSERT(ten_env, "Should not happen.");
16✔
795
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
16✔
796

797
  ten_nodejs_extension_t *extension_bridge =
16✔
798
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
16✔
799
  TEN_ASSERT(extension_bridge &&
16✔
800
                 // TEN_NOLINTNEXTLINE(thread-check)
801
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
16✔
802
             "Should not happen.");
16✔
803

804
  ten_nodejs_ten_env_t *ten_env_bridge =
16✔
805
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
16✔
806
  TEN_ASSERT(ten_env_bridge &&
16✔
807
                 // TEN_NOLINTNEXTLINE(thread-check)
808
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
16✔
809
             "Should not happen.");
16✔
810

811
  extension_on_xxx_call_info_t *call_info =
16✔
812
      TEN_MALLOC(sizeof(extension_on_xxx_call_info_t));
16✔
813
  TEN_ASSERT(call_info, "Failed to allocate memory.");
16✔
814

815
  call_info->extension_bridge = extension_bridge;
16✔
816
  call_info->ten_env_bridge = ten_env_bridge;
16✔
817

818
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_deinit, call_info);
16✔
819
  if (!rc) {
16✔
820
    TEN_LOGE("Failed to call extension on_deinit()");
×
821
    TEN_FREE(call_info);
×
822

823
    // Failed to call JS on_deinit(), so that we need to call on_deinit_done()
824
    // here to let TEN runtime proceed.
825
    ten_env_on_deinit_done(ten_env, NULL);
×
826
  }
×
827
}
16✔
828

829
static void proxy_on_cmd(ten_extension_t *self, ten_env_t *ten_env,
830
                         ten_shared_ptr_t *cmd) {
2✔
831
  TEN_ASSERT(self, "Should not happen.");
2✔
832
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
2✔
833
  TEN_ASSERT(ten_env, "Should not happen.");
2✔
834
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
2✔
835

836
  ten_nodejs_extension_t *extension_bridge =
2✔
837
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
2✔
838
  TEN_ASSERT(extension_bridge &&
2✔
839
                 // TEN_NOLINTNEXTLINE(thread-check)
840
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
2✔
841
             "Should not happen.");
2✔
842

843
  ten_nodejs_ten_env_t *ten_env_bridge =
2✔
844
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
2✔
845
  TEN_ASSERT(ten_env_bridge &&
2✔
846
                 // TEN_NOLINTNEXTLINE(thread-check)
847
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
2✔
848
             "Should not happen.");
2✔
849

850
  extension_on_msg_call_info_t *call_info =
2✔
851
      TEN_MALLOC(sizeof(extension_on_msg_call_info_t));
2✔
852
  TEN_ASSERT(call_info, "Failed to allocate memory.");
2✔
853

854
  call_info->extension_bridge = extension_bridge;
2✔
855
  call_info->ten_env_bridge = ten_env_bridge;
2✔
856
  call_info->msg = ten_shared_ptr_clone(cmd);
2✔
857

858
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_cmd, call_info);
2✔
859
  if (!rc) {
2✔
860
    TEN_LOGE("Failed to call extension on_cmd()");
×
861
    TEN_FREE(call_info);
×
862
  }
×
863
}
2✔
864
static void proxy_on_data(ten_extension_t *self, ten_env_t *ten_env,
865
                          ten_shared_ptr_t *data) {
2✔
866
  TEN_ASSERT(self, "Should not happen.");
2✔
867
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
2✔
868
  TEN_ASSERT(ten_env, "Should not happen.");
2✔
869
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
2✔
870

871
  ten_nodejs_extension_t *extension_bridge =
2✔
872
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
2✔
873
  TEN_ASSERT(extension_bridge &&
2✔
874
                 // TEN_NOLINTNEXTLINE(thread-check)
875
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
2✔
876
             "Should not happen.");
2✔
877

878
  ten_nodejs_ten_env_t *ten_env_bridge =
2✔
879
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
2✔
880
  TEN_ASSERT(ten_env_bridge &&
2✔
881
                 // TEN_NOLINTNEXTLINE(thread-check)
882
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
2✔
883
             "Should not happen.");
2✔
884

885
  extension_on_msg_call_info_t *call_info =
2✔
886
      TEN_MALLOC(sizeof(extension_on_msg_call_info_t));
2✔
887
  TEN_ASSERT(call_info, "Failed to allocate memory.");
2✔
888

889
  call_info->extension_bridge = extension_bridge;
2✔
890
  call_info->ten_env_bridge = ten_env_bridge;
2✔
891
  call_info->msg = ten_shared_ptr_clone(data);
2✔
892

893
  bool rc = ten_nodejs_tsfn_invoke(extension_bridge->js_on_data, call_info);
2✔
894
  if (!rc) {
2✔
895
    TEN_LOGE("Failed to call extension on_data()");
×
896
    TEN_FREE(call_info);
×
897
  }
×
898
}
2✔
899
static void proxy_on_audio_frame(ten_extension_t *self, ten_env_t *ten_env,
900
                                 ten_shared_ptr_t *frame) {
2✔
901
  TEN_ASSERT(self, "Should not happen.");
2✔
902
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
2✔
903

904
  ten_nodejs_extension_t *extension_bridge =
2✔
905
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
2✔
906
  TEN_ASSERT(extension_bridge &&
2✔
907
                 // TEN_NOLINTNEXTLINE(thread-check)
908
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
2✔
909
             "Should not happen.");
2✔
910

911
  ten_nodejs_ten_env_t *ten_env_bridge =
2✔
912
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
2✔
913
  TEN_ASSERT(ten_env_bridge &&
2✔
914
                 // TEN_NOLINTNEXTLINE(thread-check)
915
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
2✔
916
             "Should not happen.");
2✔
917

918
  extension_on_msg_call_info_t *call_info =
2✔
919
      TEN_MALLOC(sizeof(extension_on_msg_call_info_t));
2✔
920
  TEN_ASSERT(call_info, "Failed to allocate memory.");
2✔
921

922
  call_info->extension_bridge = extension_bridge;
2✔
923
  call_info->ten_env_bridge = ten_env_bridge;
2✔
924
  call_info->msg = ten_shared_ptr_clone(frame);
2✔
925

926
  bool rc =
2✔
927
      ten_nodejs_tsfn_invoke(extension_bridge->js_on_audio_frame, call_info);
2✔
928
  if (!rc) {
2✔
929
    TEN_LOGE("Failed to call extension on_audio_frame()");
×
930
    TEN_FREE(call_info);
×
931
  }
×
932
}
2✔
933
static void proxy_on_video_frame(ten_extension_t *self, ten_env_t *ten_env,
934
                                 ten_shared_ptr_t *frame) {
2✔
935
  TEN_ASSERT(self, "Should not happen.");
2✔
936
  TEN_ASSERT(ten_extension_check_integrity(self, true), "Should not happen.");
2✔
937
  TEN_ASSERT(ten_env, "Should not happen.");
2✔
938
  TEN_ASSERT(ten_env_check_integrity(ten_env, true), "Should not happen.");
2✔
939

940
  ten_nodejs_extension_t *extension_bridge =
2✔
941
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)self);
2✔
942
  TEN_ASSERT(extension_bridge &&
2✔
943
                 // TEN_NOLINTNEXTLINE(thread-check)
944
                 ten_nodejs_extension_check_integrity(extension_bridge, false),
2✔
945
             "Should not happen.");
2✔
946

947
  ten_nodejs_ten_env_t *ten_env_bridge =
2✔
948
      ten_binding_handle_get_me_in_target_lang((ten_binding_handle_t *)ten_env);
2✔
949
  TEN_ASSERT(ten_env_bridge &&
2✔
950
                 // TEN_NOLINTNEXTLINE(thread-check)
951
                 ten_nodejs_ten_env_check_integrity(ten_env_bridge, false),
2✔
952
             "Should not happen.");
2✔
953

954
  extension_on_msg_call_info_t *call_info =
2✔
955
      TEN_MALLOC(sizeof(extension_on_msg_call_info_t));
2✔
956
  TEN_ASSERT(call_info, "Failed to allocate memory.");
2✔
957

958
  call_info->extension_bridge = extension_bridge;
2✔
959
  call_info->ten_env_bridge = ten_env_bridge;
2✔
960
  call_info->msg = ten_shared_ptr_clone(frame);
2✔
961

962
  bool rc =
2✔
963
      ten_nodejs_tsfn_invoke(extension_bridge->js_on_video_frame, call_info);
2✔
964
  if (!rc) {
2✔
965
    TEN_LOGE("Failed to call extension on_video_frame()");
×
966
    TEN_FREE(call_info);
×
967
  }
×
968
}
2✔
969

970
static napi_value ten_nodejs_extension_create(napi_env env,
971
                                              napi_callback_info info) {
16✔
972
  TEN_ASSERT(env, "Should not happen.");
16✔
973

974
#if defined(_DEBUG)
16✔
975
  const char *enable_intentional_memory_leak =
16✔
976
      // NOLINTNEXTLINE(concurrency-mt-unsafe)
977
      getenv("TEN_ENABLE_INTENTIONAL_MEMORY_LEAK");
16✔
978
  if (enable_intentional_memory_leak &&
16✔
979
      !strcmp(enable_intentional_memory_leak, "true")) {
16✔
980
    TEN_LOGD(
×
981
        "TEN_ENABLE_INTENTIONAL_MEMORY_LEAK is defined. Memory leak is "
×
982
        "happening in nodejs extension creation.");
×
983
    TEN_MALLOC(10);
×
984
  }
×
985
#endif
16✔
986

987
  ten_string_t name;
16✔
988
  TEN_STRING_INIT(name);
16✔
989

990
  const size_t argc = 2;
16✔
991
  napi_value args[argc];  // this, name
16✔
992
  if (!ten_nodejs_get_js_func_args(env, info, args, argc)) {
16✔
993
    napi_fatal_error(NULL, NAPI_AUTO_LENGTH,
×
994
                     "Incorrect number of parameters passed.",
×
995
                     NAPI_AUTO_LENGTH);
×
996
    TEN_ASSERT(0, "Should not happen.");
×
997
    goto done;
×
998
  }
×
999

1000
  if (!ten_nodejs_get_str_from_js(env, args[1], &name)) {
16✔
1001
    napi_fatal_error(NULL, NAPI_AUTO_LENGTH, "Failed to get name.",
×
1002
                     NAPI_AUTO_LENGTH);
×
1003
    TEN_ASSERT(0, "Should not happen.");
×
1004
    goto done;
×
1005
  }
×
1006

1007
  ten_nodejs_extension_t *extension_bridge =
16✔
1008
      TEN_MALLOC(sizeof(ten_nodejs_extension_t));
16✔
1009
  TEN_ASSERT(extension_bridge, "Failed to allocate memory.");
16✔
1010

1011
  ten_signature_set(&extension_bridge->signature,
16✔
1012
                    TEN_NODEJS_EXTENSION_SIGNATURE);
16✔
1013

1014
  // The ownership of the TEN extension_bridge is the JS main thread.
1015
  ten_sanitizer_thread_check_init_with_current_thread(
16✔
1016
      &extension_bridge->thread_check);
16✔
1017

1018
  // Wraps the native bridge instance ('extension_bridge') in the javascript
1019
  // extension object (args[0]). And the returned reference ('js_ref' here) is
1020
  // a weak reference, meaning it has a reference count of 0.
1021
  napi_status status =
16✔
1022
      napi_wrap(env, args[0], extension_bridge, ten_nodejs_extension_finalize,
16✔
1023
                NULL, &extension_bridge->bridge.js_instance_ref);
16✔
1024
  GOTO_LABEL_IF_NAPI_FAIL(error, status == napi_ok,
16✔
1025
                          "Failed to bind JS extension & bridge: %d", status);
16✔
1026

1027
  // Increase the reference count of the JS extension, so that it can survive
1028
  // after the ends of this native function.
1029
  uint32_t js_extension_ref_count = 0;
16✔
1030
  status = napi_reference_ref(env, extension_bridge->bridge.js_instance_ref,
16✔
1031
                              &js_extension_ref_count);
16✔
1032
  GOTO_LABEL_IF_NAPI_FAIL(
16✔
1033
      error, status == napi_ok,
16✔
1034
      "Failed to increase the reference count of JS extension: "
16✔
1035
      "%d",
16✔
1036
      status);
16✔
1037

1038
  // Create the underlying TEN C extension.
1039
  extension_bridge->c_extension = ten_extension_create(
16✔
1040
      ten_string_get_raw_str(&name), proxy_on_configure, proxy_on_init,
16✔
1041
      proxy_on_start, proxy_on_stop, proxy_on_deinit, proxy_on_cmd,
16✔
1042
      proxy_on_data, proxy_on_audio_frame, proxy_on_video_frame, NULL);
16✔
1043
  ten_binding_handle_set_me_in_target_lang(
16✔
1044
      (ten_binding_handle_t *)(extension_bridge->c_extension),
16✔
1045
      extension_bridge);
16✔
1046

1047
  ten_nodejs_extension_create_and_attach_callbacks(env, extension_bridge);
16✔
1048

1049
  goto done;
16✔
1050

1051
error:
×
1052
  if (extension_bridge) {
×
1053
    TEN_FREE(extension_bridge);
×
1054
  }
×
1055

1056
done:
16✔
1057
  ten_string_deinit(&name);
16✔
1058
  return js_undefined(env);
16✔
1059
}
×
1060

1061
napi_value ten_nodejs_extension_module_init(napi_env env, napi_value exports) {
3✔
1062
  TEN_ASSERT(env && exports, "Should not happen.");
3✔
1063
  EXPORT_FUNC(env, exports, ten_nodejs_extension_create);
3✔
1064

1065
  return exports;
3✔
1066
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc