@wetspace/wetrtc 3.0.1 → 4.0.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.
Files changed (139) hide show
  1. package/README.md +156 -27
  2. package/dist/es/__test__/codec-preference.test.js +36 -0
  3. package/dist/es/__test__/codec-preference.test.js.map +1 -0
  4. package/dist/es/__test__/data-manager.test.js +60 -0
  5. package/dist/es/__test__/data-manager.test.js.map +1 -0
  6. package/dist/es/__test__/fsm.test.js +33 -0
  7. package/dist/es/__test__/fsm.test.js.map +1 -0
  8. package/dist/es/__test__/media-manager.test.js +41 -0
  9. package/dist/es/__test__/media-manager.test.js.map +1 -0
  10. package/dist/es/__test__/signal-manager.test.js +100 -0
  11. package/dist/es/__test__/signal-manager.test.js.map +1 -0
  12. package/dist/es/__test__/wetrtc-lifecycle.test.js +152 -0
  13. package/dist/es/__test__/wetrtc-lifecycle.test.js.map +1 -0
  14. package/dist/es/data/data-manager.d.ts +37 -0
  15. package/dist/es/data/data-manager.d.ts.map +1 -0
  16. package/dist/es/data/data-manager.js +282 -0
  17. package/dist/es/data/data-manager.js.map +1 -0
  18. package/dist/es/data/types.d.ts +34 -0
  19. package/dist/es/data/types.d.ts.map +1 -0
  20. package/dist/es/data/types.js +0 -0
  21. package/dist/es/disposable.d.ts +12 -0
  22. package/dist/es/disposable.d.ts.map +1 -0
  23. package/dist/es/disposable.js +36 -0
  24. package/dist/es/disposable.js.map +1 -0
  25. package/dist/es/fsm.d.ts +26 -0
  26. package/dist/es/fsm.d.ts.map +1 -0
  27. package/dist/es/fsm.js +63 -0
  28. package/dist/es/fsm.js.map +1 -0
  29. package/dist/es/index.d.ts +22 -0
  30. package/dist/es/index.d.ts.map +1 -0
  31. package/dist/es/index.js +48 -0
  32. package/dist/es/index.js.map +1 -0
  33. package/dist/es/media/audio-encoding.d.ts +10 -0
  34. package/dist/es/media/audio-encoding.d.ts.map +1 -0
  35. package/dist/es/media/audio-encoding.js +41 -0
  36. package/dist/es/media/audio-encoding.js.map +1 -0
  37. package/dist/es/media/codec-preference.d.ts +11 -0
  38. package/dist/es/media/codec-preference.d.ts.map +1 -0
  39. package/dist/es/media/codec-preference.js +77 -0
  40. package/dist/es/media/codec-preference.js.map +1 -0
  41. package/dist/es/media/encoding-utils.d.ts +2 -0
  42. package/dist/es/media/encoding-utils.d.ts.map +1 -0
  43. package/dist/es/media/encoding-utils.js +8 -0
  44. package/dist/es/media/encoding-utils.js.map +1 -0
  45. package/dist/es/media/media-manager.d.ts +39 -0
  46. package/dist/es/media/media-manager.d.ts.map +1 -0
  47. package/dist/es/media/media-manager.js +121 -0
  48. package/dist/es/media/media-manager.js.map +1 -0
  49. package/dist/es/media/types.d.ts +25 -0
  50. package/dist/es/media/types.d.ts.map +1 -0
  51. package/dist/es/media/types.js +0 -0
  52. package/dist/es/media/video-encoding.d.ts +12 -0
  53. package/dist/es/media/video-encoding.d.ts.map +1 -0
  54. package/dist/es/media/video-encoding.js +60 -0
  55. package/dist/es/media/video-encoding.js.map +1 -0
  56. package/dist/es/signal/signal-manager.d.ts +45 -0
  57. package/dist/es/signal/signal-manager.d.ts.map +1 -0
  58. package/dist/es/signal/signal-manager.js +250 -0
  59. package/dist/es/signal/signal-manager.js.map +1 -0
  60. package/dist/es/signal/types.d.ts +26 -0
  61. package/dist/es/signal/types.d.ts.map +1 -0
  62. package/dist/es/signal/types.js +8 -0
  63. package/dist/es/signal/types.js.map +1 -0
  64. package/dist/es/stats/stats-monitor.d.ts +32 -0
  65. package/dist/es/stats/stats-monitor.d.ts.map +1 -0
  66. package/dist/es/stats/stats-monitor.js +191 -0
  67. package/dist/es/stats/stats-monitor.js.map +1 -0
  68. package/dist/es/stats/types.d.ts +33 -0
  69. package/dist/es/stats/types.d.ts.map +1 -0
  70. package/dist/es/stats/types.js +0 -0
  71. package/dist/es/utils/types.d.ts +46 -0
  72. package/dist/es/utils/types.d.ts.map +1 -0
  73. package/dist/es/utils/types.js +80 -0
  74. package/dist/es/utils/types.js.map +1 -0
  75. package/dist/es/wetrtc.d.ts +92 -0
  76. package/dist/es/wetrtc.d.ts.map +1 -0
  77. package/dist/es/wetrtc.js +403 -0
  78. package/dist/es/wetrtc.js.map +1 -0
  79. package/dist/lib/__test__/codec-preference.test.js +34 -0
  80. package/dist/lib/__test__/codec-preference.test.js.map +1 -0
  81. package/dist/lib/__test__/data-manager.test.js +61 -0
  82. package/dist/lib/__test__/data-manager.test.js.map +1 -0
  83. package/dist/lib/__test__/fsm.test.js +34 -0
  84. package/dist/lib/__test__/fsm.test.js.map +1 -0
  85. package/dist/lib/__test__/media-manager.test.js +42 -0
  86. package/dist/lib/__test__/media-manager.test.js.map +1 -0
  87. package/dist/lib/__test__/signal-manager.test.js +101 -0
  88. package/dist/lib/__test__/signal-manager.test.js.map +1 -0
  89. package/dist/lib/__test__/wetrtc-lifecycle.test.js +153 -0
  90. package/dist/lib/__test__/wetrtc-lifecycle.test.js.map +1 -0
  91. package/dist/lib/data/data-manager.js +306 -0
  92. package/dist/lib/data/data-manager.js.map +1 -0
  93. package/dist/lib/data/types.js +18 -0
  94. package/dist/lib/data/types.js.map +1 -0
  95. package/dist/lib/disposable.js +60 -0
  96. package/dist/lib/disposable.js.map +1 -0
  97. package/dist/lib/fsm.js +87 -0
  98. package/dist/lib/fsm.js.map +1 -0
  99. package/dist/lib/index.js +75 -0
  100. package/dist/lib/index.js.map +1 -0
  101. package/dist/lib/media/audio-encoding.js +66 -0
  102. package/dist/lib/media/audio-encoding.js.map +1 -0
  103. package/dist/lib/media/codec-preference.js +106 -0
  104. package/dist/lib/media/codec-preference.js.map +1 -0
  105. package/dist/lib/media/encoding-utils.js +32 -0
  106. package/dist/lib/media/encoding-utils.js.map +1 -0
  107. package/dist/lib/media/media-manager.js +145 -0
  108. package/dist/lib/media/media-manager.js.map +1 -0
  109. package/dist/lib/media/types.js +18 -0
  110. package/dist/lib/media/types.js.map +1 -0
  111. package/dist/lib/media/video-encoding.js +87 -0
  112. package/dist/lib/media/video-encoding.js.map +1 -0
  113. package/dist/lib/signal/signal-manager.js +274 -0
  114. package/dist/lib/signal/signal-manager.js.map +1 -0
  115. package/dist/lib/signal/types.js +32 -0
  116. package/dist/lib/signal/types.js.map +1 -0
  117. package/dist/lib/stats/stats-monitor.js +215 -0
  118. package/dist/lib/stats/stats-monitor.js.map +1 -0
  119. package/dist/lib/stats/types.js +18 -0
  120. package/dist/lib/stats/types.js.map +1 -0
  121. package/dist/lib/utils/types.js +108 -0
  122. package/dist/lib/utils/types.js.map +1 -0
  123. package/dist/lib/wetrtc.js +415 -0
  124. package/dist/lib/wetrtc.js.map +1 -0
  125. package/package.json +38 -43
  126. package/es/core/constant.d.ts +0 -6
  127. package/es/core/hook.d.ts +0 -31
  128. package/es/core/index.d.ts +0 -39
  129. package/es/index.d.ts +0 -6
  130. package/es/index.js +0 -1
  131. package/es/libs/index.d.ts +0 -41
  132. package/es/libs/record.d.ts +0 -8
  133. package/lib/core/constant.d.ts +0 -6
  134. package/lib/core/hook.d.ts +0 -31
  135. package/lib/core/index.d.ts +0 -39
  136. package/lib/index.d.ts +0 -6
  137. package/lib/index.js +0 -1
  138. package/lib/libs/index.d.ts +0 -41
  139. package/lib/libs/record.d.ts +0 -8
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var audio_encoding_exports = {};
20
+ __export(audio_encoding_exports, {
21
+ applyAudioEncodingToConnection: () => applyAudioEncodingToConnection,
22
+ applyAudioSenderEncoding: () => applyAudioSenderEncoding
23
+ });
24
+ module.exports = __toCommonJS(audio_encoding_exports);
25
+ var import_encoding_utils = require("./encoding-utils");
26
+ async function applyAudioSenderEncoding(sender, options) {
27
+ const track = sender.track;
28
+ if (!track || track.kind !== "audio")
29
+ return false;
30
+ const params = sender.getParameters();
31
+ if (!params.encodings?.length) {
32
+ params.encodings = [{}];
33
+ }
34
+ const encoding = params.encodings[0];
35
+ if (options.maxBitrate != null) {
36
+ encoding.maxBitrate = options.maxBitrate;
37
+ }
38
+ if (options.priority != null) {
39
+ encoding.priority = options.priority;
40
+ }
41
+ if (options.networkPriority != null) {
42
+ encoding.networkPriority = options.networkPriority;
43
+ }
44
+ try {
45
+ await sender.setParameters(params);
46
+ return true;
47
+ } catch (err) {
48
+ if ((0, import_encoding_utils.isExpectedSetParametersError)(err)) {
49
+ return false;
50
+ }
51
+ throw err;
52
+ }
53
+ }
54
+ async function applyAudioEncodingToConnection(pc, options) {
55
+ const results = await Promise.all(
56
+ pc.getSenders().filter((sender) => sender.track?.kind === "audio").map((sender) => applyAudioSenderEncoding(sender, options))
57
+ );
58
+ return results.some(Boolean);
59
+ }
60
+ // Annotate the CommonJS export names for ESM import in node:
61
+ 0 && (module.exports = {
62
+ applyAudioEncodingToConnection,
63
+ applyAudioSenderEncoding
64
+ });
65
+
66
+ //# sourceMappingURL=audio-encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAA6C;AAU7C,eAAsB,yBACpB,QACA,SACkB;AAClB,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,SAAS,MAAM,SAAS;AAAS,WAAO;AAE7C,QAAM,SAAS,OAAO,cAAc;AACpC,MAAI,CAAC,OAAO,WAAW,QAAQ;AAC7B,WAAO,YAAY,CAAC,CAAC,CAAC;AAAA,EACxB;AAEA,QAAM,WAAW,OAAO,UAAU,CAAC;AACnC,MAAI,QAAQ,cAAc,MAAM;AAC9B,aAAS,aAAa,QAAQ;AAAA,EAChC;AACA,MAAI,QAAQ,YAAY,MAAM;AAC5B,aAAS,WAAW,QAAQ;AAAA,EAC9B;AACA,MAAI,QAAQ,mBAAmB,MAAM;AACnC,aAAS,kBAAkB,QAAQ;AAAA,EACrC;AAEA,MAAI;AACF,UAAM,OAAO,cAAc,MAAM;AACjC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAI,oDAA6B,GAAG,GAAG;AACrC,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,+BACpB,IACA,SACkB;AAClB,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,GACG,WAAW,EACX,OAAO,CAAC,WAAW,OAAO,OAAO,SAAS,OAAO,EACjD,IAAI,CAAC,WAAW,yBAAyB,QAAQ,OAAO,CAAC;AAAA,EAC9D;AACA,SAAO,QAAQ,KAAK,OAAO;AAC7B","names":[],"ignoreList":[],"sources":["../../../src/media/audio-encoding.ts"],"sourcesContent":["import { isExpectedSetParametersError } from './encoding-utils';\r\n\r\nexport interface AudioEncodingOptions {\r\n /** 最大码率 (bps),语音常用 32_000–64_000,音乐/系统声可更高 */\r\n maxBitrate?: number;\r\n priority?: RTCPriorityType;\r\n networkPriority?: RTCPriorityType;\r\n}\r\n\r\n/** @returns 是否成功调用 setParameters(协商完成前失败属正常,可在 connected 后重试) */\r\nexport async function applyAudioSenderEncoding(\r\n sender: RTCRtpSender,\r\n options: AudioEncodingOptions,\r\n): Promise<boolean> {\r\n const track = sender.track;\r\n if (!track || track.kind !== 'audio') return false;\r\n\r\n const params = sender.getParameters();\r\n if (!params.encodings?.length) {\r\n params.encodings = [{}];\r\n }\r\n\r\n const encoding = params.encodings[0];\r\n if (options.maxBitrate != null) {\r\n encoding.maxBitrate = options.maxBitrate;\r\n }\r\n if (options.priority != null) {\r\n encoding.priority = options.priority;\r\n }\r\n if (options.networkPriority != null) {\r\n encoding.networkPriority = options.networkPriority;\r\n }\r\n\r\n try {\r\n await sender.setParameters(params);\r\n return true;\r\n } catch (err) {\r\n if (isExpectedSetParametersError(err)) {\r\n return false;\r\n }\r\n throw err;\r\n }\r\n}\r\n\r\nexport async function applyAudioEncodingToConnection(\r\n pc: RTCPeerConnection,\r\n options: AudioEncodingOptions,\r\n): Promise<boolean> {\r\n const results = await Promise.all(\r\n pc\r\n .getSenders()\r\n .filter((sender) => sender.track?.kind === 'audio')\r\n .map((sender) => applyAudioSenderEncoding(sender, options)),\r\n );\r\n return results.some(Boolean);\r\n}\r\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IiIsIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W119"]}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var codec_preference_exports = {};
20
+ __export(codec_preference_exports, {
21
+ applyH264CodecPreference: () => applyH264CodecPreference,
22
+ applyH264CodecPreferences: () => applyH264CodecPreferences,
23
+ applyOpusCodecPreference: () => applyOpusCodecPreference,
24
+ applyOpusCodecPreferences: () => applyOpusCodecPreferences,
25
+ sortAudioCodecsOpusFirst: () => sortAudioCodecsOpusFirst,
26
+ sortVideoCodecsH264First: () => sortVideoCodecsH264First
27
+ });
28
+ module.exports = __toCommonJS(codec_preference_exports);
29
+ function sortVideoCodecsH264First(codecs) {
30
+ const h264 = [];
31
+ const rest = [];
32
+ for (const codec of codecs) {
33
+ if (codec.mimeType.toLowerCase() === "video/h264") {
34
+ h264.push(codec);
35
+ } else {
36
+ rest.push(codec);
37
+ }
38
+ }
39
+ h264.sort((a, b) => {
40
+ const aPkt = a.sdpFmtpLine?.includes("packetization-mode=1") ? 0 : 1;
41
+ const bPkt = b.sdpFmtpLine?.includes("packetization-mode=1") ? 0 : 1;
42
+ return aPkt - bPkt;
43
+ });
44
+ return [...h264, ...rest];
45
+ }
46
+ function applyH264CodecPreference(transceiver) {
47
+ const caps = RTCRtpReceiver.getCapabilities("video");
48
+ if (!caps?.codecs?.length)
49
+ return false;
50
+ try {
51
+ transceiver.setCodecPreferences(sortVideoCodecsH264First(caps.codecs));
52
+ return true;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+ function applyH264CodecPreferences(pc) {
58
+ for (const transceiver of pc.getTransceivers()) {
59
+ const kind = transceiver.sender.track?.kind ?? transceiver.receiver.track?.kind;
60
+ if (kind === "video") {
61
+ applyH264CodecPreference(transceiver);
62
+ }
63
+ }
64
+ }
65
+ function sortAudioCodecsOpusFirst(codecs) {
66
+ const opus = [];
67
+ const rest = [];
68
+ for (const codec of codecs) {
69
+ if (codec.mimeType.toLowerCase() === "audio/opus") {
70
+ opus.push(codec);
71
+ } else {
72
+ rest.push(codec);
73
+ }
74
+ }
75
+ return [...opus, ...rest];
76
+ }
77
+ function applyOpusCodecPreference(transceiver) {
78
+ const caps = RTCRtpReceiver.getCapabilities("audio");
79
+ if (!caps?.codecs?.length)
80
+ return false;
81
+ try {
82
+ transceiver.setCodecPreferences(sortAudioCodecsOpusFirst(caps.codecs));
83
+ return true;
84
+ } catch {
85
+ return false;
86
+ }
87
+ }
88
+ function applyOpusCodecPreferences(pc) {
89
+ for (const transceiver of pc.getTransceivers()) {
90
+ const kind = transceiver.sender.track?.kind ?? transceiver.receiver.track?.kind;
91
+ if (kind === "audio") {
92
+ applyOpusCodecPreference(transceiver);
93
+ }
94
+ }
95
+ }
96
+ // Annotate the CommonJS export names for ESM import in node:
97
+ 0 && (module.exports = {
98
+ applyH264CodecPreference,
99
+ applyH264CodecPreferences,
100
+ applyOpusCodecPreference,
101
+ applyOpusCodecPreferences,
102
+ sortAudioCodecsOpusFirst,
103
+ sortVideoCodecsH264First
104
+ });
105
+
106
+ //# sourceMappingURL=codec-preference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,SAAS,yBAAyB,QAA0C;AACjF,QAAM,OAAwB,CAAC;AAC/B,QAAM,OAAwB,CAAC;AAE/B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,YAAY,MAAM,cAAc;AACjD,WAAK,KAAK,KAAK;AAAA,IACjB,OAAO;AACL,WAAK,KAAK,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,OAAK,KAAK,CAAC,GAAG,MAAM;AAClB,UAAM,OAAO,EAAE,aAAa,SAAS,sBAAsB,IAAI,IAAI;AACnE,UAAM,OAAO,EAAE,aAAa,SAAS,sBAAsB,IAAI,IAAI;AACnE,WAAO,OAAO;AAAA,EAChB,CAAC;AAED,SAAO,CAAC,GAAG,MAAM,GAAG,IAAI;AAC1B;AAEO,SAAS,yBAAyB,aAAyC;AAChF,QAAM,OAAO,eAAe,gBAAgB,OAAO;AACnD,MAAI,CAAC,MAAM,QAAQ;AAAQ,WAAO;AAElC,MAAI;AACF,gBAAY,oBAAoB,yBAAyB,KAAK,MAAM,CAAC;AACrE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,0BAA0B,IAA6B;AACrE,aAAW,eAAe,GAAG,gBAAgB,GAAG;AAC9C,UAAM,OACJ,YAAY,OAAO,OAAO,QAAQ,YAAY,SAAS,OAAO;AAChE,QAAI,SAAS,SAAS;AACpB,+BAAyB,WAAW;AAAA,IACtC;AAAA,EACF;AACF;AAEO,SAAS,yBAAyB,QAA0C;AACjF,QAAM,OAAwB,CAAC;AAC/B,QAAM,OAAwB,CAAC;AAE/B,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,SAAS,YAAY,MAAM,cAAc;AACjD,WAAK,KAAK,KAAK;AAAA,IACjB,OAAO;AACL,WAAK,KAAK,KAAK;AAAA,IACjB;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,MAAM,GAAG,IAAI;AAC1B;AAEO,SAAS,yBAAyB,aAAyC;AAChF,QAAM,OAAO,eAAe,gBAAgB,OAAO;AACnD,MAAI,CAAC,MAAM,QAAQ;AAAQ,WAAO;AAElC,MAAI;AACF,gBAAY,oBAAoB,yBAAyB,KAAK,MAAM,CAAC;AACrE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,0BAA0B,IAA6B;AACrE,aAAW,eAAe,GAAG,gBAAgB,GAAG;AAC9C,UAAM,OACJ,YAAY,OAAO,OAAO,QAAQ,YAAY,SAAS,OAAO;AAChE,QAAI,SAAS,SAAS;AACpB,+BAAyB,WAAW;AAAA,IACtC;AAAA,EACF;AACF","names":[],"ignoreList":[],"sources":["../../../src/media/codec-preference.ts"],"sourcesContent":["export type PreferredVideoCodec = 'auto' | 'h264';\r\nexport type PreferredAudioCodec = 'auto' | 'opus';\r\n\r\nexport type VideoRtpCodec = NonNullable<\r\n ReturnType<typeof RTCRtpReceiver.getCapabilities>\r\n>['codecs'][number];\r\n\r\nexport type AudioRtpCodec = NonNullable<\r\n ReturnType<typeof RTCRtpReceiver.getCapabilities>\r\n>['codecs'][number];\r\n\r\nexport function sortVideoCodecsH264First(codecs: VideoRtpCodec[]): VideoRtpCodec[] {\r\n const h264: VideoRtpCodec[] = [];\r\n const rest: VideoRtpCodec[] = [];\r\n\r\n for (const codec of codecs) {\r\n if (codec.mimeType.toLowerCase() === 'video/h264') {\r\n h264.push(codec);\r\n } else {\r\n rest.push(codec);\r\n }\r\n }\r\n\r\n h264.sort((a, b) => {\r\n const aPkt = a.sdpFmtpLine?.includes('packetization-mode=1') ? 0 : 1;\r\n const bPkt = b.sdpFmtpLine?.includes('packetization-mode=1') ? 0 : 1;\r\n return aPkt - bPkt;\r\n });\r\n\r\n return [...h264, ...rest];\r\n}\r\n\r\nexport function applyH264CodecPreference(transceiver: RTCRtpTransceiver): boolean {\r\n const caps = RTCRtpReceiver.getCapabilities('video');\r\n if (!caps?.codecs?.length) return false;\r\n\r\n try {\r\n transceiver.setCodecPreferences(sortVideoCodecsH264First(caps.codecs));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function applyH264CodecPreferences(pc: RTCPeerConnection): void {\r\n for (const transceiver of pc.getTransceivers()) {\r\n const kind =\r\n transceiver.sender.track?.kind ?? transceiver.receiver.track?.kind;\r\n if (kind === 'video') {\r\n applyH264CodecPreference(transceiver);\r\n }\r\n }\r\n}\r\n\r\nexport function sortAudioCodecsOpusFirst(codecs: AudioRtpCodec[]): AudioRtpCodec[] {\r\n const opus: AudioRtpCodec[] = [];\r\n const rest: AudioRtpCodec[] = [];\r\n\r\n for (const codec of codecs) {\r\n if (codec.mimeType.toLowerCase() === 'audio/opus') {\r\n opus.push(codec);\r\n } else {\r\n rest.push(codec);\r\n }\r\n }\r\n\r\n return [...opus, ...rest];\r\n}\r\n\r\nexport function applyOpusCodecPreference(transceiver: RTCRtpTransceiver): boolean {\r\n const caps = RTCRtpReceiver.getCapabilities('audio');\r\n if (!caps?.codecs?.length) return false;\r\n\r\n try {\r\n transceiver.setCodecPreferences(sortAudioCodecsOpusFirst(caps.codecs));\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function applyOpusCodecPreferences(pc: RTCPeerConnection): void {\r\n for (const transceiver of pc.getTransceivers()) {\r\n const kind =\r\n transceiver.sender.track?.kind ?? transceiver.receiver.track?.kind;\r\n if (kind === 'audio') {\r\n applyOpusCodecPreference(transceiver);\r\n }\r\n }\r\n}\r\n"]}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var encoding_utils_exports = {};
20
+ __export(encoding_utils_exports, {
21
+ isExpectedSetParametersError: () => isExpectedSetParametersError
22
+ });
23
+ module.exports = __toCommonJS(encoding_utils_exports);
24
+ function isExpectedSetParametersError(err) {
25
+ return err instanceof DOMException && (err.name === "InvalidModificationError" || err.name === "InvalidStateError");
26
+ }
27
+ // Annotate the CommonJS export names for ESM import in node:
28
+ 0 && (module.exports = {
29
+ isExpectedSetParametersError
30
+ });
31
+
32
+ //# sourceMappingURL=encoding-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,6BAA6B,KAAuB;AAClE,SACE,eAAe,iBACd,IAAI,SAAS,8BAA8B,IAAI,SAAS;AAE7D","names":[],"ignoreList":[],"sources":["../../../src/media/encoding-utils.ts"],"sourcesContent":["export function isExpectedSetParametersError(err: unknown): boolean {\r\n return (\r\n err instanceof DOMException &&\r\n (err.name === 'InvalidModificationError' || err.name === 'InvalidStateError')\r\n );\r\n}\r\n"]}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var media_manager_exports = {};
20
+ __export(media_manager_exports, {
21
+ MediaManager: () => MediaManager
22
+ });
23
+ module.exports = __toCommonJS(media_manager_exports);
24
+ var import_types = require("../utils/types");
25
+ class MediaManager {
26
+ constructor() {
27
+ this.localStream = null;
28
+ this.remoteStreams = /* @__PURE__ */ new Map();
29
+ this.tracks = /* @__PURE__ */ new Map();
30
+ this.logger = (0, import_types.createLogger)();
31
+ }
32
+ // ── 实例方法(委托 static,与文档 rtc.media.* 一致) ──
33
+ enumerateDevices(kind) {
34
+ return MediaManager.enumerateDevices(kind);
35
+ }
36
+ getUserMedia(constraints) {
37
+ return MediaManager.getUserMedia(constraints);
38
+ }
39
+ getDisplayMedia(options) {
40
+ return MediaManager.getDisplayMedia(options);
41
+ }
42
+ // ── 静态工具 ──
43
+ /** 枚举设备 */
44
+ static async enumerateDevices(kind) {
45
+ const devices = await navigator.mediaDevices.enumerateDevices();
46
+ let filtered = devices;
47
+ if (kind) {
48
+ filtered = devices.filter((d) => d.kind === kind);
49
+ }
50
+ return filtered.map((d) => ({
51
+ deviceId: d.deviceId,
52
+ groupId: d.groupId,
53
+ kind: d.kind,
54
+ label: d.label || `Unknown ${d.kind}`
55
+ }));
56
+ }
57
+ /** 获取用户媒体(摄像头/麦克风) */
58
+ static async getUserMedia(constraints) {
59
+ return navigator.mediaDevices.getUserMedia(constraints);
60
+ }
61
+ /** 获取屏幕流(支持 Electron desktopCapturer sourceId) */
62
+ static async getDisplayMedia(options) {
63
+ const baseConstraints = {
64
+ video: true,
65
+ audio: options?.audio ?? false
66
+ };
67
+ if (options?.sourceId) {
68
+ baseConstraints.video = {
69
+ // @ts-expect-error Electron desktopCapturer constraints
70
+ mandatory: {
71
+ chromeMediaSource: "desktop",
72
+ chromeMediaSourceId: options.sourceId
73
+ }
74
+ };
75
+ } else if (options?.width || options?.height || options?.frameRate) {
76
+ const video = {};
77
+ if (options.width)
78
+ video.width = options.width;
79
+ if (options.height)
80
+ video.height = options.height;
81
+ if (options.frameRate)
82
+ video.frameRate = options.frameRate;
83
+ baseConstraints.video = video;
84
+ }
85
+ if (navigator.mediaDevices.getDisplayMedia) {
86
+ return navigator.mediaDevices.getDisplayMedia(baseConstraints);
87
+ }
88
+ return navigator.mediaDevices.getUserMedia(baseConstraints);
89
+ }
90
+ // ── 本地流管理 ──
91
+ setLocalStream(stream) {
92
+ this.localStream = stream;
93
+ for (const track of stream.getTracks()) {
94
+ this.tracks.set(track.id, track);
95
+ }
96
+ }
97
+ getLocalStream() {
98
+ return this.localStream;
99
+ }
100
+ addTrack(track, stream) {
101
+ stream.addTrack(track);
102
+ this.localStream = stream;
103
+ this.tracks.set(track.id, track);
104
+ }
105
+ removeTrack(track) {
106
+ track.stop();
107
+ this.tracks.delete(track.id);
108
+ this.localStream?.removeTrack(track);
109
+ }
110
+ replaceTrack(oldTrack, newTrack) {
111
+ oldTrack.stop();
112
+ this.tracks.delete(oldTrack.id);
113
+ this.tracks.set(newTrack.id, newTrack);
114
+ this.localStream?.removeTrack(oldTrack);
115
+ this.localStream?.addTrack(newTrack);
116
+ }
117
+ getLocalTracks(kind) {
118
+ const tracks = Array.from(this.tracks.values());
119
+ if (!kind)
120
+ return tracks;
121
+ return tracks.filter((t) => t.kind === kind);
122
+ }
123
+ // ── 远程流管理 ──
124
+ addRemoteStream(stream) {
125
+ this.remoteStreams.set(stream.id, stream);
126
+ }
127
+ getRemoteStreams() {
128
+ return this.remoteStreams;
129
+ }
130
+ dispose() {
131
+ for (const track of this.tracks.values()) {
132
+ track.stop();
133
+ }
134
+ this.tracks.clear();
135
+ this.localStream = null;
136
+ this.remoteStreams.clear();
137
+ this.logger.info("MediaManager disposed");
138
+ }
139
+ }
140
+ // Annotate the CommonJS export names for ESM import in node:
141
+ 0 && (module.exports = {
142
+ MediaManager
143
+ });
144
+
145
+ //# sourceMappingURL=media-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../src/media/media-manager.ts"],"sourcesContent":["import { createLogger, type Logger } from '../utils/types';\r\nimport type { IDisposable } from '../disposable';\r\nimport type { DisplayMediaOptions, UserMediaOptions } from './types';\r\n\r\nexport type { DisplayMediaOptions, UserMediaOptions } from './types';\r\n\r\ninterface DeviceInfo {\r\n deviceId: string;\r\n groupId: string;\r\n kind: MediaDeviceKind;\r\n label: string;\r\n}\r\n\r\n/**\r\n * 媒体管理器 — 设备枚举、媒体流获取、track 操作\r\n */\r\nexport class MediaManager implements IDisposable {\r\n private logger: Logger;\r\n private localStream: MediaStream | null = null;\r\n private remoteStreams = new Map<string, MediaStream>();\r\n private tracks = new Map<string, MediaStreamTrack>();\r\n\r\n constructor() {\r\n this.logger = createLogger();\r\n }\r\n\r\n // ── 实例方法(委托 static,与文档 rtc.media.* 一致) ──\r\n\r\n enumerateDevices(kind?: MediaDeviceKind): Promise<DeviceInfo[]> {\r\n return MediaManager.enumerateDevices(kind);\r\n }\r\n\r\n getUserMedia(constraints: UserMediaOptions): Promise<MediaStream> {\r\n return MediaManager.getUserMedia(constraints);\r\n }\r\n\r\n getDisplayMedia(options?: DisplayMediaOptions): Promise<MediaStream> {\r\n return MediaManager.getDisplayMedia(options);\r\n }\r\n\r\n // ── 静态工具 ──\r\n\r\n /** 枚举设备 */\r\n static async enumerateDevices(kind?: MediaDeviceKind): Promise<DeviceInfo[]> {\r\n const devices = await navigator.mediaDevices.enumerateDevices();\r\n let filtered = devices;\r\n if (kind) {\r\n filtered = devices.filter(d => d.kind === kind);\r\n }\r\n return filtered.map(d => ({\r\n deviceId: d.deviceId,\r\n groupId: d.groupId,\r\n kind: d.kind,\r\n label: d.label || `Unknown ${d.kind}`,\r\n }));\r\n }\r\n\r\n /** 获取用户媒体(摄像头/麦克风) */\r\n static async getUserMedia(\r\n constraints: UserMediaOptions,\r\n ): Promise<MediaStream> {\r\n return navigator.mediaDevices.getUserMedia(constraints);\r\n }\r\n\r\n /** 获取屏幕流(支持 Electron desktopCapturer sourceId) */\r\n static async getDisplayMedia(\r\n options?: DisplayMediaOptions,\r\n ): Promise<MediaStream> {\r\n const baseConstraints: DisplayMediaStreamOptions = {\r\n video: true,\r\n audio: options?.audio ?? false,\r\n };\r\n\r\n if (options?.sourceId) {\r\n baseConstraints.video = {\r\n // @ts-expect-error Electron desktopCapturer constraints\r\n mandatory: {\r\n chromeMediaSource: 'desktop',\r\n chromeMediaSourceId: options.sourceId,\r\n },\r\n };\r\n } else if (options?.width || options?.height || options?.frameRate) {\r\n const video: MediaTrackConstraints = {};\r\n if (options.width) video.width = options.width;\r\n if (options.height) video.height = options.height;\r\n if (options.frameRate) video.frameRate = options.frameRate;\r\n baseConstraints.video = video;\r\n }\r\n\r\n if (navigator.mediaDevices.getDisplayMedia) {\r\n return navigator.mediaDevices.getDisplayMedia(baseConstraints);\r\n }\r\n return navigator.mediaDevices.getUserMedia(baseConstraints as MediaStreamConstraints);\r\n }\r\n\r\n // ── 本地流管理 ──\r\n\r\n setLocalStream(stream: MediaStream): void {\r\n this.localStream = stream;\r\n for (const track of stream.getTracks()) {\r\n this.tracks.set(track.id, track);\r\n }\r\n }\r\n\r\n getLocalStream(): MediaStream | null {\r\n return this.localStream;\r\n }\r\n\r\n addTrack(track: MediaStreamTrack, stream: MediaStream): void {\r\n stream.addTrack(track);\r\n this.localStream = stream;\r\n this.tracks.set(track.id, track);\r\n }\r\n\r\n removeTrack(track: MediaStreamTrack): void {\r\n track.stop();\r\n this.tracks.delete(track.id);\r\n this.localStream?.removeTrack(track);\r\n }\r\n\r\n replaceTrack(\r\n oldTrack: MediaStreamTrack,\r\n newTrack: MediaStreamTrack,\r\n ): void {\r\n oldTrack.stop();\r\n this.tracks.delete(oldTrack.id);\r\n this.tracks.set(newTrack.id, newTrack);\r\n this.localStream?.removeTrack(oldTrack);\r\n this.localStream?.addTrack(newTrack);\r\n }\r\n\r\n getLocalTracks(kind?: 'audio' | 'video'): MediaStreamTrack[] {\r\n const tracks = Array.from(this.tracks.values());\r\n if (!kind) return tracks;\r\n return tracks.filter(t => t.kind === kind);\r\n }\r\n\r\n // ── 远程流管理 ──\r\n\r\n addRemoteStream(stream: MediaStream): void {\r\n this.remoteStreams.set(stream.id, stream);\r\n }\r\n\r\n getRemoteStreams(): ReadonlyMap<string, MediaStream> {\r\n return this.remoteStreams;\r\n }\r\n\r\n dispose(): void {\r\n for (const track of this.tracks.values()) {\r\n track.stop();\r\n }\r\n this.tracks.clear();\r\n this.localStream = null;\r\n this.remoteStreams.clear();\r\n this.logger.info('MediaManager disposed');\r\n }\r\n}\r\n\r\nexport type { DeviceInfo };\r\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IiIsIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W119"]}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+ var types_exports = {};
16
+ module.exports = __toCommonJS(types_exports);
17
+
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":";;;;;;;;;;;;;;AAAA;AAAA","names":[],"ignoreList":[],"sources":["../../../src/media/types.ts"],"sourcesContent":["export interface DeviceInfo {\r\n deviceId: string;\r\n groupId: string;\r\n kind: MediaDeviceKind;\r\n label: string;\r\n}\r\n\r\nexport interface DisplayMediaOptions {\r\n /** Electron desktopCapturer sourceId */\r\n sourceId?: string;\r\n /** 是否捕获系统音频 */\r\n audio?: boolean;\r\n /** 分辨率约束 */\r\n width?: number;\r\n height?: number;\r\n frameRate?: number;\r\n}\r\n\r\nexport interface UserMediaOptions {\r\n audio?: boolean | MediaTrackConstraints;\r\n video?: boolean | MediaTrackConstraints;\r\n}\r\n\r\nexport interface MediaConstraints {\r\n audio?: boolean | MediaTrackConstraints;\r\n video?: boolean | MediaTrackConstraints;\r\n}"]}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var video_encoding_exports = {};
20
+ __export(video_encoding_exports, {
21
+ applyReceiverPlayoutDelay: () => applyReceiverPlayoutDelay,
22
+ applyVideoEncodingToConnection: () => applyVideoEncodingToConnection,
23
+ applyVideoSenderEncoding: () => applyVideoSenderEncoding,
24
+ applyVideoTrackContentHint: () => applyVideoTrackContentHint
25
+ });
26
+ module.exports = __toCommonJS(video_encoding_exports);
27
+ var import_encoding_utils = require("./encoding-utils");
28
+ function applyVideoTrackContentHint(track, contentHint = "motion") {
29
+ if (track.kind !== "video")
30
+ return;
31
+ if (!("contentHint" in track) || contentHint == null)
32
+ return;
33
+ track.contentHint = contentHint;
34
+ }
35
+ async function applyVideoSenderEncoding(sender, options) {
36
+ const track = sender.track;
37
+ if (!track || track.kind !== "video")
38
+ return false;
39
+ if (options.contentHint) {
40
+ applyVideoTrackContentHint(track, options.contentHint);
41
+ }
42
+ const params = sender.getParameters();
43
+ if (!params.encodings?.length) {
44
+ params.encodings = [{}];
45
+ }
46
+ const encoding = params.encodings[0];
47
+ if (options.maxFrameRate != null) {
48
+ encoding.maxFramerate = options.maxFrameRate;
49
+ }
50
+ if (options.maxBitrate != null) {
51
+ encoding.maxBitrate = options.maxBitrate;
52
+ }
53
+ if (options.degradationPreference) {
54
+ params.degradationPreference = options.degradationPreference;
55
+ }
56
+ try {
57
+ await sender.setParameters(params);
58
+ return true;
59
+ } catch (err) {
60
+ if ((0, import_encoding_utils.isExpectedSetParametersError)(err)) {
61
+ return false;
62
+ }
63
+ throw err;
64
+ }
65
+ }
66
+ function applyReceiverPlayoutDelay(pc, delaySeconds = 0) {
67
+ for (const receiver of pc.getReceivers()) {
68
+ if (!("playoutDelayHint" in receiver))
69
+ continue;
70
+ receiver.playoutDelayHint = delaySeconds;
71
+ }
72
+ }
73
+ async function applyVideoEncodingToConnection(pc, options) {
74
+ const results = await Promise.all(
75
+ pc.getSenders().filter((sender) => sender.track?.kind === "video").map((sender) => applyVideoSenderEncoding(sender, options))
76
+ );
77
+ return results.some(Boolean);
78
+ }
79
+ // Annotate the CommonJS export names for ESM import in node:
80
+ 0 && (module.exports = {
81
+ applyReceiverPlayoutDelay,
82
+ applyVideoEncodingToConnection,
83
+ applyVideoSenderEncoding,
84
+ applyVideoTrackContentHint
85
+ });
86
+
87
+ //# sourceMappingURL=video-encoding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAA6C;AAStC,SAAS,2BACd,OACA,cAAmD,UAC7C;AACN,MAAI,MAAM,SAAS;AAAS;AAC5B,MAAI,EAAE,iBAAiB,UAAU,eAAe;AAAM;AACtD,QAAM,cAAc;AACtB;AAGA,eAAsB,yBACpB,QACA,SACkB;AAClB,QAAM,QAAQ,OAAO;AACrB,MAAI,CAAC,SAAS,MAAM,SAAS;AAAS,WAAO;AAE7C,MAAI,QAAQ,aAAa;AACvB,+BAA2B,OAAO,QAAQ,WAAW;AAAA,EACvD;AAEA,QAAM,SAAS,OAAO,cAAc;AACpC,MAAI,CAAC,OAAO,WAAW,QAAQ;AAC7B,WAAO,YAAY,CAAC,CAAC,CAAC;AAAA,EACxB;AAEA,QAAM,WAAW,OAAO,UAAU,CAAC;AACnC,MAAI,QAAQ,gBAAgB,MAAM;AAChC,aAAS,eAAe,QAAQ;AAAA,EAClC;AACA,MAAI,QAAQ,cAAc,MAAM;AAC9B,aAAS,aAAa,QAAQ;AAAA,EAChC;AACA,MAAI,QAAQ,uBAAuB;AACjC,WAAO,wBAAwB,QAAQ;AAAA,EACzC;AAEA,MAAI;AACF,UAAM,OAAO,cAAc,MAAM;AACjC,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,YAAI,oDAA6B,GAAG,GAAG;AACrC,aAAO;AAAA,IACT;AACA,UAAM;AAAA,EACR;AACF;AAEO,SAAS,0BACd,IACA,eAAe,GACT;AACN,aAAW,YAAY,GAAG,aAAa,GAAG;AACxC,QAAI,EAAE,sBAAsB;AAAW;AAEvC,IAAC,SAA2D,mBAC1D;AAAA,EACJ;AACF;AAEA,eAAsB,+BACpB,IACA,SACkB;AAClB,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,GACG,WAAW,EACX,OAAO,CAAC,WAAW,OAAO,OAAO,SAAS,OAAO,EACjD,IAAI,CAAC,WAAW,yBAAyB,QAAQ,OAAO,CAAC;AAAA,EAC9D;AACA,SAAO,QAAQ,KAAK,OAAO;AAC7B","names":[],"ignoreList":[],"sources":["../../../src/media/video-encoding.ts"],"sourcesContent":["import { isExpectedSetParametersError } from './encoding-utils';\r\n\r\nexport interface VideoEncodingOptions {\r\n maxFrameRate?: number;\r\n maxBitrate?: number;\r\n degradationPreference?: RTCDegradationPreference;\r\n contentHint?: 'motion' | 'detail' | 'text';\r\n}\r\n\r\nexport function applyVideoTrackContentHint(\r\n track: MediaStreamTrack,\r\n contentHint: VideoEncodingOptions['contentHint'] = 'motion',\r\n): void {\r\n if (track.kind !== 'video') return;\r\n if (!('contentHint' in track) || contentHint == null) return;\r\n track.contentHint = contentHint;\r\n}\r\n\r\n/** @returns 是否成功调用 setParameters(协商完成前失败属正常,可在 connected 后重试) */\r\nexport async function applyVideoSenderEncoding(\r\n sender: RTCRtpSender,\r\n options: VideoEncodingOptions,\r\n): Promise<boolean> {\r\n const track = sender.track;\r\n if (!track || track.kind !== 'video') return false;\r\n\r\n if (options.contentHint) {\r\n applyVideoTrackContentHint(track, options.contentHint);\r\n }\r\n\r\n const params = sender.getParameters();\r\n if (!params.encodings?.length) {\r\n params.encodings = [{}];\r\n }\r\n\r\n const encoding = params.encodings[0];\r\n if (options.maxFrameRate != null) {\r\n encoding.maxFramerate = options.maxFrameRate;\r\n }\r\n if (options.maxBitrate != null) {\r\n encoding.maxBitrate = options.maxBitrate;\r\n }\r\n if (options.degradationPreference) {\r\n params.degradationPreference = options.degradationPreference;\r\n }\r\n\r\n try {\r\n await sender.setParameters(params);\r\n return true;\r\n } catch (err) {\r\n if (isExpectedSetParametersError(err)) {\r\n return false;\r\n }\r\n throw err;\r\n }\r\n}\r\n\r\nexport function applyReceiverPlayoutDelay(\r\n pc: RTCPeerConnection,\r\n delaySeconds = 0,\r\n): void {\r\n for (const receiver of pc.getReceivers()) {\r\n if (!('playoutDelayHint' in receiver)) continue;\r\n\r\n (receiver as RTCRtpReceiver & { playoutDelayHint: number }).playoutDelayHint =\r\n delaySeconds;\r\n }\r\n}\r\n\r\nexport async function applyVideoEncodingToConnection(\r\n pc: RTCPeerConnection,\r\n options: VideoEncodingOptions,\r\n): Promise<boolean> {\r\n const results = await Promise.all(\r\n pc\r\n .getSenders()\r\n .filter((sender) => sender.track?.kind === 'video')\r\n .map((sender) => applyVideoSenderEncoding(sender, options)),\r\n );\r\n return results.some(Boolean);\r\n}\r\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IiIsIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6W10sInNvdXJjZXMiOltdLCJzb3VyY2VzQ29udGVudCI6W119"]}