mediasoup 3.20.7 → 3.20.9
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/README.md +8 -2
- package/node/lib/WebRtcServer.d.ts.map +1 -1
- package/node/lib/WebRtcServer.js +0 -7
- package/node/lib/WebRtcServerTypes.d.ts +0 -5
- package/node/lib/WebRtcServerTypes.d.ts.map +1 -1
- package/node/lib/fbs/web-rtc-server/dump-response.d.ts +2 -9
- package/node/lib/fbs/web-rtc-server/dump-response.d.ts.map +1 -1
- package/node/lib/fbs/web-rtc-server/dump-response.js +5 -33
- package/node/lib/fbs/web-rtc-server.d.ts +0 -1
- package/node/lib/fbs/web-rtc-server.d.ts.map +1 -1
- package/node/lib/fbs/web-rtc-server.js +1 -4
- package/node/lib/test/test-WebRtcServer.js +0 -7
- package/npm-scripts.mjs +132 -55
- package/package.json +6 -4
- package/worker/fbs/webRtcServer.fbs +0 -6
- package/worker/include/RTC/TransportTuple.hpp +70 -14
- package/worker/include/RTC/WebRtcServer.hpp +5 -2
- package/worker/include/Utils.hpp +6 -0
- package/worker/src/RTC/PortManager.cpp +16 -20
- package/worker/src/RTC/SeqManager.cpp +4 -1
- package/worker/src/RTC/SimpleProducerStreamManager.cpp +6 -3
- package/worker/src/RTC/TransportTuple.cpp +87 -50
- package/worker/src/RTC/WebRtcServer.cpp +20 -29
- package/worker/test/src/RTC/TestSeqManager.cpp +167 -62
- package/worker/test/src/RTC/TestTransportTuple.cpp +21 -14
- package/node/lib/fbs/consumer/degrade-request.d.ts +0 -30
- package/node/lib/fbs/consumer/degrade-request.d.ts.map +0 -1
- package/node/lib/fbs/consumer/degrade-request.js +0 -124
- package/node/lib/fbs/consumer/enable-delay-and-loss-request.d.ts +0 -24
- package/node/lib/fbs/consumer/enable-delay-and-loss-request.d.ts.map +0 -1
- package/node/lib/fbs/consumer/enable-delay-and-loss-request.js +0 -102
- package/node/lib/fbs/lib-uring/dump.d.ts +0 -27
- package/node/lib/fbs/lib-uring/dump.d.ts.map +0 -1
- package/node/lib/fbs/lib-uring/dump.js +0 -113
- package/node/lib/fbs/lib-uring.d.ts +0 -2
- package/node/lib/fbs/lib-uring.d.ts.map +0 -1
- package/node/lib/fbs/lib-uring.js +0 -8
- package/node/lib/fbs/producer/degrade-request.d.ts +0 -30
- package/node/lib/fbs/producer/degrade-request.d.ts.map +0 -1
- package/node/lib/fbs/producer/degrade-request.js +0 -124
- package/node/lib/fbs/sctp-parameters/num-sctp-streams.d.ts +0 -24
- package/node/lib/fbs/sctp-parameters/num-sctp-streams.d.ts.map +0 -1
- package/node/lib/fbs/sctp-parameters/num-sctp-streams.js +0 -102
- package/node/lib/fbs/transport/sctp-negotiated-max-streams-notification.d.ts +0 -24
- package/node/lib/fbs/transport/sctp-negotiated-max-streams-notification.d.ts.map +0 -1
- package/node/lib/fbs/transport/sctp-negotiated-max-streams-notification.js +0 -102
- package/node/lib/fbs/transport/sctp-negotiated-options-notification.d.ts +0 -24
- package/node/lib/fbs/transport/sctp-negotiated-options-notification.d.ts.map +0 -1
- package/node/lib/fbs/transport/sctp-negotiated-options-notification.js +0 -102
- package/node/lib/fbs/web-rtc-server/tuple-hash.d.ts +0 -25
- package/node/lib/fbs/web-rtc-server/tuple-hash.d.ts.map +0 -1
- package/node/lib/fbs/web-rtc-server/tuple-hash.js +0 -104
- package/node/lib/fbs/worker/close-notification.d.ts +0 -18
- package/node/lib/fbs/worker/close-notification.d.ts.map +0 -1
- package/node/lib/fbs/worker/close-notification.js +0 -78
- package/node/lib/fbs/worker/close-request.d.ts +0 -18
- package/node/lib/fbs/worker/close-request.d.ts.map +0 -1
- package/node/lib/fbs/worker/close-request.js +0 -78
- package/node/lib/fbs/worker/close-worker-notification.d.ts +0 -18
- package/node/lib/fbs/worker/close-worker-notification.d.ts.map +0 -1
- package/node/lib/fbs/worker/close-worker-notification.js +0 -78
package/npm-scripts.mjs
CHANGED
|
@@ -8,7 +8,9 @@ import * as tar from 'tar';
|
|
|
8
8
|
import pkg from './package.json' with { type: 'json' };
|
|
9
9
|
|
|
10
10
|
const IS_WINDOWS = os.platform() === 'win32';
|
|
11
|
-
|
|
11
|
+
// Main Git branch is 'v' concatenated with the major SEMVER number of the
|
|
12
|
+
// "version" field in package.json.
|
|
13
|
+
const MAIN_BRANCH = `v${pkg.version.split('.')[0]}`;
|
|
12
14
|
const PYTHON = getPython();
|
|
13
15
|
const PIP_INVOKE_DIR = path.resolve('worker/pip_invoke');
|
|
14
16
|
const WORKER_RELEASE_DIR = 'worker/out/Release';
|
|
@@ -17,8 +19,6 @@ const WORKER_RELEASE_BIN = IS_WINDOWS
|
|
|
17
19
|
: 'mediasoup-worker';
|
|
18
20
|
const WORKER_RELEASE_BIN_PATH = `${WORKER_RELEASE_DIR}/${WORKER_RELEASE_BIN}`;
|
|
19
21
|
const WORKER_PREBUILD_DIR = 'worker/prebuild';
|
|
20
|
-
const GH_OWNER = 'versatica';
|
|
21
|
-
const GH_REPO = 'mediasoup';
|
|
22
22
|
|
|
23
23
|
// Paths for ESLint to check.
|
|
24
24
|
const ESLINT_PATHS = [
|
|
@@ -27,6 +27,7 @@ const ESLINT_PATHS = [
|
|
|
27
27
|
'knip.config.mjs',
|
|
28
28
|
'node/src',
|
|
29
29
|
'npm-scripts.mjs',
|
|
30
|
+
'rust-scripts.mjs',
|
|
30
31
|
'worker/scripts',
|
|
31
32
|
];
|
|
32
33
|
|
|
@@ -47,6 +48,7 @@ const PRETTIER_PATHS = [
|
|
|
47
48
|
'node/src',
|
|
48
49
|
'npm-scripts.mjs',
|
|
49
50
|
'package.json',
|
|
51
|
+
'rust-scripts.mjs',
|
|
50
52
|
'tsconfig.json',
|
|
51
53
|
'worker/scripts',
|
|
52
54
|
];
|
|
@@ -137,13 +139,13 @@ async function run() {
|
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
case 'typescript:build': {
|
|
140
|
-
buildTypescript({ force: true });
|
|
142
|
+
buildTypescript({ force: true, args: taskArgs });
|
|
141
143
|
|
|
142
144
|
break;
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
case 'typescript:watch': {
|
|
146
|
-
watchTypescript();
|
|
148
|
+
watchTypescript({ args: taskArgs });
|
|
147
149
|
|
|
148
150
|
break;
|
|
149
151
|
}
|
|
@@ -215,7 +217,7 @@ async function run() {
|
|
|
215
217
|
}
|
|
216
218
|
|
|
217
219
|
case 'test:node': {
|
|
218
|
-
testNode();
|
|
220
|
+
testNode({ args: taskArgs });
|
|
219
221
|
|
|
220
222
|
break;
|
|
221
223
|
}
|
|
@@ -227,7 +229,7 @@ async function run() {
|
|
|
227
229
|
}
|
|
228
230
|
|
|
229
231
|
case 'coverage:node': {
|
|
230
|
-
coverageNode();
|
|
232
|
+
coverageNode({ args: taskArgs });
|
|
231
233
|
|
|
232
234
|
break;
|
|
233
235
|
}
|
|
@@ -245,7 +247,7 @@ async function run() {
|
|
|
245
247
|
}
|
|
246
248
|
|
|
247
249
|
case 'release': {
|
|
248
|
-
await release();
|
|
250
|
+
await release({ args: taskArgs });
|
|
249
251
|
|
|
250
252
|
break;
|
|
251
253
|
}
|
|
@@ -317,7 +319,7 @@ function deleteNodeLib() {
|
|
|
317
319
|
fs.rmSync('node/lib', { recursive: true, force: true });
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
function buildTypescript({ force }) {
|
|
322
|
+
function buildTypescript({ force, args = '' }) {
|
|
321
323
|
// Skip JavaScript code generation if the output already exists, unless forced.
|
|
322
324
|
if (!force && fs.existsSync('node/lib')) {
|
|
323
325
|
return;
|
|
@@ -327,15 +329,15 @@ function buildTypescript({ force }) {
|
|
|
327
329
|
|
|
328
330
|
deleteNodeLib();
|
|
329
331
|
|
|
330
|
-
executeCmd(`tsc ${
|
|
332
|
+
executeCmd(`tsc ${args}`);
|
|
331
333
|
}
|
|
332
334
|
|
|
333
|
-
function watchTypescript() {
|
|
335
|
+
function watchTypescript({ args = '' } = {}) {
|
|
334
336
|
logInfo('watchTypescript()');
|
|
335
337
|
|
|
336
338
|
deleteNodeLib();
|
|
337
339
|
|
|
338
|
-
executeCmd(`tsc --watch ${
|
|
340
|
+
executeCmd(`tsc --watch ${args}`);
|
|
339
341
|
}
|
|
340
342
|
|
|
341
343
|
function buildWorker() {
|
|
@@ -487,10 +489,10 @@ function flatcWorker() {
|
|
|
487
489
|
executeCmd(`"${PYTHON}" -m invoke -r worker flatc`);
|
|
488
490
|
}
|
|
489
491
|
|
|
490
|
-
function testNode() {
|
|
492
|
+
function testNode({ args = '' } = {}) {
|
|
491
493
|
logInfo('testNode()');
|
|
492
494
|
|
|
493
|
-
executeCmd(`jest --silent false --detectOpenHandles ${
|
|
495
|
+
executeCmd(`jest --silent false --detectOpenHandles ${args}`);
|
|
494
496
|
}
|
|
495
497
|
|
|
496
498
|
function testWorker() {
|
|
@@ -501,10 +503,10 @@ function testWorker() {
|
|
|
501
503
|
executeCmd(`"${PYTHON}" -m invoke -r worker test`);
|
|
502
504
|
}
|
|
503
505
|
|
|
504
|
-
function coverageNode() {
|
|
506
|
+
function coverageNode({ args = '' } = {}) {
|
|
505
507
|
logInfo('coverageNode()');
|
|
506
508
|
|
|
507
|
-
executeCmd(`jest --coverage ${
|
|
509
|
+
executeCmd(`jest --coverage ${args}`);
|
|
508
510
|
executeCmd('open-cli coverage/lcov-report/index.html');
|
|
509
511
|
}
|
|
510
512
|
|
|
@@ -542,6 +544,18 @@ function publishDryRun() {
|
|
|
542
544
|
async function checkRelease() {
|
|
543
545
|
logInfo('checkRelease()');
|
|
544
546
|
|
|
547
|
+
// Verify that CHANGELOG.md has an entry for the new version (and grab its
|
|
548
|
+
// changes, used as the GitHub release body) before the slow build steps.
|
|
549
|
+
let versionChanges;
|
|
550
|
+
|
|
551
|
+
try {
|
|
552
|
+
versionChanges = await getVersionChanges();
|
|
553
|
+
} catch (error) {
|
|
554
|
+
logError(error.message);
|
|
555
|
+
|
|
556
|
+
exitWithError();
|
|
557
|
+
}
|
|
558
|
+
|
|
545
559
|
installNodeDeps();
|
|
546
560
|
await flatcNode({ force: true });
|
|
547
561
|
buildTypescript({ force: true });
|
|
@@ -553,41 +567,55 @@ async function checkRelease() {
|
|
|
553
567
|
// Validate packaging (the `files` list in package.json) before the
|
|
554
568
|
// irreversible release steps (git push, GitHub release, npm publish).
|
|
555
569
|
publishDryRun();
|
|
570
|
+
|
|
571
|
+
return { versionChanges };
|
|
556
572
|
}
|
|
557
573
|
|
|
558
|
-
async function release() {
|
|
574
|
+
async function release({ args = '' } = {}) {
|
|
559
575
|
logInfo('release()');
|
|
560
576
|
|
|
561
|
-
|
|
562
|
-
let versionChanges;
|
|
577
|
+
const version = args.trim();
|
|
563
578
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
579
|
+
if (!/^\d+\.\d+\.\d+$/.test(version)) {
|
|
580
|
+
logError(
|
|
581
|
+
`release() | a SEMVER 'x.y.z' argument is required, but got '${version}'`
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
exitWithError();
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// Must be on the main branch.
|
|
588
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
589
|
+
encoding: 'utf-8',
|
|
590
|
+
}).trim();
|
|
591
|
+
|
|
592
|
+
if (branch !== MAIN_BRANCH) {
|
|
593
|
+
logError(
|
|
594
|
+
`release() | must be on '${MAIN_BRANCH}' branch, but it is on '${branch}' branch`
|
|
595
|
+
);
|
|
569
596
|
|
|
570
597
|
exitWithError();
|
|
571
598
|
}
|
|
572
599
|
|
|
600
|
+
// Clean working tree required before bumping the version.
|
|
601
|
+
checkGitClean();
|
|
602
|
+
|
|
603
|
+
// Lint, test, build, publish dry-run, and verify the CHANGELOG entry (of the
|
|
604
|
+
// previous version still in package.json, which is harmless).
|
|
573
605
|
await checkRelease();
|
|
574
|
-
executeCmd(`git commit -am '${pkg.version}'`);
|
|
575
|
-
executeCmd(`git tag -a ${pkg.version} -m '${pkg.version}'`);
|
|
576
|
-
executeCmd(`git push origin v${MAYOR_VERSION}`);
|
|
577
|
-
executeCmd(`git push origin '${pkg.version}'`);
|
|
578
|
-
|
|
579
|
-
logInfo('creating release in GitHub');
|
|
580
|
-
|
|
581
|
-
await octokit.repos.createRelease({
|
|
582
|
-
owner: GH_OWNER,
|
|
583
|
-
repo: GH_REPO,
|
|
584
|
-
name: pkg.version,
|
|
585
|
-
body: versionChanges,
|
|
586
|
-
tag_name: pkg.version,
|
|
587
|
-
draft: false,
|
|
588
|
-
});
|
|
589
606
|
|
|
590
|
-
|
|
607
|
+
// Bump the version in package.json + package-lock.json and in CHANGELOG.md.
|
|
608
|
+
executeCmd(`npm version ${version} --no-git-tag-version`);
|
|
609
|
+
await updateChangelog(version);
|
|
610
|
+
|
|
611
|
+
// Commit the bump, tag it, and push both. The pushed tag triggers
|
|
612
|
+
// mediasoup-npm-publish.yaml, which checks, creates the GitHub release and
|
|
613
|
+
// publishes to NPM; on its success mediasoup-worker-prebuild.yaml builds and
|
|
614
|
+
// uploads the prebuilt binaries.
|
|
615
|
+
executeCmd(`git commit -am 'version ${version}'`);
|
|
616
|
+
executeCmd(`git tag -a ${version} -m '${version}'`);
|
|
617
|
+
executeCmd(`git push origin ${MAIN_BRANCH}`);
|
|
618
|
+
executeCmd(`git push origin '${version}'`);
|
|
591
619
|
}
|
|
592
620
|
|
|
593
621
|
function ensureDir(dir) {
|
|
@@ -757,19 +785,21 @@ async function downloadPrebuiltWorker() {
|
|
|
757
785
|
});
|
|
758
786
|
}
|
|
759
787
|
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
throw new Error('missing GITHUB_TOKEN environment variable');
|
|
763
|
-
}
|
|
788
|
+
function checkGitClean() {
|
|
789
|
+
logInfo('checkGitClean()');
|
|
764
790
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
const octokit = new Octokit({
|
|
769
|
-
auth: process.env.GITHUB_TOKEN,
|
|
791
|
+
const status = execSync('git status --porcelain', {
|
|
792
|
+
encoding: 'utf-8',
|
|
793
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
770
794
|
});
|
|
771
795
|
|
|
772
|
-
|
|
796
|
+
if (status.trim()) {
|
|
797
|
+
logError(
|
|
798
|
+
'checkGitClean() | Git working tree is not clean, commit or stash your changes first'
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
exitWithError();
|
|
802
|
+
}
|
|
773
803
|
}
|
|
774
804
|
|
|
775
805
|
async function getVersionChanges() {
|
|
@@ -785,9 +815,26 @@ async function getVersionChanges() {
|
|
|
785
815
|
const entry = entries[idx];
|
|
786
816
|
|
|
787
817
|
if (entry.type === 'heading' && entry.text === pkg.version) {
|
|
788
|
-
|
|
818
|
+
// Collect every token after the matching heading until the next heading.
|
|
819
|
+
// NOTE: We cannot just use `entries[idx + 1].raw` because `marked`
|
|
820
|
+
// inserts a `space` token between the heading and its content.
|
|
821
|
+
let changes = '';
|
|
822
|
+
|
|
823
|
+
for (let next = idx + 1; next < entries.length; ++next) {
|
|
824
|
+
if (entries[next].type === 'heading') {
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
changes += entries[next].raw;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
changes = changes.trim();
|
|
789
832
|
|
|
790
|
-
|
|
833
|
+
if (changes) {
|
|
834
|
+
return changes;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
break;
|
|
791
838
|
}
|
|
792
839
|
}
|
|
793
840
|
|
|
@@ -797,6 +844,35 @@ async function getVersionChanges() {
|
|
|
797
844
|
);
|
|
798
845
|
}
|
|
799
846
|
|
|
847
|
+
async function updateChangelog(version) {
|
|
848
|
+
logInfo(`updateChangelog() [version:${version}]`);
|
|
849
|
+
|
|
850
|
+
// NOTE: Load dep on demand since it's a devDependency.
|
|
851
|
+
const marked = await import('marked');
|
|
852
|
+
|
|
853
|
+
const changelog = fs.readFileSync('./CHANGELOG.md', { encoding: 'utf-8' });
|
|
854
|
+
const tokens = marked.lexer(changelog);
|
|
855
|
+
|
|
856
|
+
// Locate the top "### NEXT" heading.
|
|
857
|
+
const nextHeading = tokens.find(
|
|
858
|
+
token =>
|
|
859
|
+
token.type === 'heading' && token.depth === 3 && token.text === 'NEXT'
|
|
860
|
+
);
|
|
861
|
+
|
|
862
|
+
if (!nextHeading) {
|
|
863
|
+
throw new Error("no '### NEXT' heading found in CHANGELOG.md");
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// Insert "### <version>" right below "### NEXT" (keeping the empty "### NEXT"
|
|
867
|
+
// for future unreleased changes), preserving the heading's trailing newlines.
|
|
868
|
+
const updatedChangelog = changelog.replace(
|
|
869
|
+
nextHeading.raw,
|
|
870
|
+
`### NEXT\n\n### ${version}${nextHeading.raw.slice('### NEXT'.length)}`
|
|
871
|
+
);
|
|
872
|
+
|
|
873
|
+
fs.writeFileSync('./CHANGELOG.md', updatedChangelog);
|
|
874
|
+
}
|
|
875
|
+
|
|
800
876
|
function executeCmd(command) {
|
|
801
877
|
logInfo(`executeCmd(): ${command}`);
|
|
802
878
|
|
|
@@ -809,11 +885,12 @@ function executeCmd(command) {
|
|
|
809
885
|
}
|
|
810
886
|
}
|
|
811
887
|
|
|
812
|
-
|
|
813
|
-
|
|
888
|
+
// eslint-disable-next-line no-unused-vars
|
|
889
|
+
function executeInteractiveCmd(command, { cwd } = {}) {
|
|
890
|
+
logInfo(`executeInteractiveCmd(): ${command}${cwd ? ` [cwd:${cwd}]` : ''}`);
|
|
814
891
|
|
|
815
892
|
try {
|
|
816
|
-
execSync(command, { stdio: 'inherit', env: process.env });
|
|
893
|
+
execSync(command, { cwd, stdio: 'inherit', env: process.env });
|
|
817
894
|
} catch (error) {
|
|
818
895
|
logError(`executeInteractiveCmd() failed, exiting: ${error}`);
|
|
819
896
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mediasoup",
|
|
3
|
-
"version": "3.20.
|
|
3
|
+
"version": "3.20.9",
|
|
4
4
|
"description": "Cutting Edge WebRTC Video Conferencing",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)",
|
|
@@ -98,7 +98,9 @@
|
|
|
98
98
|
"coverage:node": "node npm-scripts.mjs coverage:node",
|
|
99
99
|
"publish:dry-run": "node npm-scripts.mjs publish:dry-run",
|
|
100
100
|
"release:check": "node npm-scripts.mjs release:check",
|
|
101
|
-
"release": "node npm-scripts.mjs release"
|
|
101
|
+
"release": "node npm-scripts.mjs release",
|
|
102
|
+
"release:rust:check": "node rust-scripts.mjs release:check",
|
|
103
|
+
"release:rust": "node rust-scripts.mjs release"
|
|
102
104
|
},
|
|
103
105
|
"dependencies": {
|
|
104
106
|
"debug": "^4.4.3",
|
|
@@ -114,13 +116,13 @@
|
|
|
114
116
|
"@types/debug": "^4.1.13",
|
|
115
117
|
"@types/ini": "^4.1.1",
|
|
116
118
|
"@types/jest": "^30.0.0",
|
|
117
|
-
"@types/node": "^
|
|
119
|
+
"@types/node": "^26.0.0",
|
|
118
120
|
"eslint": "^10.5.0",
|
|
119
121
|
"eslint-config-prettier": "^10.1.8",
|
|
120
122
|
"eslint-plugin-jest": "^29.15.2",
|
|
121
123
|
"eslint-plugin-prettier": "^5.5.6",
|
|
122
124
|
"globals": "^17.6.0",
|
|
123
|
-
"ini": "^
|
|
125
|
+
"ini": "^7.0.0",
|
|
124
126
|
"jest": "^30.4.2",
|
|
125
127
|
"knip": "^6.17.1",
|
|
126
128
|
"marked": "^18.0.5",
|
|
@@ -12,17 +12,11 @@ table IceUserNameFragment {
|
|
|
12
12
|
web_rtc_transport_id: string (required);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
table TupleHash {
|
|
16
|
-
tuple_hash: uint64;
|
|
17
|
-
web_rtc_transport_id: string (required);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
15
|
table DumpResponse {
|
|
21
16
|
id: string (required);
|
|
22
17
|
udp_sockets: [IpPort] (required);
|
|
23
18
|
tcp_servers: [IpPort] (required);
|
|
24
19
|
web_rtc_transport_ids: [string] (required);
|
|
25
20
|
local_ice_username_fragments: [IceUserNameFragment] (required);
|
|
26
|
-
tuple_hashes: [TupleHash] (required);
|
|
27
21
|
}
|
|
28
22
|
|
|
@@ -23,28 +23,60 @@ namespace RTC
|
|
|
23
23
|
TCP = 2
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
class TupleKey
|
|
27
|
+
{
|
|
28
|
+
private:
|
|
29
|
+
friend class TransportTuple;
|
|
30
|
+
friend class TupleKeyHash;
|
|
31
|
+
|
|
32
|
+
public:
|
|
33
|
+
TupleKey() = default;
|
|
34
|
+
TupleKey(Protocol protocol, const void* udpSocketOrTcpConnection, const struct sockaddr* udpRemoteAddr)
|
|
35
|
+
: protocol(protocol),
|
|
36
|
+
udpSocketOrTcpConnection(udpSocketOrTcpConnection),
|
|
37
|
+
udpRemoteAddr(udpRemoteAddr) {};
|
|
38
|
+
|
|
39
|
+
bool operator==(const TupleKey& other) const noexcept;
|
|
40
|
+
bool operator!=(const TupleKey& other) const noexcept
|
|
41
|
+
{
|
|
42
|
+
return !(*this == other);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
private:
|
|
46
|
+
Protocol protocol{ Protocol::UDP };
|
|
47
|
+
// The local endpoint is identified by object pointer identity: the
|
|
48
|
+
// UdpSocket or the TcpConnection. For TCP the connection alone identifies
|
|
49
|
+
// the whole tuple, so `udpRemoteAddr` is unused.
|
|
50
|
+
const void* udpSocketOrTcpConnection{ nullptr };
|
|
51
|
+
const struct sockaddr* udpRemoteAddr{ nullptr };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
struct TupleKeyHash
|
|
55
|
+
{
|
|
56
|
+
size_t operator()(const TupleKey& key) const noexcept;
|
|
57
|
+
};
|
|
58
|
+
|
|
26
59
|
static Protocol ProtocolFromFbs(FBS::Transport::Protocol protocol);
|
|
27
60
|
static FBS::Transport::Protocol ProtocolToFbs(Protocol protocol);
|
|
28
|
-
static uint64_t GenerateFnv1aHash(const uint8_t* data, size_t size);
|
|
29
61
|
|
|
30
62
|
public:
|
|
31
63
|
TransportTuple(RTC::UdpSocket* udpSocket, const struct sockaddr* udpRemoteAddr)
|
|
32
64
|
: udpSocket(udpSocket),
|
|
33
65
|
udpRemoteAddr(const_cast<struct sockaddr*>(udpRemoteAddr)),
|
|
34
|
-
protocol(Protocol::UDP)
|
|
66
|
+
protocol(Protocol::UDP),
|
|
67
|
+
tupleKey(Protocol::UDP, udpSocket, udpRemoteAddr)
|
|
35
68
|
{
|
|
36
|
-
GenerateHash();
|
|
37
69
|
}
|
|
38
70
|
|
|
39
71
|
explicit TransportTuple(RTC::TcpConnection* tcpConnection)
|
|
40
|
-
: tcpConnection(tcpConnection),
|
|
72
|
+
: tcpConnection(tcpConnection),
|
|
73
|
+
protocol(Protocol::TCP),
|
|
74
|
+
tupleKey(Protocol::TCP, tcpConnection, nullptr)
|
|
41
75
|
{
|
|
42
|
-
GenerateHash();
|
|
43
76
|
}
|
|
44
77
|
|
|
45
78
|
explicit TransportTuple(const TransportTuple* tuple)
|
|
46
|
-
:
|
|
47
|
-
udpSocket(tuple->udpSocket),
|
|
79
|
+
: udpSocket(tuple->udpSocket),
|
|
48
80
|
udpRemoteAddr(tuple->udpRemoteAddr),
|
|
49
81
|
tcpConnection(tuple->tcpConnection),
|
|
50
82
|
localAnnouncedAddress(tuple->localAnnouncedAddress),
|
|
@@ -54,6 +86,10 @@ namespace RTC
|
|
|
54
86
|
{
|
|
55
87
|
StoreUdpRemoteAddress();
|
|
56
88
|
}
|
|
89
|
+
else
|
|
90
|
+
{
|
|
91
|
+
this->tupleKey = TupleKey(this->protocol, this->tcpConnection, nullptr);
|
|
92
|
+
}
|
|
57
93
|
}
|
|
58
94
|
|
|
59
95
|
public:
|
|
@@ -70,11 +106,32 @@ namespace RTC
|
|
|
70
106
|
this->udpRemoteAddrStorage = Utils::IP::CopyAddress(this->udpRemoteAddr);
|
|
71
107
|
this->udpRemoteAddr =
|
|
72
108
|
reinterpret_cast<struct sockaddr*>(std::addressof(this->udpRemoteAddrStorage));
|
|
109
|
+
this->tupleKey = TupleKey(this->protocol, this->udpSocket, this->udpRemoteAddr);
|
|
73
110
|
}
|
|
74
111
|
|
|
75
112
|
bool Compare(const TransportTuple* tuple) const
|
|
76
113
|
{
|
|
77
|
-
|
|
114
|
+
if (this->protocol != tuple->protocol)
|
|
115
|
+
{
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
switch (this->protocol)
|
|
120
|
+
{
|
|
121
|
+
case Protocol::UDP:
|
|
122
|
+
{
|
|
123
|
+
return (
|
|
124
|
+
this->udpSocket == tuple->udpSocket &&
|
|
125
|
+
Utils::IP::CompareAddresses(this->udpRemoteAddr, tuple->udpRemoteAddr));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
case Protocol::TCP:
|
|
129
|
+
{
|
|
130
|
+
return (this->tcpConnection == tuple->tcpConnection);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return true;
|
|
78
135
|
}
|
|
79
136
|
|
|
80
137
|
void SetLocalAnnouncedAddress(std::string& localAnnouncedAddress)
|
|
@@ -147,12 +204,10 @@ namespace RTC
|
|
|
147
204
|
}
|
|
148
205
|
}
|
|
149
206
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
public:
|
|
155
|
-
uint64_t hash{ 0u };
|
|
207
|
+
const TupleKey& GetTupleKey() const
|
|
208
|
+
{
|
|
209
|
+
return this->tupleKey;
|
|
210
|
+
}
|
|
156
211
|
|
|
157
212
|
private:
|
|
158
213
|
// Passed by argument.
|
|
@@ -163,6 +218,7 @@ namespace RTC
|
|
|
163
218
|
// Others.
|
|
164
219
|
struct sockaddr_storage udpRemoteAddrStorage{};
|
|
165
220
|
Protocol protocol;
|
|
221
|
+
TupleKey tupleKey;
|
|
166
222
|
};
|
|
167
223
|
} // namespace RTC
|
|
168
224
|
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include "RTC/UdpSocket.hpp"
|
|
11
11
|
#include "RTC/WebRtcTransport.hpp"
|
|
12
12
|
#include "SharedInterface.hpp"
|
|
13
|
+
#include "TransportTuple.hpp"
|
|
13
14
|
#include <flatbuffers/flatbuffers.h>
|
|
14
15
|
#include <ankerl/unordered_dense.h>
|
|
15
16
|
#include <string>
|
|
@@ -118,8 +119,10 @@ namespace RTC
|
|
|
118
119
|
ankerl::unordered_dense::set<RTC::WebRtcTransport*> webRtcTransports;
|
|
119
120
|
// Map of WebRtcTransports indexed by local ICE usernameFragment.
|
|
120
121
|
ankerl::unordered_dense::map<std::string, RTC::WebRtcTransport*> mapLocalIceUsernameFragmentWebRtcTransport;
|
|
121
|
-
// Map of WebRtcTransports indexed by TransportTuple.
|
|
122
|
-
ankerl::unordered_dense::
|
|
122
|
+
// Map of WebRtcTransports indexed by TransportTuple::TupleKey.
|
|
123
|
+
ankerl::unordered_dense::
|
|
124
|
+
map<RTC::TransportTuple::TupleKey, RTC::WebRtcTransport*, RTC::TransportTuple::TupleKeyHash>
|
|
125
|
+
mapTupleWebRtcTransport;
|
|
123
126
|
// Whether the destructor has been called.
|
|
124
127
|
bool closing{ false };
|
|
125
128
|
};
|
package/worker/include/Utils.hpp
CHANGED
|
@@ -264,6 +264,12 @@ namespace Utils
|
|
|
264
264
|
|
|
265
265
|
static void WriteRandomBytes(uint8_t* buffer, size_t len);
|
|
266
266
|
|
|
267
|
+
static void HashCombine(size_t& seed, size_t value)
|
|
268
|
+
{
|
|
269
|
+
// The implementation is the same as boost::hash_combine().
|
|
270
|
+
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
271
|
+
};
|
|
272
|
+
|
|
267
273
|
private:
|
|
268
274
|
static thread_local std::mt19937_64 rng;
|
|
269
275
|
static thread_local EVP_MAC* mac;
|
|
@@ -797,11 +797,6 @@ namespace RTC
|
|
|
797
797
|
const auto protocolBits = static_cast<uint8_t>(key.protocol);
|
|
798
798
|
const auto familyBits = static_cast<uint16_t>(key.bindAddr.ss_family);
|
|
799
799
|
|
|
800
|
-
auto hashCombine = [](size_t& seed, size_t value)
|
|
801
|
-
{
|
|
802
|
-
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
803
|
-
};
|
|
804
|
-
|
|
805
800
|
size_t seed = 0;
|
|
806
801
|
|
|
807
802
|
switch (key.bindAddr.ss_family)
|
|
@@ -810,11 +805,12 @@ namespace RTC
|
|
|
810
805
|
{
|
|
811
806
|
const auto* in = reinterpret_cast<const sockaddr_in*>(std::addressof(key.bindAddr));
|
|
812
807
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
808
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint8_t>{}(protocolBits));
|
|
809
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(familyBits));
|
|
810
|
+
Utils::Crypto::HashCombine(
|
|
811
|
+
seed, ankerl::unordered_dense::hash<uint32_t>{}(in->sin_addr.s_addr));
|
|
812
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.minPort));
|
|
813
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.maxPort));
|
|
818
814
|
|
|
819
815
|
break;
|
|
820
816
|
}
|
|
@@ -830,22 +826,22 @@ namespace RTC
|
|
|
830
826
|
std::memcpy(std::addressof(hi), addr, sizeof(uint64_t));
|
|
831
827
|
std::memcpy(std::addressof(lo), addr + sizeof(uint64_t), sizeof(uint64_t));
|
|
832
828
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
829
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint8_t>{}(protocolBits));
|
|
830
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(familyBits));
|
|
831
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint64_t>{}(hi));
|
|
832
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint64_t>{}(lo));
|
|
833
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.minPort));
|
|
834
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.maxPort));
|
|
839
835
|
|
|
840
836
|
break;
|
|
841
837
|
}
|
|
842
838
|
|
|
843
839
|
default:
|
|
844
840
|
{
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
841
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint8_t>{}(protocolBits));
|
|
842
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(familyBits));
|
|
843
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.minPort));
|
|
844
|
+
Utils::Crypto::HashCombine(seed, ankerl::unordered_dense::hash<uint16_t>{}(key.maxPort));
|
|
849
845
|
|
|
850
846
|
break;
|
|
851
847
|
}
|
|
@@ -187,7 +187,10 @@ namespace RTC
|
|
|
187
187
|
template<typename T, uint8_t N>
|
|
188
188
|
T SeqManager<T, N>::GetMaxOutput() const
|
|
189
189
|
{
|
|
190
|
-
|
|
190
|
+
// 'maxOutput' is stored in the offset-less space (as 'base' and comparisons
|
|
191
|
+
// use it), so apply 'initialOutput' here, just like `Input()` does before
|
|
192
|
+
// returning the output to the caller.
|
|
193
|
+
return (this->maxOutput + this->initialOutput) & SeqManager::MaxValue;
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
/*
|
|
@@ -97,7 +97,6 @@ namespace RTC
|
|
|
97
97
|
|
|
98
98
|
MS_ASSERT(this->externallyManagedBitrate, "bitrate is not externally managed");
|
|
99
99
|
MS_ASSERT(this->kind == RTC::Media::Kind::VIDEO, "should be video");
|
|
100
|
-
MS_ASSERT(IsActive(), "should be active");
|
|
101
100
|
|
|
102
101
|
// If this is not the first time this method is called within the same
|
|
103
102
|
// iteration, return 0 since a video Simple consumer does not keep state
|
|
@@ -109,7 +108,12 @@ namespace RTC
|
|
|
109
108
|
|
|
110
109
|
this->managingBitrate = true;
|
|
111
110
|
|
|
112
|
-
if
|
|
111
|
+
// Do nothing if the producer stream is not active. NOTE: This may happen
|
|
112
|
+
// because Consumer::GetBitratePriority() does not account for the producer
|
|
113
|
+
// stream presence/score, so the Transport may still ask us to increase.
|
|
114
|
+
if (
|
|
115
|
+
!this->producerRtpStream || (this->producerRtpStream->GetScore() == 0u &&
|
|
116
|
+
this->producerRtpStream->HasRtpInactivityCheckEnabled()))
|
|
113
117
|
{
|
|
114
118
|
return 0u;
|
|
115
119
|
}
|
|
@@ -134,7 +138,6 @@ namespace RTC
|
|
|
134
138
|
|
|
135
139
|
MS_ASSERT(this->externallyManagedBitrate, "bitrate is not externally managed");
|
|
136
140
|
MS_ASSERT(this->kind == RTC::Media::Kind::VIDEO, "should be video");
|
|
137
|
-
MS_ASSERT(IsActive(), "should be active");
|
|
138
141
|
|
|
139
142
|
this->managingBitrate = false;
|
|
140
143
|
|