@softtynet/zca-js 2.3.4 → 2.3.6

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 (129) 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/sync/downloadTransferSync.js +19 -1
  61. package/dist/apis.d.ts +81 -0
  62. package/dist/apis.js +135 -0
  63. package/dist/call-engine/ZRTPPacketCodec.d.ts +262 -0
  64. package/dist/call-engine/ZRTPPacketCodec.js +506 -0
  65. package/dist/call-engine/ZaloCallController.d.ts +134 -0
  66. package/dist/call-engine/ZaloCallController.js +638 -0
  67. package/dist/call-engine/ZaloCallTransport.d.ts +83 -0
  68. package/dist/call-engine/ZaloCallTransport.js +259 -0
  69. package/dist/call-engine/ZaloRtcSession.d.ts +609 -0
  70. package/dist/call-engine/ZaloRtcSession.js +2939 -0
  71. package/dist/call-engine/ZaloSrtpSession.d.ts +80 -0
  72. package/dist/call-engine/ZaloSrtpSession.js +278 -0
  73. package/dist/call-engine/index.d.ts +18 -0
  74. package/dist/call-engine/index.js +24 -0
  75. package/dist/cjs/apis/call/addUserGroupCall.cjs +53 -0
  76. package/dist/cjs/apis/call/answerAckVoiceCall.cjs +43 -0
  77. package/dist/cjs/apis/call/answerGroupCall.cjs +50 -0
  78. package/dist/cjs/apis/call/answerVoiceCall.cjs +55 -0
  79. package/dist/cjs/apis/call/broadcastGroupCallState.cjs +50 -0
  80. package/dist/cjs/apis/call/cancelGroupCall.cjs +50 -0
  81. package/dist/cjs/apis/call/cancelVoiceCall.cjs +5 -1
  82. package/dist/cjs/apis/call/createController.cjs +14 -0
  83. package/dist/cjs/apis/call/createRtcSession.cjs +15 -0
  84. package/dist/cjs/apis/call/endGroupCall.cjs +50 -0
  85. package/dist/cjs/apis/call/finishGroupCall.cjs +52 -0
  86. package/dist/cjs/apis/call/getGroupCallState.cjs +43 -0
  87. package/dist/cjs/apis/call/holdVoiceCall.cjs +39 -0
  88. package/dist/cjs/apis/call/joinGroupCall.cjs +51 -0
  89. package/dist/cjs/apis/call/logEndVoiceCall.cjs +51 -0
  90. package/dist/cjs/apis/call/notifyGroupCall.cjs +49 -0
  91. package/dist/cjs/apis/call/pingGroupCall.cjs +50 -0
  92. package/dist/cjs/apis/call/requestAudioToVideoCall.cjs +42 -0
  93. package/dist/cjs/apis/call/requestGroupCall.cjs +51 -0
  94. package/dist/cjs/apis/call/requestShareScreenCall.cjs +42 -0
  95. package/dist/cjs/apis/call/requestVoiceCall.cjs +52 -0
  96. package/dist/cjs/apis/call/ringRingGroupCall.cjs +50 -0
  97. package/dist/cjs/apis/call/ringRingVoiceCall.cjs +43 -0
  98. package/dist/cjs/apis/call/sendRequestGroupCall.cjs +53 -0
  99. package/dist/cjs/apis/call/sendRequestVoiceCall.cjs +56 -0
  100. package/dist/cjs/apis/call/sendVoiceCall.cjs +10 -8
  101. package/dist/cjs/apis/call/shareScreenGroupCall.cjs +50 -0
  102. package/dist/cjs/apis/call/unholdVoiceCall.cjs +39 -0
  103. package/dist/cjs/apis/call/updateCallMediaState.cjs +66 -0
  104. package/dist/cjs/apis/sync/downloadTransferSync.cjs +19 -1
  105. package/dist/cjs/apis.cjs +135 -0
  106. package/dist/cjs/call-engine/ZRTPPacketCodec.cjs +525 -0
  107. package/dist/cjs/call-engine/ZaloCallController.cjs +643 -0
  108. package/dist/cjs/call-engine/ZaloCallTransport.cjs +265 -0
  109. package/dist/cjs/call-engine/ZaloRtcSession.cjs +2945 -0
  110. package/dist/cjs/call-engine/ZaloSrtpSession.cjs +287 -0
  111. package/dist/cjs/constants/protocol.cjs +1 -1
  112. package/dist/cjs/crypto/aes.cjs +3 -1
  113. package/dist/cjs/crypto/zdb-cipher.cjs +10 -3
  114. package/dist/cjs/index.cjs +61 -11
  115. package/dist/cjs/models/CallEvent.cjs +95 -1
  116. package/dist/cjs/realtime/handlers/control.handler.cjs +17 -3
  117. package/dist/cjs/realtime/listener.cjs +19 -0
  118. package/dist/constants/protocol.d.ts +1 -1
  119. package/dist/constants/protocol.js +1 -1
  120. package/dist/crypto/aes.js +3 -1
  121. package/dist/crypto/zdb-cipher.js +10 -3
  122. package/dist/index.d.ts +32 -4
  123. package/dist/index.js +2 -0
  124. package/dist/models/CallEvent.d.ts +15 -0
  125. package/dist/models/CallEvent.js +95 -1
  126. package/dist/realtime/handlers/control.handler.js +17 -3
  127. package/dist/realtime/listener.d.ts +5 -0
  128. package/dist/realtime/listener.js +19 -0
  129. package/package.json +2 -1
