im-rtc-call-engine 1.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 (218) hide show
  1. package/LICENSE +21 -0
  2. package/dist/bytes.d.ts +11 -0
  3. package/dist/bytes.d.ts.map +1 -0
  4. package/dist/bytes.js +20 -0
  5. package/dist/bytes.js.map +1 -0
  6. package/dist/callOptions.d.ts +27 -0
  7. package/dist/callOptions.d.ts.map +1 -0
  8. package/dist/callOptions.js +19 -0
  9. package/dist/callOptions.js.map +1 -0
  10. package/dist/deviceId.d.ts +10 -0
  11. package/dist/deviceId.d.ts.map +1 -0
  12. package/dist/deviceId.js +55 -0
  13. package/dist/deviceId.js.map +1 -0
  14. package/dist/engine.d.ts +302 -0
  15. package/dist/engine.d.ts.map +1 -0
  16. package/dist/engine.js +489 -0
  17. package/dist/engine.js.map +1 -0
  18. package/dist/engineBus.d.ts +16 -0
  19. package/dist/engineBus.d.ts.map +1 -0
  20. package/dist/engineBus.js +89 -0
  21. package/dist/engineBus.js.map +1 -0
  22. package/dist/engineWiring.d.ts +40 -0
  23. package/dist/engineWiring.d.ts.map +1 -0
  24. package/dist/engineWiring.js +57 -0
  25. package/dist/engineWiring.js.map +1 -0
  26. package/dist/errors.d.ts +185 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +253 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/eventBus.d.ts +24 -0
  31. package/dist/eventBus.d.ts.map +1 -0
  32. package/dist/eventBus.js +50 -0
  33. package/dist/eventBus.js.map +1 -0
  34. package/dist/events.d.ts +220 -0
  35. package/dist/events.d.ts.map +1 -0
  36. package/dist/events.js +35 -0
  37. package/dist/events.js.map +1 -0
  38. package/dist/frameLoop.d.ts +93 -0
  39. package/dist/frameLoop.d.ts.map +1 -0
  40. package/dist/frameLoop.js +346 -0
  41. package/dist/frameLoop.js.map +1 -0
  42. package/dist/index.d.ts +60 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +42 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/logger.d.ts +64 -0
  47. package/dist/logger.d.ts.map +1 -0
  48. package/dist/logger.js +101 -0
  49. package/dist/logger.js.map +1 -0
  50. package/dist/media/engineMediaApi.d.ts +40 -0
  51. package/dist/media/engineMediaApi.d.ts.map +1 -0
  52. package/dist/media/engineMediaApi.js +71 -0
  53. package/dist/media/engineMediaApi.js.map +1 -0
  54. package/dist/media/firstFrameGate.d.ts +47 -0
  55. package/dist/media/firstFrameGate.d.ts.map +1 -0
  56. package/dist/media/firstFrameGate.js +117 -0
  57. package/dist/media/firstFrameGate.js.map +1 -0
  58. package/dist/media/mediaAdapter.d.ts +135 -0
  59. package/dist/media/mediaAdapter.d.ts.map +1 -0
  60. package/dist/media/mediaAdapter.js +2 -0
  61. package/dist/media/mediaAdapter.js.map +1 -0
  62. package/dist/media/mediaBridge.d.ts +99 -0
  63. package/dist/media/mediaBridge.d.ts.map +1 -0
  64. package/dist/media/mediaBridge.js +186 -0
  65. package/dist/media/mediaBridge.js.map +1 -0
  66. package/dist/media/mediaPlane.d.ts +58 -0
  67. package/dist/media/mediaPlane.d.ts.map +1 -0
  68. package/dist/media/mediaPlane.js +119 -0
  69. package/dist/media/mediaPlane.js.map +1 -0
  70. package/dist/media/videoProfile.d.ts +79 -0
  71. package/dist/media/videoProfile.d.ts.map +1 -0
  72. package/dist/media/videoProfile.js +46 -0
  73. package/dist/media/videoProfile.js.map +1 -0
  74. package/dist/media/videoProfile.test.d.ts +2 -0
  75. package/dist/media/videoProfile.test.d.ts.map +1 -0
  76. package/dist/media/videoProfile.test.js +26 -0
  77. package/dist/media/videoProfile.test.js.map +1 -0
  78. package/dist/media/viewRegistry.d.ts +75 -0
  79. package/dist/media/viewRegistry.d.ts.map +1 -0
  80. package/dist/media/viewRegistry.js +130 -0
  81. package/dist/media/viewRegistry.js.map +1 -0
  82. package/dist/media/webrtcAdapter.d.ts +158 -0
  83. package/dist/media/webrtcAdapter.d.ts.map +1 -0
  84. package/dist/media/webrtcAdapter.js +502 -0
  85. package/dist/media/webrtcAdapter.js.map +1 -0
  86. package/dist/protocolId.d.ts +14 -0
  87. package/dist/protocolId.d.ts.map +1 -0
  88. package/dist/protocolId.js +109 -0
  89. package/dist/protocolId.js.map +1 -0
  90. package/dist/reasons.d.ts +63 -0
  91. package/dist/reasons.d.ts.map +1 -0
  92. package/dist/reasons.js +81 -0
  93. package/dist/reasons.js.map +1 -0
  94. package/dist/redact.d.ts +19 -0
  95. package/dist/redact.d.ts.map +1 -0
  96. package/dist/redact.js +50 -0
  97. package/dist/redact.js.map +1 -0
  98. package/dist/signaling/backoff.d.ts +17 -0
  99. package/dist/signaling/backoff.d.ts.map +1 -0
  100. package/dist/signaling/backoff.js +23 -0
  101. package/dist/signaling/backoff.js.map +1 -0
  102. package/dist/signaling/candidate.d.ts +19 -0
  103. package/dist/signaling/candidate.d.ts.map +1 -0
  104. package/dist/signaling/candidate.js +22 -0
  105. package/dist/signaling/candidate.js.map +1 -0
  106. package/dist/signaling/caseMapping.d.ts +19 -0
  107. package/dist/signaling/caseMapping.d.ts.map +1 -0
  108. package/dist/signaling/caseMapping.js +34 -0
  109. package/dist/signaling/caseMapping.js.map +1 -0
  110. package/dist/signaling/connection.d.ts +110 -0
  111. package/dist/signaling/connection.d.ts.map +1 -0
  112. package/dist/signaling/connection.js +365 -0
  113. package/dist/signaling/connection.js.map +1 -0
  114. package/dist/signaling/connectionFactory.d.ts +55 -0
  115. package/dist/signaling/connectionFactory.d.ts.map +1 -0
  116. package/dist/signaling/connectionFactory.js +29 -0
  117. package/dist/signaling/connectionFactory.js.map +1 -0
  118. package/dist/signaling/connectionTypes.d.ts +94 -0
  119. package/dist/signaling/connectionTypes.d.ts.map +1 -0
  120. package/dist/signaling/connectionTypes.js +2 -0
  121. package/dist/signaling/connectionTypes.js.map +1 -0
  122. package/dist/signaling/discipline.d.ts +6 -0
  123. package/dist/signaling/discipline.d.ts.map +1 -0
  124. package/dist/signaling/discipline.js +100 -0
  125. package/dist/signaling/discipline.js.map +1 -0
  126. package/dist/signaling/enums.d.ts +53 -0
  127. package/dist/signaling/enums.d.ts.map +1 -0
  128. package/dist/signaling/enums.js +52 -0
  129. package/dist/signaling/enums.js.map +1 -0
  130. package/dist/signaling/envelope.d.ts +31 -0
  131. package/dist/signaling/envelope.d.ts.map +1 -0
  132. package/dist/signaling/envelope.js +91 -0
  133. package/dist/signaling/envelope.js.map +1 -0
  134. package/dist/signaling/fieldSpec.d.ts +101 -0
  135. package/dist/signaling/fieldSpec.d.ts.map +1 -0
  136. package/dist/signaling/fieldSpec.js +130 -0
  137. package/dist/signaling/fieldSpec.js.map +1 -0
  138. package/dist/signaling/frameSender.d.ts +34 -0
  139. package/dist/signaling/frameSender.d.ts.map +1 -0
  140. package/dist/signaling/frameSender.js +57 -0
  141. package/dist/signaling/frameSender.js.map +1 -0
  142. package/dist/signaling/frames.call.d.ts +299 -0
  143. package/dist/signaling/frames.call.d.ts.map +1 -0
  144. package/dist/signaling/frames.call.js +149 -0
  145. package/dist/signaling/frames.call.js.map +1 -0
  146. package/dist/signaling/frames.room.d.ts +566 -0
  147. package/dist/signaling/frames.room.d.ts.map +1 -0
  148. package/dist/signaling/frames.room.js +165 -0
  149. package/dist/signaling/frames.room.js.map +1 -0
  150. package/dist/signaling/frames.sys.d.ts +145 -0
  151. package/dist/signaling/frames.sys.d.ts.map +1 -0
  152. package/dist/signaling/frames.sys.js +53 -0
  153. package/dist/signaling/frames.sys.js.map +1 -0
  154. package/dist/signaling/handshakeGiveUp.d.ts +36 -0
  155. package/dist/signaling/handshakeGiveUp.d.ts.map +1 -0
  156. package/dist/signaling/handshakeGiveUp.js +48 -0
  157. package/dist/signaling/handshakeGiveUp.js.map +1 -0
  158. package/dist/signaling/heartbeat.d.ts +34 -0
  159. package/dist/signaling/heartbeat.d.ts.map +1 -0
  160. package/dist/signaling/heartbeat.js +52 -0
  161. package/dist/signaling/heartbeat.js.map +1 -0
  162. package/dist/signaling/pendingRequests.d.ts +33 -0
  163. package/dist/signaling/pendingRequests.d.ts.map +1 -0
  164. package/dist/signaling/pendingRequests.js +57 -0
  165. package/dist/signaling/pendingRequests.js.map +1 -0
  166. package/dist/signaling/reconnector.d.ts +43 -0
  167. package/dist/signaling/reconnector.d.ts.map +1 -0
  168. package/dist/signaling/reconnector.js +76 -0
  169. package/dist/signaling/reconnector.js.map +1 -0
  170. package/dist/signaling/registry.d.ts +100 -0
  171. package/dist/signaling/registry.d.ts.map +1 -0
  172. package/dist/signaling/registry.js +217 -0
  173. package/dist/signaling/registry.js.map +1 -0
  174. package/dist/signaling/resumeDeadline.d.ts +48 -0
  175. package/dist/signaling/resumeDeadline.d.ts.map +1 -0
  176. package/dist/signaling/resumeDeadline.js +89 -0
  177. package/dist/signaling/resumeDeadline.js.map +1 -0
  178. package/dist/signaling/tokenExpiry.d.ts +89 -0
  179. package/dist/signaling/tokenExpiry.d.ts.map +1 -0
  180. package/dist/signaling/tokenExpiry.js +106 -0
  181. package/dist/signaling/tokenExpiry.js.map +1 -0
  182. package/dist/signaling/webSocket.d.ts +59 -0
  183. package/dist/signaling/webSocket.d.ts.map +1 -0
  184. package/dist/signaling/webSocket.js +50 -0
  185. package/dist/signaling/webSocket.js.map +1 -0
  186. package/dist/state/callMachine.d.ts +56 -0
  187. package/dist/state/callMachine.d.ts.map +1 -0
  188. package/dist/state/callMachine.js +176 -0
  189. package/dist/state/callMachine.js.map +1 -0
  190. package/dist/state/callRecv.d.ts +12 -0
  191. package/dist/state/callRecv.d.ts.map +1 -0
  192. package/dist/state/callRecv.js +255 -0
  193. package/dist/state/callRecv.js.map +1 -0
  194. package/dist/state/engineMachine.d.ts +41 -0
  195. package/dist/state/engineMachine.d.ts.map +1 -0
  196. package/dist/state/engineMachine.js +210 -0
  197. package/dist/state/engineMachine.js.map +1 -0
  198. package/dist/state/forceEnd.d.ts +44 -0
  199. package/dist/state/forceEnd.d.ts.map +1 -0
  200. package/dist/state/forceEnd.js +96 -0
  201. package/dist/state/forceEnd.js.map +1 -0
  202. package/dist/state/roomMachine.d.ts +92 -0
  203. package/dist/state/roomMachine.d.ts.map +1 -0
  204. package/dist/state/roomMachine.js +319 -0
  205. package/dist/state/roomMachine.js.map +1 -0
  206. package/dist/state/roomRecv.d.ts +7 -0
  207. package/dist/state/roomRecv.d.ts.map +1 -0
  208. package/dist/state/roomRecv.js +209 -0
  209. package/dist/state/roomRecv.js.map +1 -0
  210. package/dist/state/types.d.ts +61 -0
  211. package/dist/state/types.d.ts.map +1 -0
  212. package/dist/state/types.js +30 -0
  213. package/dist/state/types.js.map +1 -0
  214. package/dist/version.d.ts +11 -0
  215. package/dist/version.d.ts.map +1 -0
  216. package/dist/version.js +11 -0
  217. package/dist/version.js.map +1 -0
  218. package/package.json +35 -0
