@mertushka/webrtc-node 0.1.0-alpha.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +373 -373
- package/README.md +72 -79
- package/docs/conformance.md +10 -0
- package/docs/development.md +14 -2
- package/lib/index.js +339 -76
- package/package.json +1 -1
- package/scripts/check-native-integration.js +17 -2
- package/scripts/install-native.js +5 -0
- package/scripts/run-docker-linux-ci.ps1 +73 -73
- package/src/native/addon.cc +121 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mertushka/webrtc-node",
|
|
3
|
-
"version": "0.1.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "W3C-style RTCPeerConnection and RTCDataChannel for Node.js, backed by libdatachannel.",
|
|
5
5
|
"author": "mertushka",
|
|
6
6
|
"homepage": "https://github.com/mertushka/webrtc-node#readme",
|
|
@@ -64,11 +64,26 @@ forbidMatch("NAN namespace usage", addon, /\bNan::/);
|
|
|
64
64
|
forbidMatch("non-Node-API module initializer", addon, /\bNODE_MODULE\s*\(/);
|
|
65
65
|
|
|
66
66
|
const callbackCallMatches = [...addon.matchAll(/\bcallback\.Call\s*\(/g)];
|
|
67
|
-
if (callbackCallMatches.length !==
|
|
67
|
+
if (callbackCallMatches.length !== 3) {
|
|
68
68
|
fail(
|
|
69
|
-
`expected exactly
|
|
69
|
+
`expected exactly three callback.Call sites inside EventDispatcher dispatch paths, found ${callbackCallMatches.length}`,
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
|
+
requireMatch(
|
|
73
|
+
"single native event callback dispatch",
|
|
74
|
+
addon,
|
|
75
|
+
/callback\.Call\s*\(\s*\{\s*EventToObject/,
|
|
76
|
+
);
|
|
77
|
+
requireMatch(
|
|
78
|
+
"batched native event callback dispatch",
|
|
79
|
+
addon,
|
|
80
|
+
/callback\.Call\s*\(\s*\{\s*batch\s*\}\s*\)/,
|
|
81
|
+
);
|
|
82
|
+
requireMatch(
|
|
83
|
+
"direct native event callback dispatch",
|
|
84
|
+
addon,
|
|
85
|
+
/DispatchDirect[\s\S]*callback\.Call\s*\(\s*\{\s*EventToObject/,
|
|
86
|
+
);
|
|
72
87
|
|
|
73
88
|
const cmakePinMatch = /set\s*\(\s*LIBDATACHANNEL_PINNED_COMMIT\s+"([0-9a-f]{40})"/i.exec(cmake);
|
|
74
89
|
if (!cmakePinMatch) fail("CMake libdatachannel pin is missing");
|
|
@@ -87,6 +87,7 @@ function runBuild() {
|
|
|
87
87
|
|
|
88
88
|
async function main() {
|
|
89
89
|
const buildFromSource = envFlag("npm_config_build_from_source");
|
|
90
|
+
const prebuildOnly = envFlag("WEBRTC_NODE_PREBUILD_ONLY");
|
|
90
91
|
if (!buildFromSource && hasNativeAddon()) return;
|
|
91
92
|
|
|
92
93
|
if (isSourceCheckout() && !buildFromSource) {
|
|
@@ -101,6 +102,10 @@ async function main() {
|
|
|
101
102
|
throw new Error(`downloaded archive did not provide ${moduleName}`);
|
|
102
103
|
} catch (error) {
|
|
103
104
|
console.warn(`Prebuilt binary unavailable for ${targetTuple()}: ${error.message}`);
|
|
105
|
+
if (prebuildOnly) {
|
|
106
|
+
console.error("Prebuild-only install requested; refusing to build from source.");
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
104
109
|
}
|
|
105
110
|
}
|
|
106
111
|
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
param(
|
|
2
|
-
[string]$NodeImage = "node:20-bookworm",
|
|
3
|
-
[string]$ArtifactsDir = "ci-artifacts/docker-linux-node20",
|
|
4
|
-
[switch]$SkipWpt,
|
|
5
|
-
[string[]]$WptSelector = @(),
|
|
6
|
-
[int]$WptExpectedTotal = 0
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
$ErrorActionPreference = "Stop"
|
|
10
|
-
|
|
11
|
-
$root = Resolve-Path (Join-Path $PSScriptRoot "..")
|
|
12
|
-
$artifactPath = Join-Path $root $ArtifactsDir
|
|
13
|
-
New-Item -ItemType Directory -Force $artifactPath | Out-Null
|
|
14
|
-
|
|
15
|
-
$rootForDocker = $root.Path -replace "\\", "/"
|
|
16
|
-
$artifactForDocker = (Resolve-Path $artifactPath).Path -replace "\\", "/"
|
|
17
|
-
$wptSelectorArgs = ($WptSelector | ForEach-Object {
|
|
18
|
-
if ($_.Contains("'")) {
|
|
19
|
-
throw "WPT selector cannot contain a single quote: $_"
|
|
20
|
-
}
|
|
21
|
-
"'$_'"
|
|
22
|
-
}) -join " "
|
|
23
|
-
$wptTestCommand = if ($WptSelector.Count -gt 0) {
|
|
24
|
-
"npm run wpt:test -- $wptSelectorArgs"
|
|
25
|
-
} else {
|
|
26
|
-
"npm run wpt:test"
|
|
27
|
-
}
|
|
28
|
-
$wptCheckCommand = if ($WptSelector.Count -gt 0) {
|
|
29
|
-
$expectedTotal = if ($WptExpectedTotal -gt 0) { $WptExpectedTotal } else { $WptSelector.Count }
|
|
30
|
-
"WPT_EXPECTED_TOTAL=$expectedTotal npm run wpt:check:strict"
|
|
31
|
-
} else {
|
|
32
|
-
"npm run wpt:check:strict"
|
|
33
|
-
}
|
|
34
|
-
$wptReportCommand = if ($WptSelector.Count -gt 0) {
|
|
35
|
-
"true"
|
|
36
|
-
} else {
|
|
37
|
-
"npm run wpt:report -- --output /out/wpt-report.md && RUNNER_OS=Linux RUNNER_ARCH=X64 node scripts/write-ci-evidence.js --results /out/wpt-results.json --output /out/ci-evidence.json"
|
|
38
|
-
}
|
|
39
|
-
$wptCommand = if ($SkipWpt) {
|
|
40
|
-
"npm run wpt:selection:check"
|
|
41
|
-
} else {
|
|
42
|
-
"npm run wpt:selection:check && WPT_TEST_TIMEOUT_MS=180000 WPT_WORKER_TIMEOUT_MS=600000 WPT_WORKER_DELAY_MS=2000 WPT_CLEANUP_DELAY_MS=3000 $wptTestCommand 2>&1 | tee /out/wpt-output.txt && cp wpt-results.json /out/wpt-results.json && $wptCheckCommand && $wptReportCommand"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
docker run --rm `
|
|
46
|
-
-v "${rootForDocker}:/src:ro" `
|
|
47
|
-
-v "${artifactForDocker}:/out" `
|
|
48
|
-
$NodeImage `
|
|
49
|
-
bash -lc "set -euo pipefail; mkdir -p /tmp/webrtc-node; tar -C /src --exclude='./build' --exclude='./node_modules' --exclude='./.git' --exclude='./wpt-results.json' --exclude='./wpt-report.md' --exclude='./ci-artifacts' -cf - . | tar -C /tmp/webrtc-node -xf -; cd /tmp/webrtc-node; if [ -f /etc/apt/sources.list.d/debian.sources ]; then sed -i '0,/URIs: http:\/\/deb.debian.org\/debian$/s//URIs: http:\/\/snapshot.debian.org\/archive\/debian\/20260421T000000Z/' /etc/apt/sources.list.d/debian.sources; sed -i '0,/URIs: http:\/\/deb.debian.org\/debian-security$/s//URIs: http:\/\/snapshot.debian.org\/archive\/debian-security\/20260421T000000Z/' /etc/apt/sources.list.d/debian.sources; fi; for attempt in 1 2 3; do if apt-get -o Acquire::Check-Valid-Until=false update >/out/apt-update.txt 2>&1 && apt-get install -y cmake ninja-build libssl-dev >/out/apt-install.txt 2>&1; then break; fi; if [ ""`$attempt"" = 3 ]; then exit 1; fi; sleep `$((attempt * 10)); done; npm ci 2>&1 | tee /out/npm-ci.txt; npm run check; npm run native:check; npm run build 2>&1 | tee /out/build-output.txt; npm test; npm run api:check; npm run types:check; npm run wpt:ensure; set +e; ${wptCommand}; wpt_status=`$?; set -e; cp wpt-results.json /out/wpt-results.json 2>/dev/null || true; cp wpt-manifest.json /out/wpt-manifest.json; npm run wpt:manifest > /out/wpt-manifest.txt; exit `$wpt_status"
|
|
50
|
-
|
|
51
|
-
$dockerExitCode = $LASTEXITCODE
|
|
52
|
-
|
|
53
|
-
if (-not $SkipWpt) {
|
|
54
|
-
$resultsPath = Join-Path $artifactPath "wpt-results.json"
|
|
55
|
-
if (-not (Test-Path $resultsPath)) {
|
|
56
|
-
throw "Docker CI did not produce $resultsPath"
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
$results = Get-Content -Raw -Path $resultsPath | ConvertFrom-Json
|
|
60
|
-
if ([int]$results.fail -gt 0) {
|
|
61
|
-
throw "Docker CI WPT subset failed: $($results.pass)/$($results.total) passed"
|
|
62
|
-
}
|
|
63
|
-
$retried = @($results.results | Where-Object {
|
|
64
|
-
($_.PSObject.Properties.Name -contains "retries") -and [int]$_.retries -gt 0
|
|
65
|
-
}).Count
|
|
66
|
-
if ($retried -gt 0) {
|
|
67
|
-
throw "Docker CI WPT subset required retries: $retried"
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if ($dockerExitCode -ne 0) {
|
|
72
|
-
throw "Docker CI failed with exit code $dockerExitCode"
|
|
73
|
-
}
|
|
1
|
+
param(
|
|
2
|
+
[string]$NodeImage = "node:20-bookworm",
|
|
3
|
+
[string]$ArtifactsDir = "ci-artifacts/docker-linux-node20",
|
|
4
|
+
[switch]$SkipWpt,
|
|
5
|
+
[string[]]$WptSelector = @(),
|
|
6
|
+
[int]$WptExpectedTotal = 0
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference = "Stop"
|
|
10
|
+
|
|
11
|
+
$root = Resolve-Path (Join-Path $PSScriptRoot "..")
|
|
12
|
+
$artifactPath = Join-Path $root $ArtifactsDir
|
|
13
|
+
New-Item -ItemType Directory -Force $artifactPath | Out-Null
|
|
14
|
+
|
|
15
|
+
$rootForDocker = $root.Path -replace "\\", "/"
|
|
16
|
+
$artifactForDocker = (Resolve-Path $artifactPath).Path -replace "\\", "/"
|
|
17
|
+
$wptSelectorArgs = ($WptSelector | ForEach-Object {
|
|
18
|
+
if ($_.Contains("'")) {
|
|
19
|
+
throw "WPT selector cannot contain a single quote: $_"
|
|
20
|
+
}
|
|
21
|
+
"'$_'"
|
|
22
|
+
}) -join " "
|
|
23
|
+
$wptTestCommand = if ($WptSelector.Count -gt 0) {
|
|
24
|
+
"npm run wpt:test -- $wptSelectorArgs"
|
|
25
|
+
} else {
|
|
26
|
+
"npm run wpt:test"
|
|
27
|
+
}
|
|
28
|
+
$wptCheckCommand = if ($WptSelector.Count -gt 0) {
|
|
29
|
+
$expectedTotal = if ($WptExpectedTotal -gt 0) { $WptExpectedTotal } else { $WptSelector.Count }
|
|
30
|
+
"WPT_EXPECTED_TOTAL=$expectedTotal npm run wpt:check:strict"
|
|
31
|
+
} else {
|
|
32
|
+
"npm run wpt:check:strict"
|
|
33
|
+
}
|
|
34
|
+
$wptReportCommand = if ($WptSelector.Count -gt 0) {
|
|
35
|
+
"true"
|
|
36
|
+
} else {
|
|
37
|
+
"npm run wpt:report -- --output /out/wpt-report.md && RUNNER_OS=Linux RUNNER_ARCH=X64 node scripts/write-ci-evidence.js --results /out/wpt-results.json --output /out/ci-evidence.json"
|
|
38
|
+
}
|
|
39
|
+
$wptCommand = if ($SkipWpt) {
|
|
40
|
+
"npm run wpt:selection:check"
|
|
41
|
+
} else {
|
|
42
|
+
"npm run wpt:selection:check && WPT_TEST_TIMEOUT_MS=180000 WPT_WORKER_TIMEOUT_MS=600000 WPT_WORKER_DELAY_MS=2000 WPT_CLEANUP_DELAY_MS=3000 $wptTestCommand 2>&1 | tee /out/wpt-output.txt && cp wpt-results.json /out/wpt-results.json && $wptCheckCommand && $wptReportCommand"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
docker run --rm `
|
|
46
|
+
-v "${rootForDocker}:/src:ro" `
|
|
47
|
+
-v "${artifactForDocker}:/out" `
|
|
48
|
+
$NodeImage `
|
|
49
|
+
bash -lc "set -euo pipefail; mkdir -p /tmp/webrtc-node; tar -C /src --exclude='./build' --exclude='./node_modules' --exclude='./.git' --exclude='./wpt-results.json' --exclude='./wpt-report.md' --exclude='./ci-artifacts' -cf - . | tar -C /tmp/webrtc-node -xf -; cd /tmp/webrtc-node; if [ -f /etc/apt/sources.list.d/debian.sources ]; then sed -i '0,/URIs: http:\/\/deb.debian.org\/debian$/s//URIs: http:\/\/snapshot.debian.org\/archive\/debian\/20260421T000000Z/' /etc/apt/sources.list.d/debian.sources; sed -i '0,/URIs: http:\/\/deb.debian.org\/debian-security$/s//URIs: http:\/\/snapshot.debian.org\/archive\/debian-security\/20260421T000000Z/' /etc/apt/sources.list.d/debian.sources; fi; for attempt in 1 2 3; do if apt-get -o Acquire::Check-Valid-Until=false update >/out/apt-update.txt 2>&1 && apt-get install -y cmake ninja-build libssl-dev >/out/apt-install.txt 2>&1; then break; fi; if [ ""`$attempt"" = 3 ]; then exit 1; fi; sleep `$((attempt * 10)); done; npm ci 2>&1 | tee /out/npm-ci.txt; npm run check; npm run native:check; npm run build 2>&1 | tee /out/build-output.txt; npm test; npm run api:check; npm run types:check; npm run wpt:ensure; set +e; ${wptCommand}; wpt_status=`$?; set -e; cp wpt-results.json /out/wpt-results.json 2>/dev/null || true; cp wpt-manifest.json /out/wpt-manifest.json; npm run wpt:manifest > /out/wpt-manifest.txt; exit `$wpt_status"
|
|
50
|
+
|
|
51
|
+
$dockerExitCode = $LASTEXITCODE
|
|
52
|
+
|
|
53
|
+
if (-not $SkipWpt) {
|
|
54
|
+
$resultsPath = Join-Path $artifactPath "wpt-results.json"
|
|
55
|
+
if (-not (Test-Path $resultsPath)) {
|
|
56
|
+
throw "Docker CI did not produce $resultsPath"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
$results = Get-Content -Raw -Path $resultsPath | ConvertFrom-Json
|
|
60
|
+
if ([int]$results.fail -gt 0) {
|
|
61
|
+
throw "Docker CI WPT subset failed: $($results.pass)/$($results.total) passed"
|
|
62
|
+
}
|
|
63
|
+
$retried = @($results.results | Where-Object {
|
|
64
|
+
($_.PSObject.Properties.Name -contains "retries") -and [int]$_.retries -gt 0
|
|
65
|
+
}).Count
|
|
66
|
+
if ($retried -gt 0) {
|
|
67
|
+
throw "Docker CI WPT subset required retries: $retried"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if ($dockerExitCode -ne 0) {
|
|
72
|
+
throw "Docker CI failed with exit code $dockerExitCode"
|
|
73
|
+
}
|
package/src/native/addon.cc
CHANGED
|
@@ -292,7 +292,7 @@ struct NativeEvent {
|
|
|
292
292
|
std::string error;
|
|
293
293
|
bool binary = false;
|
|
294
294
|
std::string text;
|
|
295
|
-
|
|
295
|
+
rtc::binary bytes;
|
|
296
296
|
};
|
|
297
297
|
|
|
298
298
|
struct EventDispatcher : public std::enable_shared_from_this<EventDispatcher> {
|
|
@@ -303,6 +303,29 @@ struct EventDispatcher : public std::enable_shared_from_this<EventDispatcher> {
|
|
|
303
303
|
~EventDispatcher() { Close(); }
|
|
304
304
|
|
|
305
305
|
void Emit(NativeEvent event) {
|
|
306
|
+
if (event.target != "datachannel" || event.type != "message") {
|
|
307
|
+
EmitDirect(std::move(event));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
bool scheduleDispatch = false;
|
|
312
|
+
std::lock_guard<std::mutex> lock(lifecycleMutex);
|
|
313
|
+
if (!active.load()) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
pendingEvents.push_back(std::move(event));
|
|
318
|
+
if (!dispatchScheduled) {
|
|
319
|
+
dispatchScheduled = true;
|
|
320
|
+
scheduleDispatch = true;
|
|
321
|
+
}
|
|
322
|
+
if (!scheduleDispatch)
|
|
323
|
+
return;
|
|
324
|
+
|
|
325
|
+
QueueDispatchLocked();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
void EmitDirect(NativeEvent event) {
|
|
306
329
|
auto *queued = new NativeEvent(std::move(event));
|
|
307
330
|
std::lock_guard<std::mutex> lock(lifecycleMutex);
|
|
308
331
|
if (!active.load()) {
|
|
@@ -310,13 +333,15 @@ struct EventDispatcher : public std::enable_shared_from_this<EventDispatcher> {
|
|
|
310
333
|
return;
|
|
311
334
|
}
|
|
312
335
|
|
|
313
|
-
napi_status status = tsfn.NonBlockingCall(queued,
|
|
336
|
+
napi_status status = tsfn.NonBlockingCall(queued, DispatchDirect);
|
|
314
337
|
if (status != napi_ok)
|
|
315
338
|
delete queued;
|
|
316
339
|
}
|
|
317
340
|
|
|
318
341
|
void Close() {
|
|
319
342
|
std::lock_guard<std::mutex> lock(lifecycleMutex);
|
|
343
|
+
pendingEvents.clear();
|
|
344
|
+
dispatchScheduled = false;
|
|
320
345
|
if (active.exchange(false))
|
|
321
346
|
tsfn.Release();
|
|
322
347
|
}
|
|
@@ -325,10 +350,76 @@ private:
|
|
|
325
350
|
EventDispatcher(Napi::Env env, Napi::Function callback)
|
|
326
351
|
: tsfn(Napi::ThreadSafeFunction::New(env, callback, "webrtc-node events", 0, 1)) {}
|
|
327
352
|
|
|
328
|
-
|
|
353
|
+
void Drain(Napi::Env env, Napi::Function callback) {
|
|
354
|
+
std::vector<NativeEvent> events;
|
|
355
|
+
{
|
|
356
|
+
std::lock_guard<std::mutex> lock(lifecycleMutex);
|
|
357
|
+
if (pendingEvents.empty()) {
|
|
358
|
+
dispatchScheduled = false;
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
events.swap(pendingEvents);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (events.size() == 1) {
|
|
365
|
+
callback.Call({EventToObject(env, events.front())});
|
|
366
|
+
} else {
|
|
367
|
+
Napi::Array batch = Napi::Array::New(env, events.size());
|
|
368
|
+
for (uint32_t i = 0; i < events.size(); ++i)
|
|
369
|
+
batch.Set(i, EventToObject(env, events[i]));
|
|
370
|
+
callback.Call({batch});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
std::lock_guard<std::mutex> lock(lifecycleMutex);
|
|
374
|
+
if (!active.load() || pendingEvents.empty()) {
|
|
375
|
+
dispatchScheduled = false;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
QueueDispatchLocked();
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
void QueueDispatchLocked() {
|
|
382
|
+
auto *dispatcher = new std::shared_ptr<EventDispatcher>(shared_from_this());
|
|
383
|
+
napi_status status = tsfn.NonBlockingCall(dispatcher, DispatchQueued);
|
|
384
|
+
if (status != napi_ok) {
|
|
385
|
+
dispatchScheduled = false;
|
|
386
|
+
pendingEvents.clear();
|
|
387
|
+
delete dispatcher;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
static void DispatchQueued(Napi::Env env, Napi::Function callback,
|
|
392
|
+
std::shared_ptr<EventDispatcher> *dispatcher) {
|
|
393
|
+
std::shared_ptr<EventDispatcher> scoped = std::move(*dispatcher);
|
|
394
|
+
delete dispatcher;
|
|
395
|
+
scoped->Drain(env, callback);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
static void DispatchDirect(Napi::Env env, Napi::Function callback, NativeEvent *event) {
|
|
399
|
+
std::unique_ptr<NativeEvent> scoped(event);
|
|
400
|
+
callback.Call({EventToObject(env, *scoped)});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
static Napi::Value MessagePayloadToValue(Napi::Env env, NativeEvent &event) {
|
|
404
|
+
if (!event.binary)
|
|
405
|
+
return Napi::String::New(env, event.text);
|
|
406
|
+
|
|
407
|
+
if (event.bytes.empty())
|
|
408
|
+
return Napi::ArrayBuffer::New(env, 0);
|
|
409
|
+
|
|
410
|
+
auto *bytes = new rtc::binary(std::move(event.bytes));
|
|
411
|
+
return Napi::ArrayBuffer::New(
|
|
412
|
+
env, bytes->data(), bytes->size(),
|
|
413
|
+
[](Napi::Env, void *, rtc::binary *finalizedBytes) { delete finalizedBytes; },
|
|
414
|
+
bytes);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
static Napi::Object EventToObject(Napi::Env env, NativeEvent &event);
|
|
329
418
|
|
|
330
419
|
std::atomic<bool> active{true};
|
|
331
420
|
std::mutex lifecycleMutex;
|
|
421
|
+
std::vector<NativeEvent> pendingEvents;
|
|
422
|
+
bool dispatchScheduled = false;
|
|
332
423
|
Napi::ThreadSafeFunction tsfn;
|
|
333
424
|
};
|
|
334
425
|
|
|
@@ -452,10 +543,7 @@ private:
|
|
|
452
543
|
event.text = std::get<std::string>(std::move(data));
|
|
453
544
|
} else {
|
|
454
545
|
event.binary = true;
|
|
455
|
-
|
|
456
|
-
event.bytes.reserve(binary.size());
|
|
457
|
-
for (std::byte value : binary)
|
|
458
|
-
event.bytes.push_back(std::to_integer<uint8_t>(value));
|
|
546
|
+
event.bytes = std::move(std::get<rtc::binary>(data));
|
|
459
547
|
}
|
|
460
548
|
self->Emit(std::move(event));
|
|
461
549
|
}
|
|
@@ -619,49 +707,40 @@ private:
|
|
|
619
707
|
|
|
620
708
|
Napi::FunctionReference NativeDataChannel::constructor;
|
|
621
709
|
|
|
622
|
-
|
|
623
|
-
std::unique_ptr<NativeEvent> scoped(event);
|
|
624
|
-
|
|
710
|
+
Napi::Object EventDispatcher::EventToObject(Napi::Env env, NativeEvent &event) {
|
|
625
711
|
Napi::Object object = Napi::Object::New(env);
|
|
626
|
-
object.Set("target",
|
|
627
|
-
object.Set("type",
|
|
628
|
-
if (
|
|
629
|
-
object.Set("channelId",
|
|
630
|
-
if (!
|
|
631
|
-
object.Set("state",
|
|
632
|
-
if (!
|
|
712
|
+
object.Set("target", event.target);
|
|
713
|
+
object.Set("type", event.type);
|
|
714
|
+
if (event.channelId)
|
|
715
|
+
object.Set("channelId", event.channelId);
|
|
716
|
+
if (!event.state.empty())
|
|
717
|
+
object.Set("state", event.state);
|
|
718
|
+
if (!event.descriptionType.empty()) {
|
|
633
719
|
Napi::Object description = Napi::Object::New(env);
|
|
634
|
-
description.Set("type",
|
|
635
|
-
description.Set("sdp",
|
|
720
|
+
description.Set("type", event.descriptionType);
|
|
721
|
+
description.Set("sdp", event.sdp);
|
|
636
722
|
object.Set("description", description);
|
|
637
723
|
}
|
|
638
|
-
if (!
|
|
724
|
+
if (!event.candidate.empty() || !event.mid.empty()) {
|
|
639
725
|
Napi::Object candidate = Napi::Object::New(env);
|
|
640
|
-
candidate.Set("candidate",
|
|
641
|
-
if (!
|
|
642
|
-
candidate.Set("sdpMid",
|
|
726
|
+
candidate.Set("candidate", event.candidate);
|
|
727
|
+
if (!event.mid.empty())
|
|
728
|
+
candidate.Set("sdpMid", event.mid);
|
|
643
729
|
object.Set("candidate", candidate);
|
|
644
730
|
}
|
|
645
|
-
if (!
|
|
646
|
-
object.Set("error",
|
|
647
|
-
if (
|
|
648
|
-
object.Set("binary",
|
|
649
|
-
|
|
650
|
-
Napi::ArrayBuffer buffer = Napi::ArrayBuffer::New(env, scoped->bytes.size());
|
|
651
|
-
if (!scoped->bytes.empty())
|
|
652
|
-
std::memcpy(buffer.Data(), scoped->bytes.data(), scoped->bytes.size());
|
|
653
|
-
object.Set("data", buffer);
|
|
654
|
-
} else {
|
|
655
|
-
object.Set("data", scoped->text);
|
|
656
|
-
}
|
|
731
|
+
if (!event.error.empty())
|
|
732
|
+
object.Set("error", event.error);
|
|
733
|
+
if (event.type == "message") {
|
|
734
|
+
object.Set("binary", event.binary);
|
|
735
|
+
object.Set("data", MessagePayloadToValue(env, event));
|
|
657
736
|
}
|
|
658
|
-
if (
|
|
659
|
-
object.Set("channel", NativeDataChannel::NewInstance(env,
|
|
660
|
-
object.Set("channelId",
|
|
737
|
+
if (event.channel) {
|
|
738
|
+
object.Set("channel", NativeDataChannel::NewInstance(env, event.channel));
|
|
739
|
+
object.Set("channelId", event.channel->id);
|
|
661
740
|
object.Set("channelReadyState", "open");
|
|
662
741
|
}
|
|
663
742
|
|
|
664
|
-
|
|
743
|
+
return object;
|
|
665
744
|
}
|
|
666
745
|
|
|
667
746
|
Napi::Object CandidateToObject(Napi::Env env, const rtc::Candidate &candidate) {
|
|
@@ -674,7 +753,9 @@ Napi::Object CandidateToObject(Napi::Env env, const rtc::Candidate &candidate) {
|
|
|
674
753
|
rtc::Configuration ParseConfiguration(const Napi::CallbackInfo &info) {
|
|
675
754
|
rtc::Configuration config;
|
|
676
755
|
config.disableAutoNegotiation = true;
|
|
677
|
-
config.disableAutoGathering =
|
|
756
|
+
config.disableAutoGathering = true;
|
|
757
|
+
// Standard Ethernet MTU avoids the conservative default without requiring an API extension.
|
|
758
|
+
config.mtu = 1500;
|
|
678
759
|
|
|
679
760
|
if (info.Length() == 0 || !info[0].IsObject())
|
|
680
761
|
return config;
|