package/README.md CHANGED
@@ -14,10 +14,10 @@
14
14
 
15
15
  ## Điểm nổi bật
16
16
 
17
- - **Kiến trúc 12 Domains (`224 API nguyên bản`)**: Tổ chức trực quan qua `api.auth`, `api.chat`, `api.group`, `api.friend`, `api.profile`, `api.sync`, `api.zcloud`, `api.call`, `api.media`, `api.sticker`, `api.board`, `api.business` (vẫn hỗ trợ gọi phẳng `api.<method>` tương thích ngược 100%).
17
+ - **Kiến trúc 12 Domains (`252 API nguyên bản`)**: Tổ chức trực quan qua `api.auth`, `api.chat`, `api.group`, `api.friend`, `api.profile`, `api.sync`, `api.zcloud`, `api.call`, `api.media`, `api.sticker`, `api.board`, `api.business` (vẫn hỗ trợ gọi phẳng `api.<method>` tương thích ngược 100%).
18
18
  - **Đồng bộ lịch sử Mobile (`ZDB 4.0`) & Catch-up Sync**: Hỗ trợ đầy đủ luồng `requestSyncFromPhone` $\rightarrow$ `getSyncData` (giải mã RSA-2048 OAEP/PKCS1 + ZDB 4.0 64KB multi-chunk AES-256-CBC + Deflate) & `pullMobile`.
19
19
  - **ZCloud, MediaStore & Bảo toàn Số nguyên 64-bit (`preParseJsonIds`)**: Tự động giữ nguyên độ chính xác chuỗi 19 chữ số cho `owner_id`, `group_id`, `globalMsgId`, `cliMsgId` trước khi `JSON.parse()` và tích hợp bộ mã hóa `98yS` AES-256-CBC cho ZCloud/ZFamily.
20
- - **Tín hiệu Gọi Thoại & Video Call 1-1**: Điều khiển trọn vẹn vòng đời cuộc gọi (`11300` $\rightarrow$ `11306`: `sendVoiceCall`, `cancelVoiceCall`, `endVoiceCall`) và lắng nghe `call_event` thời gian thực.
20
+ - **Zalo Call Engine thuần TypeScript (`30 API` trong `api.call` + `ZaloRtcSession` / `ZaloCallController`)**: Hỗ trợ đầy đủ cả **Gọi Đi** và **Nhận Cuộc Gọi Đến** (Thoại 1-1, Video Call H.264 FU-A Annex-B 2 chiều, Gọi Nhóm), nâng cấp Thoại $\rightarrow$ Video giữa cuộc gọi, bật/tắt Camera/Mic, Tạm giữ (Hold/Unhold), Tái kết nối UDP (`reconnectUdp`), và **Bàn giao kết nối UDP trực tiếp cho Mobile App (`signalingOnly` / `handoffUdpToExternal`)**.
21
21
 
22
22
  ---
23
23
 
@@ -55,18 +55,18 @@ const zalo = new Zalo({ imageMetadataGetter });
55
55
 
56
56
  | Phân hệ | Namespace | Số lượng API | Tài liệu chi tiết |
57
57
  | :--- | :--- | :---: | :--- |
