@softtynet/zca-js 2.3.4 → 2.3.5

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 (123) hide show
  1. package/README.md +47 -11
  2. package/dist/apis/call/addUserGroupCall.d.ts +11 -0
  3. package/dist/apis/call/addUserGroupCall.js +48 -0
  4. package/dist/apis/call/answerAckVoiceCall.d.ts +5 -0
  5. package/dist/apis/call/answerAckVoiceCall.js +38 -0
  6. package/dist/apis/call/answerGroupCall.d.ts +10 -0
  7. package/dist/apis/call/answerGroupCall.js +45 -0
  8. package/dist/apis/call/answerVoiceCall.d.ts +11 -0
  9. package/dist/apis/call/answerVoiceCall.js +50 -0
  10. package/dist/apis/call/broadcastGroupCallState.d.ts +10 -0
  11. package/dist/apis/call/broadcastGroupCallState.js +45 -0
  12. package/dist/apis/call/cancelGroupCall.d.ts +10 -0
  13. package/dist/apis/call/cancelGroupCall.js +45 -0
  14. package/dist/apis/call/cancelVoiceCall.d.ts +1 -1
  15. package/dist/apis/call/cancelVoiceCall.js +5 -1
  16. package/dist/apis/call/createController.d.ts +7 -0
  17. package/dist/apis/call/createController.js +9 -0
  18. package/dist/apis/call/createRtcSession.d.ts +8 -0
  19. package/dist/apis/call/createRtcSession.js +10 -0
  20. package/dist/apis/call/endGroupCall.d.ts +10 -0
  21. package/dist/apis/call/endGroupCall.js +45 -0
  22. package/dist/apis/call/finishGroupCall.d.ts +12 -0
  23. package/dist/apis/call/finishGroupCall.js +47 -0
  24. package/dist/apis/call/getGroupCallState.d.ts +3 -0
  25. package/dist/apis/call/getGroupCallState.js +38 -0
  26. package/dist/apis/call/holdVoiceCall.d.ts +5 -0
  27. package/dist/apis/call/holdVoiceCall.js +34 -0
  28. package/dist/apis/call/joinGroupCall.d.ts +11 -0
  29. package/dist/apis/call/joinGroupCall.js +46 -0
  30. package/dist/apis/call/logEndVoiceCall.d.ts +8 -0
  31. package/dist/apis/call/logEndVoiceCall.js +46 -0
  32. package/dist/apis/call/notifyGroupCall.d.ts +9 -0
  33. package/dist/apis/call/notifyGroupCall.js +44 -0
  34. package/dist/apis/call/pingGroupCall.d.ts +10 -0
  35. package/dist/apis/call/pingGroupCall.js +45 -0
  36. package/dist/apis/call/requestAudioToVideoCall.d.ts +5 -0
  37. package/dist/apis/call/requestAudioToVideoCall.js +37 -0
  38. package/dist/apis/call/requestGroupCall.d.ts +9 -0
  39. package/dist/apis/call/requestGroupCall.js +46 -0
  40. package/dist/apis/call/requestShareScreenCall.d.ts +5 -0
  41. package/dist/apis/call/requestShareScreenCall.js +37 -0
  42. package/dist/apis/call/requestVoiceCall.d.ts +10 -0
  43. package/dist/apis/call/requestVoiceCall.js +47 -0
  44. package/dist/apis/call/ringRingGroupCall.d.ts +10 -0
  45. package/dist/apis/call/ringRingGroupCall.js +45 -0
  46. package/dist/apis/call/ringRingVoiceCall.d.ts +5 -0
  47. package/dist/apis/call/ringRingVoiceCall.js +38 -0
  48. package/dist/apis/call/sendRequestGroupCall.d.ts +11 -0
  49. package/dist/apis/call/sendRequestGroupCall.js +48 -0
  50. package/dist/apis/call/sendRequestVoiceCall.d.ts +11 -0
  51. package/dist/apis/call/sendRequestVoiceCall.js +51 -0
  52. package/dist/apis/call/sendVoiceCall.d.ts +8 -1
  53. package/dist/apis/call/sendVoiceCall.js +10 -8
  54. package/dist/apis/call/shareScreenGroupCall.d.ts +10 -0
  55. package/dist/apis/call/shareScreenGroupCall.js +45 -0
  56. package/dist/apis/call/unholdVoiceCall.d.ts +5 -0
  57. package/dist/apis/call/unholdVoiceCall.js +34 -0
  58. package/dist/apis/call/updateCallMediaState.d.ts +7 -0
  59. package/dist/apis/call/updateCallMediaState.js +61 -0
  60. package/dist/apis.d.ts +81 -0
  61. package/dist/apis.js +135 -0
  62. package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
  63. package/dist/call-engine/ZRTPPacketCodec.js +506 -0
  64. package/dist/call-engine/ZaloCallController.d.ts +134 -0
  65. package/dist/call-engine/ZaloCallController.js +638 -0
  66. package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
  67. package/dist/call-engine/ZaloCallTransport.js +233 -0
  68. package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
  69. package/dist/call-engine/ZaloRtcSession.js +2931 -0
  70. package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
  71. package/dist/call-engine/ZaloSrtpSession.js +278 -0
  72. package/dist/call-engine/index.d.ts +18 -0
  73. package/dist/call-engine/index.js +24 -0
  74. package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
  75. package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
  76. package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
  77. package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
  78. package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
  79. package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
  80. package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
  81. package/dist/cjs/apis/call/createController.cjs +14 -0
  82. package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
  83. package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
  84. package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
  85. package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
  86. package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
  87. package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
  88. package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
  89. package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
  90. package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
  91. package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
  92. package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
  93. package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
  94. package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
  95. package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
  96. package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
  97. package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
  98. package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
  99. package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
  100. package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
  101. package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
  102. package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
  103. package/dist/cjs/apis.cjs +135 -0
  104. package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
  105. package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
  106. package/dist/cjs/call-engine/ZaloCallTransport.cjs +239 -0
  107. package/dist/cjs/call-engine/ZaloRtcSession.cjs +2937 -0
  108. package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
  109. package/dist/cjs/constants/protocol.cjs +1 -1
  110. package/dist/cjs/index.cjs +61 -11
  111. package/dist/cjs/models/CallEvent.cjs +95 -1
  112. package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
  113. package/dist/cjs/realtime/listener.cjs +19 -0
  114. package/dist/constants/protocol.d.ts +1 -1
  115. package/dist/constants/protocol.js +1 -1
  116. package/dist/index.d.ts +32 -4
  117. package/dist/index.js +2 -0
  118. package/dist/models/CallEvent.d.ts +15 -0
  119. package/dist/models/CallEvent.js +95 -1
  120. package/dist/realtime/handlers/control.handler.js +17 -3
  121. package/dist/realtime/listener.d.ts +5 -0
  122. package/dist/realtime/listener.js +19 -0
  123. package/package.json +2 -1