@@ -0,0 +1,100 @@
1
+ import { ErrorCode, RtcError } from '../errors.js';
2
+ /**
3
+ * RTC_PROTOCOL.md §2.4「七条编码硬规则」里能**脱离帧定义**判定的那几条。
4
+ *
5
+ * 它们是「三端都能实现」这句话的落点:不放浮点、不放 null、数组同构、嵌套不超过两层,
6
+ * 于是 C++ 不需要 optional<optional<T>>、TS 不需要区分 undefined 与 null、
7
+ * Swift 不需要 Optional<Optional>。
8
+ *
9
+ * 剩下两条(字段类型恒定、枚举封闭带兜底)没法脱离帧定义判,由 fieldSpec.ts 负责。
10
+ */
11
+ /** data 本身算第 1 层,再嵌一层算第 2 层,第 3 层非法。数组不增加深度。 */
12
+ const MAX_OBJECT_DEPTH = 2;
13
+ /** 2^53-1:超出这个范围 JS 会**静默**丢精度,那种 bug 在四端联调里基本定位不了。 */
14
+ const MAX_SAFE_PROTOCOL_INT = Number.MAX_SAFE_INTEGER;
15
+ /**
16
+ * checkDiscipline 检查一个已解析的 data 是否满足编码硬规则。
17
+ * 违规抛 RtcError(bad_envelope 或 bad_params)。
18
+ */
19
+ export function checkDiscipline(data) {
20
+ walk(data, 1, 'data');
21
+ }
22
+ function walk(value, depth, path) {
23
+ if (value === null) {
24
+ // §2.4 规则 2:协议里任何位置都不许出现 null。可选字段的表达方式是**省略**。
25
+ throw new RtcError(ErrorCode.badEnvelope, {
26
+ cause: new Error(`${path}: 出现 null;可选字段请省略,不要写 null`),
27
+ });
28
+ }
29
+ if (typeof value === 'number') {
30
+ checkNumber(value, path);
31
+ return;
32
+ }
33
+ if (typeof value === 'string' || typeof value === 'boolean')
34
+ return;
35
+ if (Array.isArray(value)) {
36
+ walkArray(value, depth, path);
37
+ return;
38
+ }
39
+ walkObject(value, depth, path);
40
+ }
41
+ function walkObject(value, depth, path) {
42
+ if (depth > MAX_OBJECT_DEPTH) {
43
+ throw new RtcError(ErrorCode.badParams, {
44
+ cause: new Error(`${path}: 对象嵌套 ${depth} 层 > 上限 ${MAX_OBJECT_DEPTH};` +
45
+ '要塞任意结构请用 user_data(opaque 字符串)'),
46
+ });
47
+ }
48
+ for (const [key, child] of Object.entries(value)) {
49
+ walk(child, depth + 1, `${path}.${key}`);
50
+ }
51
+ }
52
+ /**
53
+ * walkArray 除了递归检查元素,还要确认数组是**同构**的(§2.4 规则 4)。
54
+ * 异构数组在 TS/Swift 里勉强能表达,在 C++ 里就得上 variant——所以协议层直接禁掉。
55
+ */
56
+ function walkArray(value, depth, path) {
57
+ let firstKind;
58
+ for (let i = 0; i < value.length; i += 1) {
59
+ // noUncheckedIndexedAccess 下这是 JsonValue | undefined;数组内不会有洞,
60
+ // 但类型系统不知道,所以显式取一次。
61
+ const element = value[i];
62
+ const kind = kindOf(element);
63
+ if (i === 0) {
64
+ firstKind = kind;
65
+ }
66
+ else if (kind !== firstKind) {
67
+ throw new RtcError(ErrorCode.badParams, {
68
+ cause: new Error(`${path}: 数组必须同构,第 0 个是 ${String(firstKind)}、第 ${i} 个是 ${kind};` +
69
+ '要成对请用对象数组'),
70
+ });
71
+ }
72
+ walk(element, depth, `${path}[${i}]`);
73
+ }
74
+ }
75
+ /**
76
+ * checkNumber 落实 §2.4 规则 1(没有浮点数)与规则 7(整数不超过 2^53-1)。
77
+ *
78
+ * 判定按**值**而不是按字面量:`1e3` 是整数 1000,合法;`4.5` 不是,非法。
79
+ * 四端必须用同一套判定,否则一端发得出去、另一端收不下来。
80
+ */
81
+ function checkNumber(value, path) {
82
+ if (!Number.isFinite(value) || !Number.isInteger(value)) {
83
+ throw new RtcError(ErrorCode.badParams, {
84
+ cause: new Error(`${path}: 协议里没有浮点数,得到 ${value};音量/质量/时长/码率一律用整数`),
85
+ });
86
+ }
87
+ if (Math.abs(value) > MAX_SAFE_PROTOCOL_INT) {
88
+ throw new RtcError(ErrorCode.badParams, {
89
+ cause: new Error(`${path}: 整数 ${value} 超出 ±(2^53-1),会静默丢精度`),
90
+ });
91
+ }
92
+ }
93
+ function kindOf(value) {
94
+ if (value === null)
95
+ return 'null';
96
+ if (Array.isArray(value))
97
+ return 'array';
98
+ return typeof value;
99
+ }
100
+ //# sourceMappingURL=discipline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discipline.js","sourceRoot":"","sources":["../../src/signaling/discipline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 协议枚举:**封闭的小写字符串集合**(RTC_PROTOCOL.md §2.4 规则 6)。
3
+ *
4
+ * 每个枚举都配一个兜底值,收到集合外的值折成它——这是「新增枚举值不算破坏兼容」
5
+ * (§10)成立的前提:服务端发一个老客户端不认识的值时,老客户端不能崩。
6
+ *
7
+ * 用 `as const` 数组 + 联合类型,不用 TS `enum`(CONVENTIONS §3)。
8
+ */
9
+ /** MEDIA_TYPES:通话媒体类型。兜底 'audio'——宁可当语音,也不去开一个不存在的摄像头。 */
10
+ export declare const MEDIA_TYPES: readonly ["audio", "video"];
11
+ /** MediaType 是 media_type 的取值。 */
12
+ export type MediaType = (typeof MEDIA_TYPES)[number];
13
+ /** REASONS:通话结束原因,与 reasons.ts 的 CallEndReason 同一份。兜底 'error'。 */
14
+ export declare const REASONS: readonly ["hangup", "cancel", "reject", "no_answer", "busy", "offline", "answered_elsewhere", "rejected_elsewhere", "kicked", "room_closed", "network", "error"];
15
+ /** LAYERS:simulcast 层。'none' = 暂停下发但保留订阅。兜底 'l'——宁可给小图。 */
16
+ export declare const LAYERS: readonly ["none", "l", "m", "h"];
17
+ /** Layer 是 max_layer 的取值。 */
18
+ export type Layer = (typeof LAYERS)[number];
19
+ /** TRACK_KINDS:Track 类型。 */
20
+ export declare const TRACK_KINDS: readonly ["audio", "video"];
21
+ /** TrackKind 是 kind 的取值。 */
22
+ export type TrackKind = (typeof TRACK_KINDS)[number];
23
+ /** TRACK_SOURCES:Track 来源。同一 participant 同一 source 最多一条 Track。 */
24
+ export declare const TRACK_SOURCES: readonly ["microphone", "camera", "screen", "screen_audio"];
25
+ /** TrackSource 是 source 的取值。 */
26
+ export type TrackSource = (typeof TRACK_SOURCES)[number];
27
+ /**
28
+ * PC_ROLES:两条 PeerConnection。**每条的 offerer 是固定的**(§3.3)——
29
+ * pub 由客户端 offer、sub 由服务端 offer。固定 offerer 就没有 glare,
30
+ * 所以 engine 里不需要 perfect negotiation / rollback。
31
+ */
32
+ export declare const PC_ROLES: readonly ["pub", "sub"];
33
+ /** PcRole 是 pc 的取值。 */
34
+ export type PcRole = (typeof PC_ROLES)[number];
35
+ /** ROOM_KINDS:房间策略预设。 */
36
+ export declare const ROOM_KINDS: readonly ["call_1v1", "call_group", "meeting"];
37
+ /** RoomKind 是 room_kind 的取值。 */
38
+ export type RoomKind = (typeof ROOM_KINDS)[number];
39
+ /** HANDLED_ACTIONS:另一台设备做了什么。 */
40
+ export declare const HANDLED_ACTIONS: readonly ["accept", "reject"];
41
+ /** HandledAction 是 action 的取值。 */
42
+ export type HandledAction = (typeof HANDLED_ACTIONS)[number];
43
+ /** 网络质量等级 0~6(§3.4)。0 是 unknown,也是越界值的兜底。 */
44
+ export declare const QUALITY_UNKNOWN = 0;
45
+ /** QUALITY_DISCONNECTED 是 level 的上界。 */
46
+ export declare const QUALITY_DISCONNECTED = 6;
47
+ /** 振铃超时的默认值与范围(§2.6)。越界钳到边界,不报错。 */
48
+ export declare const DEFAULT_TIMEOUT_SEC = 30;
49
+ /** MIN_TIMEOUT_SEC 是振铃超时下界。 */
50
+ export declare const MIN_TIMEOUT_SEC = 5;
51
+ /** MAX_TIMEOUT_SEC 是振铃超时上界。 */
52
+ export declare const MAX_TIMEOUT_SEC = 120;
53
+ //# sourceMappingURL=enums.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../src/signaling/enums.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,WAAW,6BAA8B,CAAC;AACvD,kCAAkC;AAClC,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,kEAAkE;AAClE,eAAO,MAAM,OAAO,kKAaV,CAAC;AAEX,2DAA2D;AAC3D,eAAO,MAAM,MAAM,kCAAmC,CAAC;AACvD,6BAA6B;AAC7B,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5C,4BAA4B;AAC5B,eAAO,MAAM,WAAW,6BAA8B,CAAC;AACvD,4BAA4B;AAC5B,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,kEAAkE;AAClE,eAAO,MAAM,aAAa,6DAA8D,CAAC;AACzF,gCAAgC;AAChC,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,yBAA0B,CAAC;AAChD,uBAAuB;AACvB,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,yBAAyB;AACzB,eAAO,MAAM,UAAU,gDAAiD,CAAC;AACzE,gCAAgC;AAChC,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,iCAAiC;AACjC,eAAO,MAAM,eAAe,+BAAgC,CAAC;AAC7D,kCAAkC;AAClC,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,6CAA6C;AAC7C,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,wCAAwC;AACxC,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,oCAAoC;AACpC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AACtC,+BAA+B;AAC/B,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,+BAA+B;AAC/B,eAAO,MAAM,eAAe,MAAM,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * 协议枚举:**封闭的小写字符串集合**(RTC_PROTOCOL.md §2.4 规则 6)。
3
+ *
4
+ * 每个枚举都配一个兜底值,收到集合外的值折成它——这是「新增枚举值不算破坏兼容」
5
+ * (§10)成立的前提:服务端发一个老客户端不认识的值时,老客户端不能崩。
6
+ *
7
+ * 用 `as const` 数组 + 联合类型,不用 TS `enum`(CONVENTIONS §3)。
8
+ */
9
+ /** MEDIA_TYPES:通话媒体类型。兜底 'audio'——宁可当语音,也不去开一个不存在的摄像头。 */
10
+ export const MEDIA_TYPES = ['audio', 'video'];
11
+ /** REASONS:通话结束原因,与 reasons.ts 的 CallEndReason 同一份。兜底 'error'。 */
12
+ export const REASONS = [
13
+ 'hangup',
14
+ 'cancel',
15
+ 'reject',
16
+ 'no_answer',
17
+ 'busy',
18
+ 'offline',
19
+ 'answered_elsewhere',
20
+ 'rejected_elsewhere',
21
+ 'kicked',
22
+ 'room_closed',
23
+ 'network',
24
+ 'error',
25
+ ];
26
+ /** LAYERS:simulcast 层。'none' = 暂停下发但保留订阅。兜底 'l'——宁可给小图。 */
27
+ export const LAYERS = ['none', 'l', 'm', 'h'];
28
+ /** TRACK_KINDS:Track 类型。 */
29
+ export const TRACK_KINDS = ['audio', 'video'];
30
+ /** TRACK_SOURCES:Track 来源。同一 participant 同一 source 最多一条 Track。 */
31
+ export const TRACK_SOURCES = ['microphone', 'camera', 'screen', 'screen_audio'];
32
+ /**
33
+ * PC_ROLES:两条 PeerConnection。**每条的 offerer 是固定的**(§3.3)——
34
+ * pub 由客户端 offer、sub 由服务端 offer。固定 offerer 就没有 glare,
35
+ * 所以 engine 里不需要 perfect negotiation / rollback。
36
+ */
37
+ export const PC_ROLES = ['pub', 'sub'];
38
+ /** ROOM_KINDS:房间策略预设。 */
39
+ export const ROOM_KINDS = ['call_1v1', 'call_group', 'meeting'];
40
+ /** HANDLED_ACTIONS:另一台设备做了什么。 */
41
+ export const HANDLED_ACTIONS = ['accept', 'reject'];
42
+ /** 网络质量等级 0~6(§3.4)。0 是 unknown,也是越界值的兜底。 */
43
+ export const QUALITY_UNKNOWN = 0;
44
+ /** QUALITY_DISCONNECTED 是 level 的上界。 */
45
+ export const QUALITY_DISCONNECTED = 6;
46
+ /** 振铃超时的默认值与范围(§2.6)。越界钳到边界,不报错。 */
47
+ export const DEFAULT_TIMEOUT_SEC = 30;
48
+ /** MIN_TIMEOUT_SEC 是振铃超时下界。 */
49
+ export const MIN_TIMEOUT_SEC = 5;
50
+ /** MAX_TIMEOUT_SEC 是振铃超时上界。 */
51
+ export const MAX_TIMEOUT_SEC = 120;
52
+ //# sourceMappingURL=enums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.js","sourceRoot":"","sources":["../../src/signaling/enums.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AAIvD,kEAAkE;AAClE,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,WAAW;IACX,MAAM;IACN,SAAS;IACT,oBAAoB;IACpB,oBAAoB;IACpB,QAAQ;IACR,aAAa;IACb,SAAS;IACT,OAAO;CACC,CAAC;AAEX,2DAA2D;AAC3D,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAIvD,4BAA4B;AAC5B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAU,CAAC;AAIvD,kEAAkE;AAClE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,cAAc,CAAU,CAAC;AAIzF;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,KAAK,CAAU,CAAC;AAIhD,yBAAyB;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,YAAY,EAAE,SAAS,CAAU,CAAC;AAIzE,iCAAiC;AACjC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAI7D,6CAA6C;AAC7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,wCAAwC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC,oCAAoC;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,+BAA+B;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 信封:**每一帧都是一个 JSON 对象,四个字段,一个不多一个不少**
3
+ * (RTC_PROTOCOL.md §2.1)。
4
+ */
5
+ /** MAX_FRAME_BYTES 是单帧上限(§2.6)。超限对应 WS 关闭码 4400。 */
6
+ export declare const MAX_FRAME_BYTES: number;
7
+ /** OK_SUFFIX 是成功应答的唯一后缀(§2.2)。 */
8
+ export declare const OK_SUFFIX = ".ok";
9
+ /** okType 返回某个请求帧对应的成功应答类型。 */
10
+ export declare function okType(requestType: string): string;
11
+ /** Envelope 是解析后的信封。字段名在 TS 侧用 camelCase,线路上是 snake_case。 */
12
+ export interface Envelope {
13
+ readonly type: string;
14
+ /** 服务端主动推送的事件恒为 ''(§2.2)。 */
15
+ readonly reqId: string;
16
+ /** 发送方的 Unix 毫秒时间戳。**只用于日志,禁止参与逻辑判断**(时钟偏移)。 */
17
+ readonly ts: number;
18
+ readonly data: Readonly<Record<string, unknown>>;
19
+ }
20
+ /**
21
+ * decodeEnvelope 把一帧原始文本解成 Envelope,并施加 §2.4 的编码硬规则。
22
+ *
23
+ * 它**不做**帧级解析——那是 decodeFrame 的事。分成两步是因为路由阶段
24
+ * 只需要 type 与 req_id,没必要为一个马上要丢掉的帧去解 data。
25
+ */
26
+ export declare function decodeEnvelope(raw: string): Envelope;
27
+ /** encodeEnvelope 序列化一帧。data 省略时写成 {}。 */
28
+ export declare function encodeEnvelope(type: string, reqId: string, data?: Readonly<Record<string, unknown>>, ts?: number): string;
29
+ /** isEvent 报告这一帧是不是服务端主动推送的事件。 */
30
+ export declare function isEvent(envelope: Envelope): boolean;
31
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/signaling/envelope.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,oDAAoD;AACpD,eAAO,MAAM,eAAe,QAAY,CAAC;AAEzC,kCAAkC;AAClC,eAAO,MAAM,SAAS,QAAQ,CAAC;AAE/B,+BAA+B;AAC/B,wBAAgB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAqCpD;AAED,0CAA0C;AAC1C,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM,EAC5C,EAAE,GAAE,MAAmB,GACtB,MAAM,CASR;AAED,kCAAkC;AAClC,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,91 @@
1
+ import { byteLength } from '../bytes.js';
2
+ import { ErrorCode, RtcError } from '../errors.js';
3
+ import { checkDiscipline } from './discipline.js';
4
+ /**
5
+ * 信封:**每一帧都是一个 JSON 对象,四个字段,一个不多一个不少**
6
+ * (RTC_PROTOCOL.md §2.1)。
7
+ */
8
+ /** MAX_FRAME_BYTES 是单帧上限(§2.6)。超限对应 WS 关闭码 4400。 */
9
+ export const MAX_FRAME_BYTES = 64 * 1024;
10
+ /** OK_SUFFIX 是成功应答的唯一后缀(§2.2)。 */
11
+ export const OK_SUFFIX = '.ok';
12
+ /** okType 返回某个请求帧对应的成功应答类型。 */
13
+ export function okType(requestType) {
14
+ return requestType + OK_SUFFIX;
15
+ }
16
+ const REQUIRED_KEYS = ['type', 'req_id', 'ts', 'data'];
17
+ /**
18
+ * decodeEnvelope 把一帧原始文本解成 Envelope,并施加 §2.4 的编码硬规则。
19
+ *
20
+ * 它**不做**帧级解析——那是 decodeFrame 的事。分成两步是因为路由阶段
21
+ * 只需要 type 与 req_id,没必要为一个马上要丢掉的帧去解 data。
22
+ */
23
+ export function decodeEnvelope(raw) {
24
+ if (byteLength(raw) > MAX_FRAME_BYTES) {
25
+ throw new RtcError(ErrorCode.frameTooLarge, {
26
+ cause: new Error(`帧 ${byteLength(raw)} 字节 > 上限 ${MAX_FRAME_BYTES}`),
27
+ });
28
+ }
29
+ const parsed = parseObject(raw);
30
+ for (const key of REQUIRED_KEYS) {
31
+ if (!Object.hasOwn(parsed, key)) {
32
+ throw badEnvelope(`缺少必填字段 "${key}"`);
33
+ }
34
+ }
35
+ const type = parsed['type'];
36
+ if (typeof type !== 'string' || type === '') {
37
+ throw badEnvelope('字段 type 必须是非空字符串');
38
+ }
39
+ const reqId = parsed['req_id'];
40
+ if (typeof reqId !== 'string') {
41
+ // req_id 允许是 ''(事件就是 ''),但不允许缺失或非字符串。
42
+ throw badEnvelope('字段 req_id 必须是字符串');
43
+ }
44
+ const ts = parsed['ts'];
45
+ if (typeof ts !== 'number' || !Number.isInteger(ts)) {
46
+ throw badEnvelope('字段 ts 必须是整数');
47
+ }
48
+ const data = parsed['data'];
49
+ if (data === null) {
50
+ throw badEnvelope('字段 data 不能是 null,无内容时用 {}');
51
+ }
52
+ if (typeof data !== 'object' || Array.isArray(data)) {
53
+ throw badEnvelope('字段 data 必须是对象,无内容时用 {}');
54
+ }
55
+ checkDiscipline(data);
56
+ return { type, reqId, ts, data: data };
57
+ }
58
+ /** encodeEnvelope 序列化一帧。data 省略时写成 {}。 */
59
+ export function encodeEnvelope(type, reqId, data = {}, ts = Date.now()) {
60
+ if (type === '')
61
+ throw badEnvelope('type 不能为空');
62
+ const raw = JSON.stringify({ type, req_id: reqId, ts, data });
63
+ if (byteLength(raw) > MAX_FRAME_BYTES) {
64
+ throw new RtcError(ErrorCode.frameTooLarge, {
65
+ cause: new Error(`${type} 编码后 ${byteLength(raw)} 字节 > 上限 ${MAX_FRAME_BYTES}`),
66
+ });
67
+ }
68
+ return raw;
69
+ }
70
+ /** isEvent 报告这一帧是不是服务端主动推送的事件。 */
71
+ export function isEvent(envelope) {
72
+ return envelope.reqId === '';
73
+ }
74
+ function parseObject(raw) {
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(raw);
78
+ }
79
+ catch (cause) {
80
+ throw new RtcError(ErrorCode.badEnvelope, { cause });
81
+ }
82
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
83
+ throw badEnvelope('一帧必须是一个 JSON 对象');
84
+ }
85
+ // parsed 已确认是非数组的普通对象,这个断言是安全的。
86
+ return parsed;
87
+ }
88
+ function badEnvelope(reason) {
89
+ return new RtcError(ErrorCode.badEnvelope, { cause: new Error(reason) });
90
+ }
91
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/signaling/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * 帧字段的**声明式定义**:一处声明同时产出运行时校验与 TS 类型。
3
+ *
4
+ * 为什么不像服务端那样逐帧写结构体:TS 有条件类型,可以从声明推出类型,
5
+ * 于是「协议表 → 代码」只需要写一遍。两处写会漂,一处写不会。
6
+ *
7
+ * 这套声明负责 RTC_PROTOCOL.md §2.4 里**必须结合帧定义**才能判的两条:
8
+ * 规则 3(字段类型恒定)与规则 6(枚举封闭且带兜底)。
9
+ * 与帧无关的四条在 discipline.ts。
10
+ */
11
+ /** FieldSpec 是一个字段的契约。`wire` 是线路上的 snake_case 名。 */
12
+ export type FieldSpec = {
13
+ readonly kind: 'string';
14
+ readonly wire: string;
15
+ readonly default?: string;
16
+ } | {
17
+ readonly kind: 'int';
18
+ readonly wire: string;
19
+ readonly default?: number;
20
+ readonly min?: number;
21
+ readonly max?: number;
22
+ /**
23
+ * 越界时的处理方式。协议对不同字段的规定不一样,不能一刀切:
24
+ * - `timeout_sec` 越界**钳到边界**(§2.6);
25
+ * - 质量 `level` 越界**折成 0 = unknown**(§2.4 规则 6 的兜底表)。
26
+ *
27
+ * 给了 outOfRange 就折成它,没给就钳到边界。
28
+ */
29
+ readonly outOfRange?: number;
30
+ } | {
31
+ readonly kind: 'bool';
32
+ readonly wire: string;
33
+ readonly default?: boolean;
34
+ } | {
35
+ readonly kind: 'enum';
36
+ readonly wire: string;
37
+ readonly values: readonly string[];
38
+ /** 收到集合外的值时折成它,**禁止崩溃、禁止透传给 UI**。 */
39
+ readonly fallback: string;
40
+ readonly default?: string;
41
+ } | {
42
+ readonly kind: 'stringArray';
43
+ readonly wire: string;
44
+ } | {
45
+ readonly kind: 'enumArray';
46
+ readonly wire: string;
47
+ readonly values: readonly string[];
48
+ readonly fallback: string;
49
+ } | {
50
+ readonly kind: 'objectArray';
51
+ readonly wire: string;
52
+ readonly fields: FrameFields;
53
+ } | {
54
+ readonly kind: 'object';
55
+ readonly wire: string;
56
+ readonly fields: FrameFields;
57
+ };
58
+ /** FrameFields 把 camelCase 属性名映射到字段契约。 */
59
+ export type FrameFields = Readonly<Record<string, FieldSpec>>;
60
+ /** FieldType 从字段契约推出 TS 类型。 */
61
+ type FieldType<S extends FieldSpec> = S extends {
62
+ kind: 'string';
63
+ } ? string : S extends {
64
+ kind: 'int';
65
+ } ? number : S extends {
66
+ kind: 'bool';
67
+ } ? boolean : S extends {
68
+ kind: 'enum';
69
+ values: readonly (infer V)[];
70
+ } ? V : S extends {
71
+ kind: 'stringArray';
72
+ } ? string[] : S extends {
73
+ kind: 'enumArray';
74
+ values: readonly (infer V)[];
75
+ } ? V[] : S extends {
76
+ kind: 'objectArray';
77
+ fields: infer F;
78
+ } ? F extends FrameFields ? FrameData<F>[] : never : S extends {
79
+ kind: 'object';
80
+ fields: infer F;
81
+ } ? F extends FrameFields ? FrameData<F> : never : never;
82
+ /**
83
+ * FrameData 从字段声明推出整帧的 TS 类型。
84
+ *
85
+ * `-readonly` 是必要的:字段声明用 `as const` 写,同态映射会把 readonly 一并带过来,
86
+ * 于是「从 newFrameData() 起手再改字段」这条发送侧规矩就没法执行了。
87
+ */
88
+ export type FrameData<F extends FrameFields> = {
89
+ -readonly [K in keyof F]: FieldType<F[K]>;
90
+ };
91
+ /**
92
+ * decodeFields 把线路上的 data 解成带默认值的帧对象。
93
+ *
94
+ * 「可选字段用省略表达,接收方按默认值填」(§2.4 规则 2)就落在这里:
95
+ * 字段缺席 → 取 spec 的默认值;出现了 → 校验类型、归一化枚举、钳制数值。
96
+ */
97
+ export declare function decodeFields<F extends FrameFields>(fields: F, raw: Readonly<Record<string, unknown>>, path?: string): FrameData<F>;
98
+ /** encodeFields 把帧对象映射回线路上的 snake_case data。 */
99
+ export declare function encodeFields<F extends FrameFields>(fields: F, value: FrameData<F>): Record<string, unknown>;
100
+ export {};
101
+ //# sourceMappingURL=fieldSpec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldSpec.d.ts","sourceRoot":"","sources":["../../src/signaling/fieldSpec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { ErrorCode, RtcError } from '../errors.js';
2
+ /**
3
+ * decodeFields 把线路上的 data 解成带默认值的帧对象。
4
+ *
5
+ * 「可选字段用省略表达,接收方按默认值填」(§2.4 规则 2)就落在这里:
6
+ * 字段缺席 → 取 spec 的默认值;出现了 → 校验类型、归一化枚举、钳制数值。
7
+ */
8
+ export function decodeFields(fields, raw, path = 'data') {
9
+ const out = {};
10
+ for (const [prop, spec] of Object.entries(fields)) {
11
+ out[prop] = decodeField(spec, raw[spec.wire], `${path}.${spec.wire}`);
12
+ }
13
+ // out 的每个键都按 fields 的声明填过了,这个断言与上面的循环一一对应。
14
+ return out;
15
+ }
16
+ /** encodeFields 把帧对象映射回线路上的 snake_case data。 */
17
+ export function encodeFields(fields, value) {
18
+ const out = {};
19
+ for (const [prop, spec] of Object.entries(fields)) {
20
+ const own = value[prop];
21
+ out[spec.wire] = encodeField(spec, own);
22
+ }
23
+ return out;
24
+ }
25
+ function decodeField(spec, value, path) {
26
+ if (value === undefined)
27
+ return defaultOf(spec);
28
+ switch (spec.kind) {
29
+ case 'string':
30
+ return expectString(value, path);
31
+ case 'bool':
32
+ // 布尔必须是真布尔:0/1/"true" 一律拒(§2.4「禁止用 0/1 代替」)。
33
+ if (typeof value !== 'boolean')
34
+ throw badParams(`${path} 必须是布尔,得到 ${typeOf(value)}`);
35
+ return value;
36
+ case 'int':
37
+ return coerceInt(expectInt(value, path), spec.min, spec.max, spec.outOfRange);
38
+ case 'enum':
39
+ return normalizeEnum(expectString(value, path), spec.values, spec.fallback);
40
+ case 'stringArray':
41
+ return expectArray(value, path).map((item, i) => expectString(item, `${path}[${i}]`));
42
+ case 'enumArray':
43
+ return expectArray(value, path).map((item, i) => normalizeEnum(expectString(item, `${path}[${i}]`), spec.values, spec.fallback));
44
+ case 'objectArray':
45
+ return expectArray(value, path).map((item, i) => decodeFields(spec.fields, expectObject(item, `${path}[${i}]`), `${path}[${i}]`));
46
+ case 'object':
47
+ return decodeFields(spec.fields, expectObject(value, path), path);
48
+ }
49
+ }
50
+ function encodeField(spec, value) {
51
+ if (value === undefined)
52
+ return defaultOf(spec);
53
+ if (spec.kind === 'objectArray') {
54
+ return expectArray(value, spec.wire).map((item) => encodeFields(spec.fields, item));
55
+ }
56
+ if (spec.kind === 'object') {
57
+ return encodeFields(spec.fields, value);
58
+ }
59
+ return value;
60
+ }
61
+ /**
62
+ * defaultOf 给出字段的协议默认值。
63
+ *
64
+ * **数组的默认值恒为空数组,绝不是 null/undefined**——协议里没有 null,
65
+ * 而 JSON.stringify 会把 undefined 字段整个丢掉,导致「本该有的空数组不见了」。
66
+ */
67
+ function defaultOf(spec) {
68
+ switch (spec.kind) {
69
+ case 'string':
70
+ return spec.default ?? '';
71
+ case 'int':
72
+ return spec.default ?? 0;
73
+ case 'bool':
74
+ return spec.default ?? false;
75
+ case 'enum':
76
+ return spec.default ?? spec.fallback;
77
+ case 'stringArray':
78
+ case 'enumArray':
79
+ case 'objectArray':
80
+ return [];
81
+ case 'object':
82
+ return decodeFields(spec.fields, {});
83
+ }
84
+ }
85
+ function normalizeEnum(value, values, fallback) {
86
+ return values.includes(value) ? value : fallback;
87
+ }
88
+ function coerceInt(value, min, max, outOfRange) {
89
+ const belowMin = min !== undefined && value < min;
90
+ const aboveMax = max !== undefined && value > max;
91
+ if (!belowMin && !aboveMax)
92
+ return value;
93
+ if (outOfRange !== undefined)
94
+ return outOfRange;
95
+ return belowMin ? min : max;
96
+ }
97
+ function expectString(value, path) {
98
+ if (typeof value !== 'string')
99
+ throw badParams(`${path} 必须是字符串,得到 ${typeOf(value)}`);
100
+ return value;
101
+ }
102
+ function expectInt(value, path) {
103
+ if (typeof value !== 'number' || !Number.isInteger(value)) {
104
+ throw badParams(`${path} 必须是整数,得到 ${typeOf(value)}`);
105
+ }
106
+ return value;
107
+ }
108
+ function expectArray(value, path) {
109
+ if (!Array.isArray(value))
110
+ throw badParams(`${path} 必须是数组,得到 ${typeOf(value)}`);
111
+ return value;
112
+ }
113
+ function expectObject(value, path) {
114
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
115
+ throw badParams(`${path} 必须是对象,得到 ${typeOf(value)}`);
116
+ }
117
+ // 已确认是非数组的普通对象。
118
+ return value;
119
+ }
120
+ function typeOf(value) {
121
+ if (value === null)
122
+ return 'null';
123
+ if (Array.isArray(value))
124
+ return 'array';
125
+ return typeof value;
126
+ }
127
+ function badParams(reason) {
128
+ return new RtcError(ErrorCode.badParams, { cause: new Error(reason) });
129
+ }
130
+ //# sourceMappingURL=fieldSpec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldSpec.js","sourceRoot":"","sources":["../../src/signaling/fieldSpec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { MediaAdapter } from '../media/mediaAdapter.js';
2
+ import type { Connection } from './connection.js';
3
+ import type { PcRole } from './enums.js';
4
+ /**
5
+ * FrameSender 把状态机产出的**意图**变成线路上的一帧。
6
+ *
7
+ * # 为什么这一层要单独存在
8
+ *
9
+ * 状态机是纯函数,产不出 SDP——它给的协商帧 `sdp` 字段是空的。
10
+ * 「取真值填进去」这件事既要碰媒体层又要碰连接,放在状态机里会毁掉它的可测性,
11
+ * 放在门面里则让门面同时管路由、填 SDP 和事件三件事。所以单独一层:
12
+ * **门面只管把帧交给它,它只管把帧变成真的**。
13
+ */
14
+ export declare class FrameSender {
15
+ private readonly media;
16
+ /** 服务端最近一次下发的 sub offer,答复时要用。 */
17
+ private lastSubOfferSdp;
18
+ constructor(media: MediaAdapter);
19
+ /** noteSubOffer 记下服务端下发的 sub offer。**答复它时才有得可答**。 */
20
+ noteSubOffer(sdp: string): void;
21
+ /**
22
+ * send 发一帧并返回应答(`{type, data}`)。
23
+ *
24
+ * 返回应答而不是直接消化掉:**`.ok` 也要喂回状态机**——join.ok / publish.ok
25
+ * 都是状态推进的关键一步,漏掉那一半会让房间永远停在 `joining`。
26
+ */
27
+ send(connection: Connection, type: string, data: Readonly<Record<string, unknown>>): Promise<{
28
+ type: string;
29
+ data: Record<string, unknown>;
30
+ } | null>;
31
+ /** sendCandidate 发一个本端候选。候选是尽力而为的,失败由调用方转成 error 事件。 */
32
+ sendCandidate(connection: Connection, pc: PcRole, candidate: RTCIceCandidateInit): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=frameSender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameSender.d.ts","sourceRoot":"","sources":["../../src/signaling/frameSender.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGzC;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAe;IACrC,kCAAkC;IAClC,OAAO,CAAC,eAAe,CAAM;gBAEjB,KAAK,EAAE,YAAY;IAI/B,qDAAqD;IACrD,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAI/B;;;;;OAKG;IACG,IAAI,CACR,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IAclE,wDAAwD;IAClD,aAAa,CACjB,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,mBAAmB,GAC7B,OAAO,CAAC,IAAI,CAAC;CAUjB"}