58
- | **Xác thực & Phiên** | `api.auth` | 8 | [`docs/api/auth.md`](docs/api/auth.md) |
59
- | **Tin nhắn & Hội thoại** | `api.chat` | 35 | [`docs/api/chat.md`](docs/api/chat.md) |
60
- | **Nhóm & Cộng đồng** | `api.group` | 48 | [`docs/api/group.md`](docs/api/group.md) |
61
- | **Bạn bè & Danh bạ** | `api.friend` | 26 | [`docs/api/friend.md`](docs/api/friend.md) |
62
- | **Hồ sơ cá nhân** | `api.profile` | 18 | [`docs/api/profile.md`](docs/api/profile.md) |
58
+ | **Xác thực & Phiên** | `api.auth` | 14 | [`docs/api/auth.md`](docs/api/auth.md) |
59
+ | **Tin nhắn & Hội thoại** | `api.chat` | 41 | [`docs/api/chat.md`](docs/api/chat.md) |
60
+ | **Nhóm & Cộng đồng** | `api.group` | 44 | [`docs/api/group.md`](docs/api/group.md) |
61
+ | **Bạn bè & Danh bạ** | `api.friend` | 33 | [`docs/api/friend.md`](docs/api/friend.md) |
62
+ | **Hồ sơ cá nhân** | `api.profile` | 16 | [`docs/api/profile.md`](docs/api/profile.md) |
63
63
  | **Đồng bộ Mobile ZDB 4.0** | `api.sync` | 5 | [`docs/api/sync.md`](docs/api/sync.md) |
64
64
  | **Đám mây ZCloud & ZFamily** | `api.zcloud` | 9 | [`docs/api/zcloud.md`](docs/api/zcloud.md) |
65
- | **Gọi thoại & Video 1-1** | `api.call` | 3 | [`docs/api/call.md`](docs/api/call.md) |
66
- | **Kho lưu trữ & Voice-to-Text** | `api.media` | 7 | [`docs/api/media.md`](docs/api/media.md) |
67
- | **Nhãn dán & Biểu cảm** | `api.sticker` | 8 | [`docs/api/sticker.md`](docs/api/sticker.md) |
65
+ | **Gọi thoại, Video & Gọi nhóm** | `api.call` | 30 | [`docs/api/call.md`](docs/api/call.md) |
66
+ | **Kho lưu trữ & Voice-to-Text** | `api.media` | 8 | [`docs/api/media.md`](docs/api/media.md) |
67
+ | **Nhãn dán & Biểu cảm** | `api.sticker` | 10 | [`docs/api/sticker.md`](docs/api/sticker.md) |
68
68
  | **Bảng tin, Bình chọn & Lịch hẹn** | `api.board` | 16 | [`docs/api/board.md`](docs/api/board.md) |
69
- | **Zalo Business & Danh mục** | `api.business` | 41 | [`docs/api/business.md`](docs/api/business.md) |
69
+ | **Zalo Business & Danh mục** | `api.business` | 26 | [`docs/api/business.md`](docs/api/business.md) |
70
70
 
71
71
  > Xem tổng quan toàn bộ tài liệu tại [`docs/api/index.md`](docs/api/index.md) hoặc chạy trang tài liệu VitePress cục bộ bằng lệnh `npm run docs:dev`.
72
72
 