@@ -0,0 +1,525 @@
1
+ 'use strict';
2
+
3
+ var node_buffer = require('node:buffer');
4
+
5
+ /**
6
+ * Các mã lệnh điều khiển UDP trong `zrtc::ZRTPPacket` (`_buildPacketInternal` @ `0x10015830c`)
7
+ */
8
+ exports.ZRTPControlCommand = void 0;
9
+ (function (ZRTPControlCommand) {
10
+ ZRTPControlCommand[ZRTPControlCommand["RelayPing"] = 2] = "RelayPing";
11
+ ZRTPControlCommand[ZRTPControlCommand["EndCall"] = 3] = "EndCall";
12
+ ZRTPControlCommand[ZRTPControlCommand["Ping"] = 5] = "Ping";
13
+ ZRTPControlCommand[ZRTPControlCommand["InitCallCaller"] = 11] = "InitCallCaller";
14
+ ZRTPControlCommand[ZRTPControlCommand["InitCallCallee"] = 12] = "InitCallCallee";
15
+ ZRTPControlCommand[ZRTPControlCommand["RequestForward"] = 32] = "RequestForward";
16
+ ZRTPControlCommand[ZRTPControlCommand["InitZaviPing"] = 51] = "InitZaviPing";
17
+ })(exports.ZRTPControlCommand || (exports.ZRTPControlCommand = {}));
18
+ /**
19
+ * Sub-command cho gói tin điều khiển `RequestForward` (`cmd = 32` / `0x0020`, `byte[20]`)
20
+ * dùng để Ping/Pong kiểm tra kết nối 2 chiều qua máy chủ Relay và điều khiển Audio/Video.
21
+ */
22
+ exports.ZRTPForwardSubCommand = void 0;
23
+ (function (ZRTPForwardSubCommand) {
24
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["OnMic"] = 5] = "OnMic";
25
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["OffMic"] = 6] = "OffMic";
26
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["OnCamera"] = 7] = "OnCamera";
27
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["OffCamera"] = 8] = "OffCamera";
28
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["OffCameraCallKit"] = 9] = "OffCameraCallKit";
29
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["VideoControl"] = 10] = "VideoControl";
30
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["Ping"] = 11] = "Ping";
31
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["Pong"] = 16] = "Pong";
32
+ ZRTPForwardSubCommand[ZRTPForwardSubCommand["PartnerSuspendVideo"] = 17] = "PartnerSuspendVideo";
33
+ })(exports.ZRTPForwardSubCommand || (exports.ZRTPForwardSubCommand = {}));
34
+ /**
35
+ * Loại gói tin Media qua máy chủ Relay:
36
+ * - Gửi đi (5-byte header `[type(1B)] + [routingToken(4B LE)] + [RTP/RTCP]`): `{3, 5, 7, 13, 15}`
37
+ * - Nhận về từ Relay (1-byte header `[type(1B)] + [RTP]`): `{4, 7, 14}`
38
+ * - Nhận về RTCP từ Relay (5-byte header `[type(1B)] + [routingToken(4B LE)] + [RTCP]`): `{5, 15}`
39
+ */
40
+ exports.ZRTPLegacyMediaType = void 0;
41
+ (function (ZRTPLegacyMediaType) {
42
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["AudioRtp"] = 3] = "AudioRtp";
43
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["IncomingAudioRtp"] = 4] = "IncomingAudioRtp";
44
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["AudioRtcp"] = 5] = "AudioRtcp";
45
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["AudioFec"] = 7] = "AudioFec";
46
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["VideoRtp"] = 13] = "VideoRtp";
47
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["IncomingVideoRtp"] = 14] = "IncomingVideoRtp";
48
+ ZRTPLegacyMediaType[ZRTPLegacyMediaType["VideoRtcp"] = 15] = "VideoRtcp";
49
+ })(exports.ZRTPLegacyMediaType || (exports.ZRTPLegacyMediaType = {}));
50
+ /**
51
+ * Sub-command cho gói tin ZRTC Multiplexed Media (`byte[0] == 0x7f`, 9-byte header)
52
+ */
53
+ exports.ZRTCMediaSubCommand = void 0;
54
+ (function (ZRTCMediaSubCommand) {
55
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["P2PPingRequest"] = 1] = "P2PPingRequest";
56
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["P2PPingResponse"] = 2] = "P2PPingResponse";
57
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["P2PInitCaller"] = 3] = "P2PInitCaller";
58
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["P2PInitCallee"] = 4] = "P2PInitCallee";
59
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["AudioRtp"] = 6] = "AudioRtp";
60
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["AudioRtcp"] = 7] = "AudioRtcp";
61
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["VideoRtp"] = 8] = "VideoRtp";
62
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["VideoRtcp"] = 9] = "VideoRtcp";
63
+ ZRTCMediaSubCommand[ZRTCMediaSubCommand["AudioFec"] = 10] = "AudioFec";
64
+ })(exports.ZRTCMediaSubCommand || (exports.ZRTCMediaSubCommand = {}));
65
+ exports.ZRTCRole = void 0;
66
+ (function (ZRTCRole) {
67
+ ZRTCRole[ZRTCRole["Caller"] = 0] = "Caller";
68
+ ZRTCRole[ZRTCRole["Callee"] = 1] = "Callee";
69
+ })(exports.ZRTCRole || (exports.ZRTCRole = {}));
70
+ /**
71
+ * Chuỗi codec Opus chuẩn được `ZaloCall` tạo trong `sendSignal 416`
72
+ */
73
+ const DEFAULT_ZALO_AUDIO_CODEC = JSON.stringify([
74
+ {
75
+ dynamicFptime: 0,
76
+ frmPtime: 20,
77
+ name: "opus/16000/1",
78
+ payload: 112,
79
+ },
80
+ ]);
81
+ /**
82
+ * Chuỗi codec Audio + Video H264 chuẩn cho cuộc gọi Video
83
+ */
84
+ const DEFAULT_ZALO_VIDEO_CODEC = JSON.stringify([
85
+ {
86
+ dynamicFptime: 0,
87
+ frmPtime: 20,
88
+ name: "opus/16000/1",
89
+ payload: 112,
90
+ },
91
+ ]);
92
+ /**
93
+ * Tạo cấu trúc `extendData` chuẩn xác theo `ZaloCall` (`sendSignal 416` / `answer 402`).
94
+ */
95
+ function buildZrtcExtendData(options) {
96
+ const rtp = options.rtpAddress;
97
+ const rtcp = options.rtcpAddress || options.rtpAddress;
98
+ const isVideo = Boolean(options.isVideo);
99
+ const extend = {
100
+ callType: isVideo ? 1 : 0,
101
+ fecTP: 0,
102
+ gccAudio: 0,
103
+ gccEarlyCall: 0,
104
+ gccMode: 0,
105
+ gccSVLR: 0,
106
+ maxFT: 120,
107
+ newZrtc: 1,
108
+ packetMode: options.packetMode ?? 2,
109
+ platform: options.platform ?? 2,
110
+ sP2P: 0,
111
+ serverAddr: [
112
+ {
113
+ rtcp,
114
+ rtcpIPv6: `::FFFF:${rtcp}`,
115
+ rtp,
116
+ rtpIPv6: `::FFFF:${rtp}`,
117
+ tpType: 0,
118
+ },
119
+ ],
120
+ spTcp: 0,
121
+ srtcp: 0,
122
+ srtpMode: options.srtpMode ?? 0,
123
+ supportCallBusy: 0,
124
+ supportHevcDecode: 0,
125
+ tpType: 0,
126
+ };
127
+ if (options.srtpKey) {
128
+ extend.srtpKey = options.srtpKey;
129
+ }
130
+ // Khớp với CallController::getExtendData (0x10016871c): luôn đính kèm danh sách codec video
131
+ // để phiên gọi có thể nâng cấp Thoại ➔ Video hoặc bật/tắt Camera giữa cuộc gọi.
132
+ extend.video = {
133
+ codec: [{ name: "h264", payload: 97 }],
134
+ };
135
+ return extend;
136
+ }
137
+ /**
138
+ * Rút gọn UID 64-bit dạng chuỗi của Zalo về `uint32` dùng trong header `ZRTPPacket`
139
+ */
140
+ function uidToUint32(uid) {
141
+ if (uid === undefined || uid === null || uid === "")
142
+ return 0;
143
+ if (typeof uid === "number")
144
+ return uid >>> 0;
145
+ try {
146
+ return Number(BigInt(uid) & 0xffffffffn) >>> 0;
147
+ }
148
+ catch {
149
+ return (Number.parseInt(uid, 10) || 0) >>> 0;
150
+ }
151
+ }
152
+ function writeControlHeader(buf, packetType, subType, seqNum, headerCallId, fromUid, toUid, cmd, flags) {
153
+ buf.writeUInt8(packetType, 0);
154
+ buf.writeUInt8(subType & 0xff, 1);
155
+ buf.writeUInt32LE(seqNum >>> 0, 2);
156
+ buf.writeUInt32LE(headerCallId >>> 0, 6);
157
+ buf.writeUInt32LE(fromUid >>> 0, 10);
158
+ buf.writeUInt32LE(toUid >>> 0, 14);
159
+ buf.writeUInt16LE(cmd & 0xffff, 18);
160
+ buf.writeUInt8(flags & 0xff, 20);
161
+ }
162
+ /**
163
+ * Đóng gói gói tin UDP `InitCall` (`0x01 0x7e`, `cmd = 11` cho Caller hoặc `12` cho Callee)
164
+ * gửi tới máy chủ `rtpaddr` của Zalo (`zrtc::ZRTPPacket::_buildPacketInternal` @ `0x10015830c`).
165
+ */
166
+ function buildInitCallRequest(options) {
167
+ const isCaller = options.isCaller ?? true;
168
+ const cmd = isCaller ? exports.ZRTPControlCommand.InitCallCaller : exports.ZRTPControlCommand.InitCallCallee;
169
+ const seqNum = options.seqNum ?? 0;
170
+ const headerCallId = options.headerCallId ?? options.callId ?? 0;
171
+ const fromUid = options.fromUid ?? 0;
172
+ const toUid = options.toUid ?? 0;
173
+ const flags = options.flags ?? 1;
174
+ const subFlags = options.subFlags ?? toUid;
175
+ const sessBytes = node_buffer.Buffer.from(options.sessId, "utf-8");
176
+ const cfgBytes = options.zrtcConfig ? node_buffer.Buffer.from(options.zrtcConfig, "utf-8") : undefined;
177
+ const totalLen = 21 + 4 + 4 + 2 + sessBytes.length + (cfgBytes ? 2 + cfgBytes.length : 0);
178
+ const buf = node_buffer.Buffer.alloc(totalLen);
179
+ writeControlHeader(buf, 1, 0x7e, seqNum, headerCallId, fromUid, toUid, cmd, flags);
180
+ buf.writeUInt32LE(options.callId >>> 0, 21);
181
+ buf.writeUInt32LE(subFlags >>> 0, 25);
182
+ buf.writeUInt16LE(sessBytes.length, 29);
183
+ sessBytes.copy(buf, 31);
184
+ if (cfgBytes) {
185
+ const offset = 31 + sessBytes.length;
186
+ buf.writeUInt16LE(cfgBytes.length, offset);
187
+ cfgBytes.copy(buf, offset + 2);
188
+ }
189
+ return buf;
190
+ }
191
+ /**
192
+ * Đóng gói gói tin UDP phản hồi `InitCall` (`0x02 0x7e`, `cmd = 11 | 12`)
193
+ * khớp chính xác với `zrtc::ZRTPPacket::_parsePacketInternal` (`0x100158db8`)
194
+ * và `zrtc::CallController` (`0x100177920`).
195
+ */
196
+ function buildInitCallResponse(options) {
197
+ const isCaller = options.isCaller ?? true;
198
+ const cmd = isCaller ? exports.ZRTPControlCommand.InitCallCaller : exports.ZRTPControlCommand.InitCallCallee;
199
+ const seqNum = options.seqNum ?? 0;
200
+ const headerCallId = options.headerCallId ?? 0;
201
+ const fromUid = options.fromUid ?? 0;
202
+ const toUid = options.toUid ?? 0;
203
+ const flags = options.flags ?? 1;
204
+ const errorCode = options.errorCode ?? 0;
205
+ const routingToken = (options.routingToken >>> 0) || 1;
206
+ const sessBytes = node_buffer.Buffer.from(options.sessId, "utf-8");
207
+ const buf = node_buffer.Buffer.alloc(35 + sessBytes.length);
208
+ writeControlHeader(buf, 2, 0x7e, seqNum, headerCallId, fromUid, toUid, cmd, flags);
209
+ buf.writeUInt32LE(errorCode >>> 0, 21);
210
+ buf.writeUInt32LE(options.callId >>> 0, 25);
211
+ buf.writeUInt32LE(routingToken, 29);
212
+ buf.writeUInt16LE(sessBytes.length, 33);
213
+ sessBytes.copy(buf, 35);
214
+ return buf;
215
+ }
216
+ /**
217
+ * Đóng gói gói tin UDP `Ping` (`0x01 0x01`, `cmd = 5`) gửi định kỳ tới máy chủ relay của Zalo.
218
+ */
219
+ function buildPingRequest(options) {
220
+ const elapsedBytes = node_buffer.Buffer.from(String(options.elapsedMs), "utf-8");
221
+ const minLen = options.minByteLength ?? 40;
222
+ const rawLen = 21 + 2 + elapsedBytes.length;
223
+ const buf = node_buffer.Buffer.alloc(Math.max(rawLen, minLen));
224
+ writeControlHeader(buf, 1, 0x01, options.seqNum, options.callId, options.fromUid ?? 0, options.toUid ?? 0, exports.ZRTPControlCommand.Ping, 0x01);
225
+ buf.writeUInt16LE(elapsedBytes.length, 21);
226
+ elapsedBytes.copy(buf, 23);
227
+ return buf;
228
+ }
229
+ /**
230
+ * Đóng gói gói tin UDP phản hồi `Ping` (`0x02 0x01`, `cmd = 5`).
231
+ */
232
+ function buildPingResponse(options) {
233
+ const elapsedBytes = node_buffer.Buffer.from(String(options.elapsedMs), "utf-8");
234
+ const buf = node_buffer.Buffer.alloc(21 + 4 + 2 + elapsedBytes.length);
235
+ writeControlHeader(buf, 2, 0x01, options.seqNum, options.callId, options.fromUid ?? 0, options.toUid ?? 0, exports.ZRTPControlCommand.Ping, 0x01);
236
+ buf.writeUInt32LE((options.errorCode ?? 0) >>> 0, 21);
237
+ buf.writeUInt16LE(elapsedBytes.length, 25);
238
+ elapsedBytes.copy(buf, 27);
239
+ return buf;
240
+ }
241
+ /**
242
+ * Đóng gói gói tin UDP `RequestPing` (`0x01 0x01`, `cmd = 2`) gửi tới máy chủ Relay Zalo
243
+ * (`zrtc::ZRTPPacket::initZRTPPacketRequestPing` @ `0x100157b88`).
244
+ */
245
+ function buildRelayPingRequest(options) {
246
+ const sessBytes = node_buffer.Buffer.from(options.sessId, "utf-8");
247
+ const buf = node_buffer.Buffer.alloc(21 + 2 + sessBytes.length);
248
+ writeControlHeader(buf, 1, 0x01, options.seqNum ?? 0, options.callId ?? 0, options.fromUid >>> 0, options.routingToken >>> 0, exports.ZRTPControlCommand.RelayPing, 0x01);
249
+ buf.writeUInt16LE(sessBytes.length, 21);
250
+ sessBytes.copy(buf, 23);
251
+ return buf;
252
+ }
253
+ /**
254
+ * Đóng gói gói tin UDP `RequestForward` (`0x01 0x01`, `cmd = 32` / `0x0020`)
255
+ * dùng cho Ping (`subCmd = 11`) / Pong (`subCmd = 16`) giữa 2 đầu qua máy chủ Relay
256
+ * (`zrtc::ZRTPPacket::initZRTPPacketRequestForward` @ `0x100157c4c`).
257
+ */
258
+ function buildRequestForwardPacket(options) {
259
+ const payloadBuf = options.payload === undefined
260
+ ? node_buffer.Buffer.alloc(0)
261
+ : node_buffer.Buffer.isBuffer(options.payload)
262
+ ? options.payload
263
+ : node_buffer.Buffer.from(options.payload, "utf-8");
264
+ const buf = node_buffer.Buffer.alloc(21 + 4 + payloadBuf.length);
265
+ writeControlHeader(buf, 1, 0x01, options.seqNum ?? 0, options.seqId >>> 0, options.fromUid >>> 0, options.routingToken >>> 0, exports.ZRTPControlCommand.RequestForward, options.subCmd & 0xff);
266
+ buf.writeUInt32LE(payloadBuf.length >>> 0, 21);
267
+ if (payloadBuf.length > 0) {
268
+ payloadBuf.copy(buf, 25);
269
+ }
270
+ return buf;
271
+ }
272
+ /**
273
+ * Đóng gói gói tin UDP `Echo` (`cmd = 3`)
274
+ */
275
+ function buildEchoRequest(options) {
276
+ const buf = node_buffer.Buffer.alloc(25);
277
+ writeControlHeader(buf, 1, 0x01, options.seqNum, options.callId, options.fromUid ?? 0, options.toUid ?? 0, exports.ZRTPControlCommand.EndCall, 0x01);
278
+ buf.writeUInt32LE(options.token >>> 0, 21);
279
+ return buf;
280
+ }
281
+ /**
282
+ * Đóng gói gói tin UDP `RequestEndCall` (`0x01 0x7e`, `cmd = 3`, 25 bytes)
283
+ * khớp với `zrtc::ZRTPPacket::initZRTPPacketRequestEndCall` (`0x100157b44`)
284
+ * và `_buildPacketInternal` (`0x10015830c`).
285
+ */
286
+ function buildEndCallRequest(options) {
287
+ const buf = node_buffer.Buffer.alloc(25);
288
+ const routingOrTo = (options.routingToken ?? options.toUid ?? 0) >>> 0;
289
+ writeControlHeader(buf, 1, 0x7e, options.seqNum ?? 0, 0, options.fromUid ?? 0, routingOrTo, exports.ZRTPControlCommand.EndCall, options.flags ?? 0);
290
+ buf.writeUInt32LE(options.callId >>> 0, 21);
291
+ return buf;
292
+ }
293
+ /**
294
+ * Bọc gói tin chuẩn WebRTC RTP/RTCP/SRTP vào khung 5-byte Legacy Media của Zalo
295
+ * (`byte[0]` in `{3, 5, 7, 13, 15}` + `routingId` 4B LE).
296
+ */
297
+ function wrapLegacyMediaPacket(mediaType, routingId, rtpOrRtcpPayload) {
298
+ const out = node_buffer.Buffer.allocUnsafe(5 + rtpOrRtcpPayload.length);
299
+ out.writeUInt8(mediaType, 0);
300
+ out.writeUInt32LE(routingId >>> 0, 1);
301
+ rtpOrRtcpPayload.copy(out, 5);
302
+ return out;
303
+ }
304
+ /**
305
+ * Bọc gói tin chuẩn WebRTC RTP/RTCP/SRTP vào khung 9-byte ZRTC Multiplexed Media (`0x7f`)
306
+ * (`[0x7f, 0x00, role, routingToken(4B LE), subCmd(2B LE)] + [RTP/RTCP]`).
307
+ */
308
+ function wrapZrtcMediaPacket(subCmd, routingToken, rtpOrRtcpPayload, role = exports.ZRTCRole.Caller) {
309
+ const out = node_buffer.Buffer.allocUnsafe(9 + rtpOrRtcpPayload.length);
310
+ out.writeUInt8(0x7f, 0);
311
+ out.writeUInt8(0x00, 1);
312
+ out.writeUInt8(role & 0xff, 2);
313
+ out.writeUInt32LE(routingToken >>> 0, 3);
314
+ out.writeUInt16LE(subCmd & 0xffff, 7);
315
+ rtpOrRtcpPayload.copy(out, 9);
316
+ return out;
317
+ }
318
+ /**
319
+ * Giải mã bất kỳ gói tin UDP `ZRTPPacket` nào nhận được từ máy chủ Relay Zalo hoặc Peer
320
+ * (`zrtc::ZRTPPacket::_parsePacketInternal` @ `0x1001589e8`).
321
+ */
322
+ function parseZRTPPacket(buf) {
323
+ if (!buf || buf.length < 5) {
324
+ return { family: "raw", raw: buf ?? node_buffer.Buffer.alloc(0) };
325
+ }
326
+ const firstByte = buf.readUInt8(0);
327
+ // 1. Gói tin điều khiển / bắt tay (0x01 = Request, 0x02 = Response)
328
+ if ((firstByte === 1 || firstByte === 2) && buf.length >= 21) {
329
+ const packetType = firstByte;
330
+ const isResponse = packetType === 2;
331
+ const subType = buf.readUInt8(1);
332
+ const seqNum = buf.readUInt32LE(2);
333
+ const headerCallId = buf.readUInt32LE(6);
334
+ const fromUid = buf.readUInt32LE(10);
335
+ const toUid = buf.readUInt32LE(14);
336
+ const cmd = buf.readUInt16LE(18);
337
+ const flags = buf.readUInt8(20);
338
+ const rawBody = buf.subarray(21);
339
+ const packet = {
340
+ family: "control",
341
+ isResponse,
342
+ packetType,
343
+ subType,
344
+ seqNum,
345
+ headerCallId,
346
+ fromUid,
347
+ toUid,
348
+ cmd,
349
+ flags,
350
+ rawBody,
351
+ };
352
+ if (cmd === exports.ZRTPControlCommand.InitCallCaller || cmd === exports.ZRTPControlCommand.InitCallCallee) {
353
+ if (!isResponse && flags !== 6 && buf.length >= 31) {
354
+ packet.callId = buf.readUInt32LE(21);
355
+ packet.subFlags = buf.readUInt32LE(25);
356
+ const sessLen = buf.readUInt16LE(29);
357
+ const sessEnd = Math.min(31 + sessLen, buf.length);
358
+ packet.sessId = buf.subarray(31, sessEnd).toString("utf-8");
359
+ if (buf.length >= sessEnd + 2) {
360
+ const cfgLen = buf.readUInt16LE(sessEnd);
361
+ const cfgEnd = Math.min(sessEnd + 2 + cfgLen, buf.length);
362
+ if (cfgLen > 0) {
363
+ packet.zrtcConfig = buf.subarray(sessEnd + 2, cfgEnd).toString("utf-8");
364
+ }
365
+ }
366
+ }
367
+ else if (isResponse && buf.length >= 25) {
368
+ packet.errorCode = buf.readInt32LE(21);
369
+ if (buf.length >= 33) {
370
+ packet.callId = buf.readUInt32LE(25);
371
+ packet.routingToken = buf.readUInt32LE(29);
372
+ }
373
+ if (buf.length >= 35) {
374
+ const sessLen = buf.readUInt16LE(33);
375
+ const sessEnd = Math.min(35 + sessLen, buf.length);
376
+ packet.sessId = buf.subarray(35, sessEnd).toString("utf-8");
377
+ }
378
+ }
379
+ }
380
+ else if (cmd === exports.ZRTPControlCommand.RelayPing) {
381
+ if (!isResponse && buf.length >= 23) {
382
+ const sessLen = buf.readUInt16LE(21);
383
+ const sessEnd = Math.min(23 + sessLen, buf.length);
384
+ packet.sessId = buf.subarray(23, sessEnd).toString("utf-8");
385
+ }
386
+ else if (isResponse && buf.length >= 25) {
387
+ packet.errorCode = buf.readInt32LE(21);
388
+ if (buf.length >= 27) {
389
+ const sessLen = buf.readUInt16LE(25);
390
+ const sessEnd = Math.min(27 + sessLen, buf.length);
391
+ packet.sessId = buf.subarray(27, sessEnd).toString("utf-8");
392
+ }
393
+ }
394
+ }
395
+ else if (cmd === exports.ZRTPControlCommand.Ping) {
396
+ if (!isResponse && buf.length >= 23) {
397
+ const strLen = buf.readUInt16LE(21);
398
+ const strEnd = Math.min(23 + strLen, buf.length);
399
+ packet.pingString = buf.subarray(23, strEnd).toString("utf-8");
400
+ }
401
+ else if (isResponse && buf.length >= 25) {
402
+ packet.errorCode = buf.readUInt32LE(21);
403
+ if (buf.length >= 27) {
404
+ const strLen = buf.readUInt16LE(25);
405
+ const strEnd = Math.min(27 + strLen, buf.length);
406
+ packet.pingString = buf.subarray(27, strEnd).toString("utf-8");
407
+ }
408
+ }
409
+ }
410
+ else if (cmd === exports.ZRTPControlCommand.RequestForward) {
411
+ if (!isResponse && buf.length >= 25) {
412
+ const payloadLen = buf.readUInt32LE(21);
413
+ const payloadEnd = Math.min(25 + payloadLen, buf.length);
414
+ packet.forwardPayload = buf.subarray(25, payloadEnd);
415
+ }
416
+ else if (!isResponse) {
417
+ packet.forwardPayload = buf.subarray(21);
418
+ }
419
+ else if (isResponse && buf.length >= 25) {
420
+ packet.errorCode = buf.readInt32LE(21);
421
+ }
422
+ }
423
+ else if (cmd === exports.ZRTPControlCommand.EndCall) {
424
+ if (!isResponse && buf.length >= 25) {
425
+ const val = buf.readUInt32LE(21);
426
+ packet.callId = val;
427
+ packet.echoToken = val;
428
+ }
429
+ else if (isResponse && buf.length >= 25) {
430
+ packet.errorCode = buf.readInt32LE(21);
431
+ if (buf.length >= 29) {
432
+ packet.echoToken = buf.readUInt32LE(25);
433
+ }
434
+ }
435
+ }
436
+ return packet;
437
+ }
438
+ // 2a. Gói tin Relay Media nhận về từ máy chủ Zalo (1-byte header: type in {4, 14})
439
+ // (`zrtc::ZRTPPacket::_parsePacketInternal` @ `0x100158a1c`, mask `0x4090`)
440
+ if ((firstByte === exports.ZRTPLegacyMediaType.IncomingAudioRtp ||
441
+ firstByte === exports.ZRTPLegacyMediaType.IncomingVideoRtp) &&
442
+ buf.length >= 13) {
443
+ const mediaType = firstByte;
444
+ return {
445
+ family: "legacy_media",
446
+ mediaType,
447
+ isVideo: mediaType === exports.ZRTPLegacyMediaType.IncomingVideoRtp,
448
+ isRtcp: false,
449
+ isFec: false,
450
+ routingId: 0,
451
+ rtpPayload: buf.subarray(1),
452
+ };
453
+ }
454
+ // 2b. Gói tin Relay Media 5-byte header (`type` in `{3, 5, 7, 13, 15}` + `routingToken` 4B LE)
455
+ if (firstByte === exports.ZRTPLegacyMediaType.AudioRtp ||
456
+ firstByte === exports.ZRTPLegacyMediaType.AudioRtcp ||
457
+ firstByte === exports.ZRTPLegacyMediaType.AudioFec ||
458
+ firstByte === exports.ZRTPLegacyMediaType.VideoRtp ||
459
+ firstByte === exports.ZRTPLegacyMediaType.VideoRtcp) {
460
+ const mediaType = firstByte;
461
+ const routingId = buf.readUInt32LE(1);
462
+ return {
463
+ family: "legacy_media",
464
+ mediaType,
465
+ isVideo: mediaType === exports.ZRTPLegacyMediaType.VideoRtp || mediaType === exports.ZRTPLegacyMediaType.VideoRtcp,
466
+ isRtcp: mediaType === exports.ZRTPLegacyMediaType.AudioRtcp || mediaType === exports.ZRTPLegacyMediaType.VideoRtcp,
467
+ isFec: mediaType === exports.ZRTPLegacyMediaType.AudioFec,
468
+ routingId,
469
+ rtpPayload: buf.subarray(5),
470
+ };
471
+ }
472
+ // 3. Gói tin ZRTC Multiplexed Media / P2P (0x7f, >= 9 bytes)
473
+ if (firstByte === 0x7f && buf.length >= 9) {
474
+ const version = buf.readUInt8(1);
475
+ const role = (buf.readUInt8(2) === 1 ? exports.ZRTCRole.Callee : exports.ZRTCRole.Caller);
476
+ const routingToken = buf.readUInt32LE(3);
477
+ const subCmd = buf.readUInt16LE(7);
478
+ if (subCmd === exports.ZRTCMediaSubCommand.AudioRtp ||
479
+ subCmd === exports.ZRTCMediaSubCommand.AudioRtcp ||
480
+ subCmd === exports.ZRTCMediaSubCommand.VideoRtp ||
481
+ subCmd === exports.ZRTCMediaSubCommand.VideoRtcp ||
482
+ subCmd === exports.ZRTCMediaSubCommand.AudioFec) {
483
+ return {
484
+ family: "zrtc_media",
485
+ version,
486
+ role,
487
+ routingToken,
488
+ subCmd,
489
+ isVideo: subCmd === exports.ZRTCMediaSubCommand.VideoRtp || subCmd === exports.ZRTCMediaSubCommand.VideoRtcp,
490
+ isRtcp: subCmd === exports.ZRTCMediaSubCommand.AudioRtcp || subCmd === exports.ZRTCMediaSubCommand.VideoRtcp,
491
+ isFec: subCmd === exports.ZRTCMediaSubCommand.AudioFec,
492
+ rtpPayload: buf.subarray(9),
493
+ };
494
+ }
495
+ if (buf.length >= 17) {
496
+ return {
497
+ family: "zrtc_p2p",
498
+ version,
499
+ role,
500
+ routingToken,
501
+ subCmd,
502
+ seqNum: buf.readUInt32LE(9),
503
+ callId: buf.readUInt32LE(13),
504
+ payload: buf.subarray(17),
505
+ };
506
+ }
507
+ }
508
+ return { family: "raw", raw: buf };
509
+ }
510
+
511
+ exports.DEFAULT_ZALO_AUDIO_CODEC = DEFAULT_ZALO_AUDIO_CODEC;
512
+ exports.DEFAULT_ZALO_VIDEO_CODEC = DEFAULT_ZALO_VIDEO_CODEC;
513
+ exports.buildEchoRequest = buildEchoRequest;
514
+ exports.buildEndCallRequest = buildEndCallRequest;
515
+ exports.buildInitCallRequest = buildInitCallRequest;
516
+ exports.buildInitCallResponse = buildInitCallResponse;
517
+ exports.buildPingRequest = buildPingRequest;
518
+ exports.buildPingResponse = buildPingResponse;
519
+ exports.buildRelayPingRequest = buildRelayPingRequest;
520
+ exports.buildRequestForwardPacket = buildRequestForwardPacket;
521
+ exports.buildZrtcExtendData = buildZrtcExtendData;
522
+ exports.parseZRTPPacket = parseZRTPPacket;
523
+ exports.uidToUint32 = uidToUint32;
524
+ exports.wrapLegacyMediaPacket = wrapLegacyMediaPacket;
525
+ exports.wrapZrtcMediaPacket = wrapZrtcMediaPacket;