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,96 @@
1
+ import { CallEndReason, callDurationSec } from '../reasons.js';
2
+ import { FrameType } from '../signaling/registry.js';
3
+ import { initialCallContext } from './callMachine.js';
4
+ import { clearedRoom } from './roomMachine.js';
5
+ /**
6
+ * 强制收场:红键按下去**等不到结束事件**时的出口(门面见 `CallEngine.forceEnd`)。
7
+ *
8
+ * # 为什么 hangup 不够
9
+ *
10
+ * hangup 只发帧,状态由随后的 `call.ended` 推进——服务端才是裁决方(§5.1)。帧要是根本没发出去,
11
+ * 这一场就永远收不掉:2026-09-13 14:54 iOS frank 按了挂断,`call.hangup` 一帧没到服务端,
12
+ * Kit 的看门狗把界面收了,Engine 却还留在通话与房间里,别人一直看得见他,直到 14:58 整通结束。
13
+ *
14
+ * # 这里只算「该发什么、收成什么样」
15
+ *
16
+ * 纯函数,与 `dropLostSession` 同一个形状:通话机、房间机一起归零,抛唯一的结束出口。
17
+ * **发帧由帧循环直接交给信令连接**(不排在在途请求后面),关媒体走既有的 `LEAVE_CALLBACKS`。
18
+ * 五端同形:iOS `IMEngineMachine.forceEnd`、Android 同名。
19
+ */
20
+ /**
21
+ * forceEnd 算出强制收场的结果。没有进行中的通话也不在房里时原样返回(`emit` 为空)。
22
+ *
23
+ * 时长与恢复失败时 I8 的那条例外同一个算法:本地已经收场,服务端那条带真值的 `call.ended`
24
+ * 随后会因为 idle 被丢掉,没有更准的值可用。起点优先用**本端**进来那一刻(`callStartedAtMs`),
25
+ * 没记到才退回整通电话的 `connected_at_ms`——中途被拉进来的人用后者会偏大
26
+ * (2026-09-15 10:05 iOS frank 待了约 6 秒,本地写成 124 秒)。
27
+ *
28
+ * `reason` 不给就按此刻状态挑(红键);给了就用它——`room.publish` 被拒时帧循环传 `error`,
29
+ * 那不是用户挂的,写成 hangup 是撒谎。
30
+ */
31
+ export function forceEnd(ctx, nowMs, reasonOverride) {
32
+ if (ctx.call.state !== 'idle') {
33
+ const { frames, reason: byState } = endFrames(ctx.call);
34
+ const reason = reasonOverride ?? byState;
35
+ const startedAtMs = ctx.callStartedAtMs > 0 ? ctx.callStartedAtMs : ctx.call.connectedAtMs;
36
+ return {
37
+ state: { room: clearedRoom('idle'), call: initialCallContext, callStartedAtMs: 0 },
38
+ send: frames,
39
+ emit: [
40
+ {
41
+ cb: 'onCallEnd',
42
+ args: {
43
+ call_id: ctx.call.callId,
44
+ reason,
45
+ duration_sec: callDurationSec(startedAtMs, nowMs),
46
+ ended_by: '',
47
+ },
48
+ },
49
+ ],
50
+ };
51
+ }
52
+ if (ctx.room.state === 'idle')
53
+ return { state: ctx, send: [], emit: [] };
54
+ // 没有通话却在房里:会议。结束动作是离房(uikit 的红键在会议里就是 leaveRoom)。
55
+ const send = ctx.room.roomId === '' ? [] : [{ type: FrameType.roomLeave, data: { room_id: ctx.room.roomId } }];
56
+ return {
57
+ state: { ...ctx, room: clearedRoom('idle') },
58
+ send,
59
+ emit: [{ cb: 'onRoomLeft', args: { room_id: ctx.room.roomId } }],
60
+ };
61
+ }
62
+ /**
63
+ * endFrames 按通话此刻的状态挑结束帧,以及本地收场写哪个结束原因。
64
+ *
65
+ * - `accepting` 发 **reject + hangup 两帧**:accept 有没有在服务端落地,本端不知道。
66
+ * 还在响铃就是 reject 生效(随后那条 hangup 被拒,无害);已经接起来就是 hangup 生效。
67
+ * - `inviting` 还没拿到 call_id(`call.invite.ok` 没回来)时**此刻发不了 cancel**,
68
+ * 由那条 invite.ok 迟到时补发(`callRecv.ts` 的 `handleLateFrame`)。
69
+ */
70
+ export function endFrames(call) {
71
+ let reason = CallEndReason.hangup;
72
+ let types = [];
73
+ switch (call.state) {
74
+ case 'idle':
75
+ return { frames: [], reason };
76
+ case 'ringing':
77
+ reason = CallEndReason.reject;
78
+ types = [FrameType.callReject];
79
+ break;
80
+ case 'inviting':
81
+ reason = CallEndReason.cancel;
82
+ types = [FrameType.callCancel];
83
+ break;
84
+ case 'accepting':
85
+ types = [FrameType.callReject, FrameType.callHangup];
86
+ break;
87
+ case 'connecting':
88
+ case 'connected':
89
+ types = [FrameType.callHangup];
90
+ break;
91
+ }
92
+ if (call.callId === '')
93
+ return { frames: [], reason };
94
+ return { frames: types.map((type) => ({ type, data: { call_id: call.callId } })), reason };
95
+ }
96
+ //# sourceMappingURL=forceEnd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forceEnd.js","sourceRoot":"","sources":["../../src/state/forceEnd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ import type { Layer, TrackKind } from '../signaling/enums.js';
2
+ import type { EmittedEvent, MachineInput, MachineOutput, OutgoingFrame } from './types.js';
3
+ /**
4
+ * 房间状态机:RTC_PROTOCOL.md §5.3 的 TS 实现。
5
+ *
6
+ * 一致性向量:`im-rtc-server/docs/conformance/room_fsm.json`,四端跑同一份。
7
+ *
8
+ * # 三条不变量(协议 §5.3 的 R1~R3)
9
+ *
10
+ * - **R1** 只有 `joined` 才允许 publish / subscribe / mute;其余状态**本地拒绝**,
11
+ * 不发上去让服务端报错。
12
+ * - **R2** `joining` 与 `reconnecting` 期间**禁止发任何房间帧**,但要把用户意图
13
+ * 缓存下来,进房/恢复后一次性重放。这两个状态的共同点是**宿主观察不到**——
14
+ * 它拿到 onCallBegin 就推流是最自然的写法,不该因为一个内部中间态而失败。
15
+ * - **R3** 订阅与换层是**幂等**的:重复 subscribe 同一条 track 等价于换层。
16
+ */
17
+ /** RoomState 是房间连接状态。 */
18
+ export type RoomState = 'idle' | 'joining' | 'joined' | 'leaving' | 'reconnecting';
19
+ /** PublishState 是一条本端 Track 的发布状态。 */
20
+ export type PublishState = 'publishing' | 'published' | 'unpublishing';
21
+ /** SubscribeState 是一条远端 Track 的订阅状态。 */
22
+ export type SubscribeState = 'subscribing' | 'subscribed' | 'unsubscribing';
23
+ /** RemoteTrack 是远端 Track 的本地记账。 */
24
+ export interface RemoteTrack {
25
+ readonly uid: string;
26
+ readonly kind: TrackKind;
27
+ readonly participantId: string;
28
+ }
29
+ /** RoomContext 是房间状态机持有的全部数据。 */
30
+ export interface RoomContext {
31
+ readonly state: RoomState;
32
+ readonly roomId: string;
33
+ readonly roomToken: string;
34
+ readonly participantId: string;
35
+ readonly autoSubscribe: boolean;
36
+ /** cid → 发布状态。用 cid 而不是 track_id:发布请求发出时还没有 track_id。 */
37
+ readonly publish: Readonly<Record<string, PublishState>>;
38
+ /** cid → 服务端分配的 track_id。 */
39
+ readonly publishTrackIds: Readonly<Record<string, string>>;
40
+ /** track_id → 订阅状态。 */
41
+ readonly subscribe: Readonly<Record<string, SubscribeState>>;
42
+ /** track_id → 远端 Track 记账。`track_unpublished` 帧不带 kind,只能靠它。 */
43
+ readonly remoteTracks: Readonly<Record<string, RemoteTrack>>;
44
+ /** 期望的最高层。track_id → layer。 */
45
+ readonly layers: Readonly<Record<string, Layer>>;
46
+ /** joining / reconnecting 期间缓存的用户意图(不变量 R2)。 */
47
+ readonly buffered: readonly BufferedIntent[];
48
+ /**
49
+ * 这个房间**真的收到过 `room.join.ok`** 吗。
50
+ *
51
+ * 只有它能区分 `reconnecting` 的两种来路:从 `joined` 断的(服务端那边成员关系还在,
52
+ * 恢复后直接回 `joined`),还是从 `joining` 断的(`room.join` 还在飞,服务端从没受理过)。
53
+ * 少了它,{@link resumeRoom} 会把后者也宣布成 `joined`。
54
+ *
55
+ * **不进一致性向量**:向量只断言 `room` / `publish` / `subscribe` 那几个键,
56
+ * 这是本端为了分辨来路自己记的账。四端同一份(iOS / Android 的 `didJoin`)。
57
+ */
58
+ readonly didJoin: boolean;
59
+ }
60
+ /**
61
+ * BufferedIntent 是攒下来的一次调用,**存的是意图不是帧**。
62
+ *
63
+ * 存帧的话重放时只能原样发出去,状态(比如 `publish[cid]='publishing'`)就漏掉了;
64
+ * 存意图则可以在 joined 态重新走一遍正常路径,跟没缓存过一模一样。
65
+ */
66
+ export interface BufferedIntent {
67
+ readonly op: string;
68
+ readonly args: Readonly<Record<string, unknown>>;
69
+ }
70
+ /** initialRoomContext 是 idle 态的初值。 */
71
+ export declare const initialRoomContext: RoomContext;
72
+ /** roomOut 构造一次状态转移的产物。roomRecv.ts 也用它。 */
73
+ export declare function roomOut(state: RoomContext, send?: OutgoingFrame[], emit?: EmittedEvent[]): MachineOutput<RoomContext>;
74
+ /** clearedRoom 把房间相关的记账全部清空,但保留 state 由调用方决定。 */
75
+ export declare function clearedRoom(state: RoomState): RoomContext;
76
+ /** reduceRoom 是房间状态机的唯一入口。 */
77
+ export declare function reduceRoom(ctx: RoomContext, input: MachineInput): MachineOutput<RoomContext>;
78
+ /**
79
+ * resumeRoom 在重连成功后恢复房间:重放缓存的用户意图。
80
+ *
81
+ * `resumed=false` 时**必须回到 idle 并重新 join**(协议 §1.4)——
82
+ * 服务端那边的成员关系已经过期了,装作还在只会让 UI 撒谎。
83
+ */
84
+ export declare function resumeRoom(ctx: RoomContext, resumed: boolean): MachineOutput<RoomContext>;
85
+ /**
86
+ * replayBuffered 在 joined 态把攒下的意图重新走一遍。
87
+ *
88
+ * **重放走的是正常路径**(reduceRoomAct),不是把缓存的帧直接吐出去——
89
+ * 这样状态更新与帧生成永远一致,不会出现「帧发了但本地记账没跟上」。
90
+ */
91
+ export declare function replayBuffered(ctx: RoomContext): MachineOutput<RoomContext>;
92
+ //# sourceMappingURL=roomMachine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roomMachine.d.ts","sourceRoot":"","sources":["../../src/state/roomMachine.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAG9D,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3F;;;;;;;;;;;;;GAaG;AAEH,yBAAyB;AACzB,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,cAAc,CAAC;AAEnF,sCAAsC;AACtC,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc,CAAC;AAEvE,wCAAwC;AACxC,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG,YAAY,GAAG,eAAe,CAAC;AAE5E,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACzD,6BAA6B;IAC7B,QAAQ,CAAC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3D,uBAAuB;IACvB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAC7D,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC7D,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACjD,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C;;;;;;;;;OASG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAClD;AAED,sCAAsC;AACtC,eAAO,MAAM,kBAAkB,EAAE,WAahC,CAAC;AAEF,2CAA2C;AAC3C,wBAAgB,OAAO,CACrB,KAAK,EAAE,WAAW,EAClB,IAAI,GAAE,aAAa,EAAO,EAC1B,IAAI,GAAE,YAAY,EAAO,GACxB,aAAa,CAAC,WAAW,CAAC,CAE5B;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAEzD;AAED,8BAA8B;AAC9B,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,GAAG,aAAa,CAAC,WAAW,CAAC,CAS5F;AA8ED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAKzF;AA+BD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,CAa3E"}
@@ -0,0 +1,319 @@
1
+ import { ErrorCode, errorName } from '../errors.js';
2
+ import { FrameType } from '../signaling/registry.js';
3
+ import { reduceRoomRecv } from './roomRecv.js';
4
+ import { bool, str } from './types.js';
5
+ /** initialRoomContext 是 idle 态的初值。 */
6
+ export const initialRoomContext = {
7
+ state: 'idle',
8
+ roomId: '',
9
+ roomToken: '',
10
+ participantId: '',
11
+ autoSubscribe: true,
12
+ publish: {},
13
+ publishTrackIds: {},
14
+ subscribe: {},
15
+ remoteTracks: {},
16
+ layers: {},
17
+ buffered: [],
18
+ didJoin: false,
19
+ };
20
+ /** roomOut 构造一次状态转移的产物。roomRecv.ts 也用它。 */
21
+ export function roomOut(state, send = [], emit = []) {
22
+ return { state, send, emit };
23
+ }
24
+ /** clearedRoom 把房间相关的记账全部清空,但保留 state 由调用方决定。 */
25
+ export function clearedRoom(state) {
26
+ return { ...initialRoomContext, state };
27
+ }
28
+ /** reduceRoom 是房间状态机的唯一入口。 */
29
+ export function reduceRoom(ctx, input) {
30
+ switch (input.kind) {
31
+ case 'act':
32
+ return reduceRoomAct(ctx, input.op, input.args ?? {});
33
+ case 'recv':
34
+ return reduceRoomRecv(ctx, input.type, input.data);
35
+ case 'internal':
36
+ return reduceRoomInternal(ctx, input.name, input.args ?? {});
37
+ }
38
+ }
39
+ function reduceRoomInternal(ctx, name, args) {
40
+ switch (name) {
41
+ case 'disconnected':
42
+ // 断线**不等于**离房:协议给了 30 秒恢复窗口,房内其他人这时还看得见我们。
43
+ return ctx.state === 'idle' ? roomOut(ctx) : roomOut({ ...ctx, state: 'reconnecting' });
44
+ case 'ws_closed_4403':
45
+ case 'reset':
46
+ return roomOut(clearedRoom('idle'));
47
+ case 'join_failed':
48
+ /*
49
+ 进房被拒(房间没了、票过期、已在房里…)。**退回 idle**,否则状态机
50
+ 永远停在 joining,之后每次 publish 都被 R1 本地拒成 2005。
51
+
52
+ **还要抛 `onRoomLeft`**:只清状态的话宿主什么都不知道,会议界面会一直停在
53
+ 「正在进入会议…」——和「呼叫被拒却不回 idle」是同一类毛病,
54
+ 界面需要一个明确的收场信号。房间的收场信号就是这一条。
55
+ */
56
+ return ctx.state === 'joining'
57
+ ? roomOut(clearedRoom('idle'), [], [{ cb: 'onRoomLeft', args: { room_id: ctx.roomId } }])
58
+ : roomOut(ctx);
59
+ case 'leave_failed':
60
+ /*
61
+ 离房被拒(1203 未在房间里、1201 房间没了…)。**照样当离成功收场**——
62
+ 服务端回 1203 恰恰说明我们已经不在房里了,本地再挂着毫无意义。
63
+
64
+ 不接这一条的后果比进房失败更重:房间永久停在 `leaving`,`onRoomLeft` 抛不出去,
65
+ 于是 engine 那边的 `LEAVE_CALLBACKS` 不命中、媒体面不归零,**摄像头指示灯一直亮**;
66
+ 而之后每次 join / leave 都被 R1 本地拒成 2005,除非 logout 否则再也进不了房。
67
+ */
68
+ return ctx.state === 'leaving'
69
+ ? roomOut(clearedRoom('idle'), [], [{ cb: 'onRoomLeft', args: { room_id: ctx.roomId } }])
70
+ : roomOut(ctx);
71
+ case 'publish_failed':
72
+ return dropFailedPublish(ctx, str(args, 'cid'));
73
+ case 'subscribe_failed':
74
+ return dropFailedSubscribe(ctx, str(args, 'track_id'));
75
+ default:
76
+ return roomOut(ctx);
77
+ }
78
+ }
79
+ /**
80
+ * dropFailedPublish:`room.publish` 被拒(或没送到)时把那条 `publishing` 摘掉(静默失败审计 §A)。
81
+ *
82
+ * 不摘的话它永远停在 `publishing`:`publish.ok` 不会来,pub offer 永远不产出。
83
+ * **通话里走不到这里**——帧循环直接把整通强制收场(reason=error),因为推不上去的那一端
84
+ * 对方全程听不见看不见,留在通话里只是一块撒谎的界面。这里只管没有通话的会议房。
85
+ * 错误本身由帧循环先抛过了,这里不再重复抛。
86
+ */
87
+ function dropFailedPublish(ctx, cid) {
88
+ if (ctx.publish[cid] !== 'publishing')
89
+ return roomOut(ctx);
90
+ const publish = { ...ctx.publish };
91
+ delete publish[cid];
92
+ return roomOut({ ...ctx, publish });
93
+ }
94
+ /**
95
+ * dropFailedSubscribe:`room.subscribe` 被拒时把那条 `subscribing` 连同层记账摘掉。
96
+ *
97
+ * 不摘的话不变量 R3 会把之后的每次重订都当成「已经订过、只换层」,
98
+ * 只发 `room.update_layer`,**再也发不出 `room.subscribe`**。最常见的来路是 1301:
99
+ * 订阅与对方的 `track_unpublished` 赛跑输了,此时摘掉正是实情。
100
+ */
101
+ function dropFailedSubscribe(ctx, trackId) {
102
+ if (ctx.subscribe[trackId] !== 'subscribing')
103
+ return roomOut(ctx);
104
+ const subscribe = { ...ctx.subscribe };
105
+ const layers = { ...ctx.layers };
106
+ delete subscribe[trackId];
107
+ delete layers[trackId];
108
+ return roomOut({ ...ctx, subscribe, layers });
109
+ }
110
+ /**
111
+ * resumeRoom 在重连成功后恢复房间:重放缓存的用户意图。
112
+ *
113
+ * `resumed=false` 时**必须回到 idle 并重新 join**(协议 §1.4)——
114
+ * 服务端那边的成员关系已经过期了,装作还在只会让 UI 撒谎。
115
+ */
116
+ export function resumeRoom(ctx, resumed) {
117
+ if (!resumed)
118
+ return roomOut(clearedRoom('idle'));
119
+ if (ctx.state !== 'reconnecting')
120
+ return roomOut(ctx);
121
+ if (!ctx.didJoin)
122
+ return rejoin(ctx);
123
+ return replayBuffered({ ...ctx, state: 'joined' });
124
+ }
125
+ /**
126
+ * rejoin 把「进房还没落地就断了」的那一轮**重发一遍**。
127
+ *
128
+ * `disconnected` 会把**任何**非 idle 状态推进 `reconnecting`,`joining` 也在内。
129
+ * 而从 `joining` 断的那一种,`room.join` 当时还在飞:服务端从没受理过我们,
130
+ * 恢复的只是那条 WS 会话,**不是房间成员关系**。原先无条件宣布 `joined`,
131
+ * 于是本端以为自己在房里,之后每一帧都换回 1201/1203,
132
+ * 而重新 join 又因为「不在 idle」被本地拒成 2005——一个哑掉的死局。
133
+ *
134
+ * **本端踩得比另外两端更稳**:`handleClose` 是**同步**调 `onDisconnected` 的,
135
+ * 而 `dispatch` 头一行就同步 reduce;`rejectAll` 触发的 `join_failed` 只能等微任务。
136
+ * 所以 `disconnected` **每次都赢**,那条本该兜住它的 `join_failed` 必定变成空操作
137
+ * (它 guard 在 `joining` 上,而状态早被推走了)。iOS 那边是竞态,这里是稳定复现。
138
+ *
139
+ * 所以判据改成认 {@link RoomContext.didJoin} 这笔账,**不认时序**。
140
+ * 房号与房票都还在手上,该做的正是把那次没落地的进房重来一遍;
141
+ * 攒下的意图照旧留着,等进房后再重放。
142
+ */
143
+ function rejoin(ctx) {
144
+ // 连房号都没有(`join` 的帧还没产出就断了):没得重发,干净地回 idle。
145
+ if (ctx.roomId === '')
146
+ return roomOut(clearedRoom('idle'));
147
+ return roomOut({ ...ctx, state: 'joining' }, [
148
+ {
149
+ type: FrameType.roomJoin,
150
+ data: { room_id: ctx.roomId, room_token: ctx.roomToken, auto_subscribe: ctx.autoSubscribe },
151
+ },
152
+ ]);
153
+ }
154
+ /**
155
+ * replayBuffered 在 joined 态把攒下的意图重新走一遍。
156
+ *
157
+ * **重放走的是正常路径**(reduceRoomAct),不是把缓存的帧直接吐出去——
158
+ * 这样状态更新与帧生成永远一致,不会出现「帧发了但本地记账没跟上」。
159
+ */
160
+ export function replayBuffered(ctx) {
161
+ if (ctx.buffered.length === 0)
162
+ return roomOut(ctx);
163
+ let state = { ...ctx, buffered: [] };
164
+ const send = [];
165
+ const emit = [];
166
+ for (const intent of ctx.buffered) {
167
+ const result = reduceRoomAct(state, intent.op, intent.args);
168
+ state = result.state;
169
+ send.push(...result.send);
170
+ emit.push(...result.emit);
171
+ }
172
+ return roomOut(state, send, emit);
173
+ }
174
+ function reduceRoomAct(ctx, op, args) {
175
+ if (op === 'join')
176
+ return joinRoom(ctx, args);
177
+ if (op === 'leave') {
178
+ return ctx.state === 'joined'
179
+ ? roomOut({ ...ctx, state: 'leaving' }, [
180
+ { type: FrameType.roomLeave, data: { room_id: ctx.roomId } },
181
+ ])
182
+ : localReject(ctx);
183
+ }
184
+ // R1:只有 joined 才允许发布/订阅类操作。
185
+ // R2:**joining 与 reconnecting** 期间把意图缓存下来,之后重放——
186
+ // 不是丢掉,也不是发上去。这两个状态宿主都观察不到,
187
+ // 在它们上面报「状态非法」等于让宿主为一个内部细节买单。
188
+ if (ctx.state === 'joining' || ctx.state === 'reconnecting') {
189
+ return bufferIntent(ctx, op, args);
190
+ }
191
+ if (ctx.state !== 'joined')
192
+ return localReject(ctx);
193
+ switch (op) {
194
+ case 'publish':
195
+ return publishTrack(ctx, args);
196
+ case 'unpublish':
197
+ return unpublishTrack(ctx, args);
198
+ case 'mute':
199
+ return roomOut(ctx, [{ type: FrameType.roomMute, data: muteData(args) }]);
200
+ case 'subscribe':
201
+ return subscribeTrack(ctx, args);
202
+ case 'unsubscribe':
203
+ return unsubscribeTrack(ctx, args);
204
+ case 'update_layer':
205
+ return updateLayer(ctx, args);
206
+ /*
207
+ 上行那条 PC 断了,重新 offer 一次把 ICE 打回来(媒体层已经把 restart 位置好了)。
208
+ **不进 BUFFERABLE_OPS**:这是「此刻网断了」的即时反应,等到重放的时候
209
+ 那条 PC 早就换过一轮了,补发一个过期的重启只会白折腾一次协商。
210
+ */
211
+ case 'restart_pub_ice':
212
+ return roomOut(ctx, [{ type: FrameType.roomOffer, data: { pc: 'pub', sdp: '' } }]);
213
+ default:
214
+ return localReject(ctx);
215
+ }
216
+ }
217
+ function joinRoom(ctx, args) {
218
+ if (ctx.state !== 'idle')
219
+ return localReject(ctx);
220
+ // auto_subscribe 默认 true——直接读 args 会把「没写」当成 false,
221
+ // 那正是协议 §2.4 点名的发送侧陷阱。
222
+ const autoSubscribe = args['auto_subscribe'] === undefined ? true : bool(args, 'auto_subscribe');
223
+ const roomId = str(args, 'room_id');
224
+ const roomToken = str(args, 'room_token');
225
+ return roomOut({ ...ctx, state: 'joining', roomId, roomToken, autoSubscribe }, [
226
+ {
227
+ type: FrameType.roomJoin,
228
+ data: { room_id: roomId, room_token: roomToken, auto_subscribe: autoSubscribe },
229
+ },
230
+ ]);
231
+ }
232
+ function publishTrack(ctx, args) {
233
+ const cid = str(args, 'cid');
234
+ return roomOut({ ...ctx, publish: { ...ctx.publish, [cid]: 'publishing' } }, [
235
+ {
236
+ type: FrameType.roomPublish,
237
+ data: {
238
+ cid,
239
+ kind: str(args, 'kind'),
240
+ source: str(args, 'source'),
241
+ simulcast: bool(args, 'simulcast'),
242
+ },
243
+ },
244
+ ]);
245
+ }
246
+ function unpublishTrack(ctx, args) {
247
+ const trackId = str(args, 'track_id');
248
+ const cid = cidOfTrack(ctx, trackId);
249
+ const publish = { ...ctx.publish };
250
+ if (cid !== undefined)
251
+ publish[cid] = 'unpublishing';
252
+ return roomOut({ ...ctx, publish }, [
253
+ { type: FrameType.roomUnpublish, data: { track_id: trackId } },
254
+ ]);
255
+ }
256
+ /**
257
+ * subscribeTrack:**重复订阅等价于换层**(不变量 R3)。
258
+ *
259
+ * 客户端的订阅与服务端的 `track_unpublished` 天然会赛跑,所以这条路径必须幂等。
260
+ */
261
+ function subscribeTrack(ctx, args) {
262
+ const trackId = str(args, 'track_id');
263
+ const maxLayer = (str(args, 'max_layer') || 'm');
264
+ if (ctx.subscribe[trackId] !== undefined) {
265
+ return roomOut({ ...ctx, layers: { ...ctx.layers, [trackId]: maxLayer } }, [
266
+ { type: FrameType.roomUpdateLayer, data: { track_id: trackId, max_layer: maxLayer } },
267
+ ]);
268
+ }
269
+ return roomOut({
270
+ ...ctx,
271
+ subscribe: { ...ctx.subscribe, [trackId]: 'subscribing' },
272
+ layers: { ...ctx.layers, [trackId]: maxLayer },
273
+ }, [{ type: FrameType.roomSubscribe, data: { track_id: trackId, max_layer: maxLayer } }]);
274
+ }
275
+ function unsubscribeTrack(ctx, args) {
276
+ const trackId = str(args, 'track_id');
277
+ return roomOut({ ...ctx, subscribe: { ...ctx.subscribe, [trackId]: 'unsubscribing' } }, [
278
+ { type: FrameType.roomUnsubscribe, data: { track_id: trackId } },
279
+ ]);
280
+ }
281
+ function updateLayer(ctx, args) {
282
+ const trackId = str(args, 'track_id');
283
+ const maxLayer = (str(args, 'max_layer') || 'm');
284
+ return roomOut({ ...ctx, layers: { ...ctx.layers, [trackId]: maxLayer } }, [
285
+ { type: FrameType.roomUpdateLayer, data: { track_id: trackId, max_layer: maxLayer } },
286
+ ]);
287
+ }
288
+ /** BUFFERABLE_OPS 是值得攒下来重放的操作——正好是 R1 管的那一组。 */
289
+ const BUFFERABLE_OPS = new Set([
290
+ 'publish',
291
+ 'unpublish',
292
+ 'mute',
293
+ 'subscribe',
294
+ 'unsubscribe',
295
+ 'update_layer',
296
+ ]);
297
+ /** bufferIntent 把中间态期间的用户意图缓存起来(不变量 R2)。 */
298
+ function bufferIntent(ctx, op, args) {
299
+ // 不认识的 op 照旧本地拒绝:缓存的是**合法但来早了**的调用,不是笔误。
300
+ if (!BUFFERABLE_OPS.has(op))
301
+ return localReject(ctx);
302
+ return roomOut({ ...ctx, buffered: [...ctx.buffered, { op, args }] });
303
+ }
304
+ function muteData(args) {
305
+ return { track_id: str(args, 'track_id'), muted: bool(args, 'muted') };
306
+ }
307
+ function cidOfTrack(ctx, trackId) {
308
+ return Object.entries(ctx.publishTrackIds).find(([, id]) => id === trackId)?.[0];
309
+ }
310
+ /** localReject 是不变量 R1 的落点:错误状态下的调用**本地拒绝**,不发上去。 */
311
+ function localReject(ctx) {
312
+ return roomOut(ctx, [], [
313
+ {
314
+ cb: 'onError',
315
+ args: { code: ErrorCode.invalidState, name: errorName(ErrorCode.invalidState) },
316
+ },
317
+ ]);
318
+ }
319
+ //# sourceMappingURL=roomMachine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roomMachine.js","sourceRoot":"","sources":["../../src/state/roomMachine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PublishState, RoomContext } from './roomMachine.js';
2
+ import type { MachineOutput } from './types.js';
3
+ /** reduceRoomRecv 处理一条下行房间帧。 */
4
+ export declare function reduceRoomRecv(ctx: RoomContext, type: string, data: Readonly<Record<string, unknown>>): MachineOutput<RoomContext>;
5
+ /** publishStateOf 供测试与诊断读取某个 cid 的发布状态。 */
6
+ export declare function publishStateOf(ctx: RoomContext, cid: string): PublishState | undefined;
7
+ //# sourceMappingURL=roomRecv.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roomRecv.d.ts","sourceRoot":"","sources":["../../src/state/roomRecv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAe,WAAW,EAAkB,MAAM,kBAAkB,CAAC;AAE/F,OAAO,KAAK,EAAgB,aAAa,EAAiB,MAAM,YAAY,CAAC;AAgB7E,gCAAgC;AAChC,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,aAAa,CAAC,WAAW,CAAC,CA6C5B;AA0MD,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEtF"}