@@ -125,6 +125,42 @@ const mediaList = await api.media.getConversationMedia({
125
125
  const profiles = await api.group.getGroupMembersInfo(["1000000000000000001"]);
126
126
  ```
127
127
 
128
+ ### 4. Gọi Thoại, Video Call 2 chiều & Nhận Cuộc Gọi Đến (`ZaloRtcSession`)
129
+
130
+ ```ts
131
+ import { CallType } from "@softtynet/zca-js";
132
+
133
+ const session = api.call.createRtcSession({ autoAttachListener: true });
134
+
135
+ // 1) Gọi đi (Audio hoặc Video Call)
136
+ const params = await session.startOutgoingCall("5249661060655759359", {
137
+ callType: CallType.Video,
138
+ });
139
+
140
+ // 2) Nhận luồng Audio Opus & Video H.264 Annex-B thời gian thực
141
+ session.on("audio_frame", (frame) => {
142
+ // frame.payload: Buffer (Opus 16kHz mono)
143
+ });
144
+ session.on("video_annexb_frame", (frame) => {
145
+ // frame.annexB: Buffer (00 00 00 01 + SPS/PPS/IDR/P-Slice), frame.isKeyframe: boolean
146
+ });
147
+
148
+ // 3) Nhận cuộc gọi đến từ sự kiện WebSocket `call_event`
149
+ api.listener.on("call_event", async (ev) => {
150
+ if (ev.act === "request" || ev.act === "group_request") {
151
+ await session.ringIncomingCall(ev); // Báo máy đang đổ chuông (402 / 502)
152
+ const incomingParams = await session.acceptIncomingCall(ev, { skipRingRing: true });
153
+ console.log("Đã bắt máy cuộc gọi đến:", incomingParams.callId, incomingParams.rtpAddress);
154
+ }
155
+ });
156
+
157
+ // 4) Chế độ Worker tạo cuộc gọi và bàn giao gói UDP trực tiếp cho Mobile App:
158
+ const handoffParams = await session.startOutgoingCall("5249661060655759359", {
159
+ callType: CallType.Audio,
160
+ signalingOnly: true, // Worker không mở UDP, xuất sẵn gói `params.mobileDirectHandoff` cho Mobile
161
+ });
162
+ ```
163
+
128
164
  ---
129
165
 
130
166
  ## Chạy trang Tài liệu (VitePress Docs)
@@ -0,0 +1,11 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type AddUserGroupCallOptions = {
3
+ calleeId?: string;
4
+ callType?: CallType | number;
5
+ hostCall: string;
6
+ data?: string | Record<string, unknown>;
7
+ session: string;
8
+ partners: string[];
9
+ };
10
+ export type AddUserGroupCallResponse = Record<string, unknown>;
11
+ export declare const addUserGroupCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: AddUserGroupCallOptions) => Promise<AddUserGroupCallResponse>;
@@ -0,0 +1,48 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ import { CallType } from "./sendVoiceCall.js";
4
+ export const addUserGroupCallFactory = apiFactory()((api, _ctx, utils) => {
5
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
6
+ /**
7
+ * Mời thêm thành viên vào cuộc gọi nhóm đang diễn ra (`/api/voicecall/group/adduser`, command `12435`).
8
+ *
9
+ * @param callId ID của cuộc gọi nhóm
10
+ * @param options Thông tin `hostCall`, `session`, `partners`, `calleeId`, `callType` và `data`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function addUserGroupCall(callId, options) {
14
+ if (!callId)
15
+ throw new ZaloApiError("Missing callId");
16
+ if (!options?.hostCall)
17
+ throw new ZaloApiError("Missing hostCall");
18
+ if (!options?.session)
19
+ throw new ZaloApiError("Missing session");
20
+ if (!voiceCallService)
21
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
22
+ const dataStr = options.data === undefined
23
+ ? "{}"
24
+ : typeof options.data === "string"
25
+ ? options.data
26
+ : JSON.stringify(options.data);
27
+ const params = {
28
+ calleeId: options.calleeId ?? "",
29
+ callId,
30
+ callType: options.callType ?? CallType.GroupAudio,
31
+ hostCall: String(options.hostCall),
32
+ data: dataStr,
33
+ session: options.session,
34
+ partners: (options.partners ?? []).map(String),
35
+ };
36
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
37
+ if (!encryptedParams)
38
+ throw new ZaloApiError("Failed to encrypt addUserGroupCall params");
39
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/adduser`, {
40
+ zpw_type: 24,
41
+ params: encryptedParams,
42
+ });
43
+ const response = await utils.request(url, {
44
+ method: "GET",
45
+ });
46
+ return utils.resolve(response);
47
+ };
48
+ });
@@ -0,0 +1,5 @@
1
+ export type AnswerAckVoiceCallOptions = {
2
+ status?: number;
3
+ };
4
+ export type AnswerAckVoiceCallResponse = Record<string, unknown>;
5
+ export declare const answerAckVoiceCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (calleeId: string, callId: number, options?: AnswerAckVoiceCallOptions) => Promise<AnswerAckVoiceCallResponse>;
@@ -0,0 +1,38 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const answerAckVoiceCallFactory = apiFactory()((api, ctx, utils) => {
4
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
5
+ /**
6
+ * Xác nhận bắt tay hoàn tất từ phía người gọi sau khi người nhận bắt máy (`/api/voicecall/answerack`, command `11304`, signal `408`).
7
+ *
8
+ * @param calleeId User ID của người nhận cuộc gọi
9
+ * @param callId ID của cuộc gọi
10
+ * @param options Tuỳ chọn mã trạng thái (`status`, mặc định `0`)
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function answerAckVoiceCall(calleeId, callId, options = {}) {
14
+ if (!calleeId)
15
+ throw new ZaloApiError("Missing calleeId");
16
+ if (!callId)
17
+ throw new ZaloApiError("Missing callId");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const params = {
21
+ calleeId: String(calleeId),
22
+ callId,
23
+ status: options.status ?? 0,
24
+ imei: ctx.imei,
25
+ };
26
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
27
+ if (!encryptedParams)
28
+ throw new ZaloApiError("Failed to encrypt answerAckVoiceCall params");
29
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/answerack`, {
30
+ zpw_type: 24,
31
+ params: encryptedParams,
32
+ });
33
+ const response = await utils.request(url, {
34
+ method: "GET",
35
+ });
36
+ return utils.resolve(response);
37
+ };
38
+ });
@@ -0,0 +1,10 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type AnswerGroupCallOptions = {
3
+ calleeId?: string;
4
+ callType?: CallType | number;
5
+ hostCall: string;
6
+ data?: string | Record<string, unknown>;
7
+ partners?: string[];
8
+ };
9
+ export type AnswerGroupCallResponse = Record<string, unknown>;
10
+ export declare const answerGroupCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: AnswerGroupCallOptions) => Promise<AnswerGroupCallResponse>;
@@ -0,0 +1,45 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ import { CallType } from "./sendVoiceCall.js";
4
+ export const answerGroupCallFactory = apiFactory()((api, ctx, utils) => {
5
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
6
+ /**
7
+ * Chấp nhận / Nghe cuộc gọi nhóm đến (`/api/voicecall/group/answer`, command `12436`).
8
+ *
9
+ * @param callId ID của cuộc gọi nhóm
10
+ * @param options Thông tin `hostCall`, `calleeId`, `callType`, `partners` và `data`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function answerGroupCall(callId, options) {
14
+ if (!callId)
15
+ throw new ZaloApiError("Missing callId");
16
+ if (!options?.hostCall)
17
+ throw new ZaloApiError("Missing hostCall");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const dataStr = options.data === undefined
21
+ ? "{}"
22
+ : typeof options.data === "string"
23
+ ? options.data
24
+ : JSON.stringify(options.data);
25
+ const params = {
26
+ calleeId: String(options.calleeId ?? ctx.uid),
27
+ callId,
28
+ callType: options.callType ?? CallType.GroupAudio,
29
+ hostCall: String(options.hostCall),
30
+ data: dataStr,
31
+ partners: (options.partners ?? []).map(String),
32
+ };
33
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
34
+ if (!encryptedParams)
35
+ throw new ZaloApiError("Failed to encrypt answerGroupCall params");
36
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/answer`, {
37
+ zpw_type: 24,
38
+ params: encryptedParams,
39
+ });
40
+ const response = await utils.request(url, {
41
+ method: "GET",
42
+ });
43
+ return utils.resolve(response);
44
+ };
45
+ });
@@ -0,0 +1,11 @@
1
+ export type AnswerVoiceCallOptions = {
2
+ status?: number;
3
+ codec?: string;
4
+ rtcpAddress?: string;
5
+ rtpAddress?: string;
6
+ sessionId?: string;
7
+ extendData?: string | Record<string, unknown>;
8
+ subCommand?: number;
9
+ };
10
+ export type AnswerVoiceCallResponse = Record<string, unknown>;
11
+ export declare const answerVoiceCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callerId: string, callId: number, options?: AnswerVoiceCallOptions) => Promise<AnswerVoiceCallResponse>;
@@ -0,0 +1,50 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const answerVoiceCallFactory = apiFactory()((api, _ctx, utils) => {
4
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
5
+ /**
6
+ * Chấp nhận / Nghe cuộc gọi thoại hoặc video đến (`/api/voicecall/answer`, command `11303`, signal `402`).
7
+ *
8
+ * @param callerId User ID của người gọi đến
9
+ * @param callId ID của cuộc gọi
10
+ * @param options Thông tin `sessionId`, `rtpAddress`, `rtcpAddress`, `codec`, `extendData` và `status`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function answerVoiceCall(callerId, callId, options = {}) {
14
+ if (!callerId)
15
+ throw new ZaloApiError("Missing callerId");
16
+ if (!callId)
17
+ throw new ZaloApiError("Missing callId");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const extendDataStr = options.extendData === undefined
21
+ ? undefined
22
+ : typeof options.extendData === "string"
23
+ ? options.extendData
24
+ : JSON.stringify(options.extendData);
25
+ const params = {
26
+ callerId: String(callerId),
27
+ callId,
28
+ status: options.status ?? 0,
29
+ codec: options.codec ?? "",
30
+ rtcpAddress: options.rtcpAddress ?? "",
31
+ rtpAddress: options.rtpAddress ?? "",
32
+ session_id: options.sessionId ?? "",
33
+ };
34
+ if (extendDataStr) {
35
+ params.extendData = extendDataStr;
36
+ params.subCommand = options.subCommand ?? 3;
37
+ }
38
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
39
+ if (!encryptedParams)
40
+ throw new ZaloApiError("Failed to encrypt answerVoiceCall params");
41
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/answer`, {
42
+ zpw_type: 24,
43
+ params: encryptedParams,
44
+ });
45
+ const response = await utils.request(url, {
46
+ method: "GET",
47
+ });
48
+ return utils.resolve(response);
49
+ };
50
+ });
@@ -0,0 +1,10 @@
1
+ export type BroadcastGroupCallStateOptions = {
2
+ hostCall: string;
3
+ userId?: string;
4
+ callState?: number;
5
+ audioState?: number;
6
+ videoState?: number;
7
+ params?: string | Record<string, unknown>;
8
+ };
9
+ export type BroadcastGroupCallStateResponse = Record<string, unknown>;
10
+ export declare const broadcastGroupCallStateFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: BroadcastGroupCallStateOptions) => Promise<BroadcastGroupCallStateResponse>;
@@ -0,0 +1,45 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ export const broadcastGroupCallStateFactory = apiFactory()((api, ctx, utils) => {
4
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
5
+ /**
6
+ * Phát (broadcast) trạng thái âm thanh / hình ảnh của thành viên trong cuộc gọi nhóm (`/api/voicecall/group/broadcast`, command `12098`).
7
+ *
8
+ * @param callId ID của cuộc gọi nhóm
9
+ * @param options Thông tin `hostCall`, `userId`, `callState`, `audioState`, `videoState` và `params`
10
+ * @throws {ZaloApiError}
11
+ */
12
+ return async function broadcastGroupCallState(callId, options) {
13
+ if (!callId)
14
+ throw new ZaloApiError("Missing callId");
15
+ if (!options?.hostCall)
16
+ throw new ZaloApiError("Missing hostCall");
17
+ if (!voiceCallService)
18
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
19
+ const paramsStr = options.params === undefined
20
+ ? "{}"
21
+ : typeof options.params === "string"
22
+ ? options.params
23
+ : JSON.stringify(options.params);
24
+ const payload = {
25
+ callId,
26
+ hostCall: String(options.hostCall),
27
+ userId: String(options.userId ?? ctx.uid),
28
+ callstate: options.callState ?? 1,
29
+ audiostate: options.audioState ?? 1,
30
+ videostate: options.videoState ?? 0,
31
+ params: paramsStr,
32
+ };
33
+ const encryptedParams = utils.encodeAES(JSON.stringify(payload));
34
+ if (!encryptedParams)
35
+ throw new ZaloApiError("Failed to encrypt broadcastGroupCallState params");
36
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/broadcast`, {
37
+ zpw_type: 24,
38
+ params: encryptedParams,
39
+ });
40
+ const response = await utils.request(url, {
41
+ method: "GET",
42
+ });
43
+ return utils.resolve(response);
44
+ };
45
+ });
@@ -0,0 +1,10 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type CancelGroupCallOptions = {
3
+ calleeId?: string;
4
+ callType?: CallType | number;
5
+ hostCall: string;
6
+ data?: string | Record<string, unknown>;
7
+ partners?: string[];
8
+ };
9
+ export type CancelGroupCallResponse = Record<string, unknown>;
10
+ export declare const cancelGroupCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: CancelGroupCallOptions) => Promise<CancelGroupCallResponse>;
@@ -0,0 +1,45 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ import { CallType } from "./sendVoiceCall.js";
4
+ export const cancelGroupCallFactory = apiFactory()((api, ctx, utils) => {
5
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
6
+ /**
7
+ * Từ chối / Huỷ lời mời tham gia cuộc gọi nhóm (`/api/voicecall/group/cancel`, command `12437`).
8
+ *
9
+ * @param callId ID của cuộc gọi nhóm
10
+ * @param options Thông tin `hostCall`, `calleeId`, `callType`, `partners` và `data`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function cancelGroupCall(callId, options) {
14
+ if (!callId)
15
+ throw new ZaloApiError("Missing callId");
16
+ if (!options?.hostCall)
17
+ throw new ZaloApiError("Missing hostCall");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const dataStr = options.data === undefined
21
+ ? "{}"
22
+ : typeof options.data === "string"
23
+ ? options.data
24
+ : JSON.stringify(options.data);
25
+ const params = {
26
+ calleeId: String(options.calleeId ?? ctx.uid),
27
+ callId,
28
+ callType: options.callType ?? CallType.GroupAudio,
29
+ hostCall: String(options.hostCall),
30
+ data: dataStr,
31
+ partners: (options.partners ?? []).map(String),
32
+ };
33
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
34
+ if (!encryptedParams)
35
+ throw new ZaloApiError("Failed to encrypt cancelGroupCall params");
36
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/cancel`, {
37
+ zpw_type: 24,
38
+ params: encryptedParams,
39
+ });
40
+ const response = await utils.request(url, {
41
+ method: "GET",
42
+ });
43
+ return utils.resolve(response);
44
+ };
45
+ });
@@ -1,6 +1,6 @@
1
1
  import { CallType } from "./sendVoiceCall.js";
2
2
  export type CancelVoiceCallOptions = {
3
- callType?: CallType;
3
+ callType?: CallType | number;
4
4
  status?: number;
5
5
  };
6
6
  export type CancelVoiceCallResponse = Record<string, unknown>;
@@ -18,10 +18,14 @@ export const cancelVoiceCallFactory = apiFactory()((api, ctx, utils) => {
18
18
  throw new ZaloApiError("Missing callId");
19
19
  if (!voiceCallService)
20
20
  throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
21
+ const rawCallType = options.callType ?? CallType.Audio;
22
+ // Khớp với ZMessageSerializer::sendCancelCall (0x100026acc): callType = (callType != 1 ? 1 : 0)
23
+ // Cho phép truyền trực tiếp 0 (Audio) hoặc 1 (Video), hoặc CallType.Audio (1) -> 0, CallType.Video (3) -> 1
24
+ const normalizedCallType = rawCallType === 0 || rawCallType === CallType.Audio ? 0 : 1;
21
25
  const params = {
22
26
  callerId: String(calleeId),
23
27
  callId,
24
- callType: options.callType ?? CallType.Audio,
28
+ callType: normalizedCallType,
25
29
  status: options.status ?? 0,
26
30
  imei: ctx.imei,
27
31
  };
@@ -0,0 +1,7 @@
1
+ import type { API } from "../../apis.js";
2
+ import { ZaloCallController, type ZaloCallControllerOptions } from "../../call-engine/ZaloCallController.js";
3
+ import type { ContextSession } from "../../context.js";
4
+ /**
5
+ * Khởi tạo bộ điều phối cuộc gọi thuần TypeScript `ZaloCallController` (tích hợp `ZaloRtcSession` và kênh IPC `ZaloCallTransport`).
6
+ */
7
+ export declare function createControllerFactory(_ctx: ContextSession, api: API): (options?: ZaloCallControllerOptions) => ZaloCallController;
@@ -0,0 +1,9 @@
1
+ import { ZaloCallController } from "../../call-engine/ZaloCallController.js";
2
+ /**
3
+ * Khởi tạo bộ điều phối cuộc gọi thuần TypeScript `ZaloCallController` (tích hợp `ZaloRtcSession` và kênh IPC `ZaloCallTransport`).
4
+ */
5
+ export function createControllerFactory(_ctx, api) {
6
+ return function createController(options = {}) {
7
+ return new ZaloCallController(api, options);
8
+ };
9
+ }
@@ -0,0 +1,8 @@
1
+ import type { API } from "../../apis.js";
2
+ import { ZaloRtcSession, type ZaloRtcSessionOptions } from "../../call-engine/ZaloRtcSession.js";
3
+ import type { ContextSession } from "../../context.js";
4
+ /**
5
+ * Khởi tạo phiên gọi Thoại & Video thuần TypeScript / Node.js (`ZaloRtcSession` — UDP `ZRTPPacket` + `SRTP`)
6
+ * hoạt động độc lập 100% trên Worker / Server / Desktop / Mobile Bridge mà không cần cài đặt Zalo PC.
7
+ */
8
+ export declare function createRtcSessionFactory(_ctx: ContextSession, api: API): (options?: ZaloRtcSessionOptions) => ZaloRtcSession;
@@ -0,0 +1,10 @@
1
+ import { ZaloRtcSession } from "../../call-engine/ZaloRtcSession.js";
2
+ /**
3
+ * Khởi tạo phiên gọi Thoại & Video thuần TypeScript / Node.js (`ZaloRtcSession` — UDP `ZRTPPacket` + `SRTP`)
4
+ * hoạt động độc lập 100% trên Worker / Server / Desktop / Mobile Bridge mà không cần cài đặt Zalo PC.
5
+ */
6
+ export function createRtcSessionFactory(_ctx, api) {
7
+ return function createRtcSession(options = {}) {
8
+ return new ZaloRtcSession(api, options);
9
+ };
10
+ }
@@ -0,0 +1,10 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type EndGroupCallOptions = {
3
+ calleeId?: string;
4
+ callType?: CallType | number;
5
+ hostCall: string;
6
+ data?: string | Record<string, unknown>;
7
+ partners?: string[];
8
+ };
9
+ export type EndGroupCallResponse = Record<string, unknown>;
10
+ export declare const endGroupCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: EndGroupCallOptions) => Promise<EndGroupCallResponse>;
@@ -0,0 +1,45 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ import { CallType } from "./sendVoiceCall.js";
4
+ export const endGroupCallFactory = apiFactory()((api, ctx, utils) => {
5
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
6
+ /**
7
+ * Rời khỏi hoặc kết thúc cuộc gọi nhóm (`/api/voicecall/group/endcall`, command `12438`).
8
+ *
9
+ * @param callId ID của cuộc gọi nhóm
10
+ * @param options Thông tin `hostCall`, `calleeId`, `callType`, `partners` và `data`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function endGroupCall(callId, options) {
14
+ if (!callId)
15
+ throw new ZaloApiError("Missing callId");
16
+ if (!options?.hostCall)
17
+ throw new ZaloApiError("Missing hostCall");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const dataStr = options.data === undefined
21
+ ? "{}"
22
+ : typeof options.data === "string"
23
+ ? options.data
24
+ : JSON.stringify(options.data);
25
+ const params = {
26
+ calleeId: String(options.calleeId ?? ctx.uid),
27
+ callId,
28
+ callType: options.callType ?? CallType.GroupAudio,
29
+ hostCall: String(options.hostCall),
30
+ data: dataStr,
31
+ partners: (options.partners ?? []).map(String),
32
+ };
33
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
34
+ if (!encryptedParams)
35
+ throw new ZaloApiError("Failed to encrypt endGroupCall params");
36
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/endcall`, {
37
+ zpw_type: 24,
38
+ params: encryptedParams,
39
+ });
40
+ const response = await utils.request(url, {
41
+ method: "GET",
42
+ });
43
+ return utils.resolve(response);
44
+ };
45
+ });
@@ -0,0 +1,12 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type FinishGroupCallOptions = {
3
+ callType?: CallType | number;
4
+ data?: string | Record<string, unknown>;
5
+ duration?: number;
6
+ hostCall: string;
7
+ partners?: string[];
8
+ status?: number;
9
+ joinTime?: number;
10
+ };
11
+ export type FinishGroupCallResponse = Record<string, unknown>;
12
+ export declare const finishGroupCallFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, options: FinishGroupCallOptions) => Promise<FinishGroupCallResponse>;
@@ -0,0 +1,47 @@
1
+ import { ZaloApiError } from "../../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../../utils.js";
3
+ import { CallType } from "./sendVoiceCall.js";
4
+ export const finishGroupCallFactory = apiFactory()((api, _ctx, utils) => {
5
+ const voiceCallService = api.zpwServiceMap.voice_call?.[0];
6
+ /**
7
+ * Gửi báo cáo hoàn tất / kết thúc phiên gọi nhóm (`/api/voicecall/group/finish`, command `12446`).
8
+ *
9
+ * @param callId ID của cuộc gọi nhóm
10
+ * @param options Thông tin `hostCall`, `duration`, `joinTime`, `status`, `partners` và `data`
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function finishGroupCall(callId, options) {
14
+ if (!callId)
15
+ throw new ZaloApiError("Missing callId");
16
+ if (!options?.hostCall)
17
+ throw new ZaloApiError("Missing hostCall");
18
+ if (!voiceCallService)
19
+ throw new ZaloApiError("Missing voice_call service URL in zpwServiceMap");
20
+ const dataStr = options.data === undefined
21
+ ? "{}"
22
+ : typeof options.data === "string"
23
+ ? options.data
24
+ : JSON.stringify(options.data);
25
+ const params = {
26
+ callId,
27
+ callType: options.callType ?? CallType.GroupAudio,
28
+ data: dataStr,
29
+ duration: options.duration ?? 0,
30
+ hostCall: String(options.hostCall),
31
+ partners: (options.partners ?? []).map(String),
32
+ status: options.status ?? 0,
33
+ joinTime: options.joinTime ?? 0,
34
+ };
35
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
36
+ if (!encryptedParams)
37
+ throw new ZaloApiError("Failed to encrypt finishGroupCall params");
38
+ const url = utils.makeURL(`${voiceCallService}/api/voicecall/group/finish`, {
39
+ zpw_type: 24,
40
+ params: encryptedParams,
41
+ });
42
+ const response = await utils.request(url, {
43
+ method: "GET",
44
+ });
45
+ return utils.resolve(response);
46
+ };
47
+ });
@@ -0,0 +1,3 @@
1
+ import { CallType } from "./sendVoiceCall.js";
2
+ export type GetGroupCallStateResponse = Record<string, unknown>;
3
+ export declare const getGroupCallStateFactory: (ctx: import("../../context.js").ContextBase, api: import("../../apis.js").API) => (callId: number, hostCall: string, callType?: CallType | number) => Promise<GetGroupCallStateResponse>;