@trtc/calls-uikit-vue 4.4.2 → 4.4.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.
- package/package.json +2 -2
- package/src/Components/TUICallKit.vue +1 -1
- package/src/Components/assets/aiAssistant/desktop/subtitleSettings.svg +4 -0
- package/src/Components/assets/aiAssistant/mobile/close-aiAssistant.svg +7 -0
- package/src/Components/assets/aiAssistant/mobile/open-aiAssistant.svg +7 -0
- package/src/Components/assets/aiAssistant/mobile/subtitleSettings.svg +3 -0
- package/src/Components/components/base/CustomSelect/CustomSelect.ts +45 -0
- package/src/Components/components/base/CustomSelect/CustomSelect.vue +199 -0
- package/src/Components/components/common/AIAssistant/AISubtitle.vue +155 -37
- package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchH5.vue +35 -0
- package/src/Components/components/common/AIAssistant/components/AITranscriberSwitchPC.vue +89 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleContent.vue +234 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleSettingsH5.vue +534 -0
- package/src/Components/components/common/AIAssistant/components/SubtitleSettingsPC.vue +294 -0
- package/src/Components/components/common/TopBar/TopBar.vue +41 -15
- package/src/Components/hooks/index.ts +1 -0
- package/src/Components/hooks/useAIAssistant.ts +142 -0
- package/src/Components/hooks/useGetVolumeMap.ts +2 -2
- package/src/TUICallService/CallService/AIAssistant.ts +285 -39
- package/src/TUICallService/CallService/UIKitModal.ts +14 -6
- package/src/TUICallService/CallService/bellContext.ts +25 -2
- package/src/TUICallService/CallService/engineEventHandler.ts +6 -1
- package/src/TUICallService/CallService/index.ts +72 -39
- package/src/TUICallService/CallService/miniProgram.ts +0 -12
- package/src/TUICallService/TUIStore/callStore.ts +6 -1
- package/src/TUICallService/UIKitModal/UIKitModal.ts +117 -0
- package/src/TUICallService/UIKitModal/index.ts +2 -0
- package/src/TUICallService/UIKitModal/type.ts +15 -0
- package/src/TUICallService/const/index.ts +4 -0
- package/src/TUICallService/interface/ICallStore.ts +5 -0
- package/src/TUICallService/locales/en.ts +15 -0
- package/src/TUICallService/locales/ja_JP.ts +15 -0
- package/src/TUICallService/locales/zh-cn.ts +15 -0
- package/src/TUICallService/utils/common-utils.ts +1 -1
- package/src/index.ts +1 -1
- package/stats.html +1 -1
- package/tuicall-uikit-vue.es.js +4199 -3474
- package/tuicall-uikit-vue.umd.js +2 -2
- package/types/Components/components/base/CustomSelect/CustomSelect.d.ts +41 -0
- package/types/Components/hooks/index.d.ts +1 -0
- package/types/Components/hooks/useAIAssistant.d.ts +19 -0
- package/types/TUICallService/CallService/AIAssistant.d.ts +72 -15
- package/types/TUICallService/CallService/bellContext.d.ts +3 -0
- package/types/TUICallService/CallService/index.d.ts +4 -3
- package/types/TUICallService/CallService/miniProgram.d.ts +0 -1
- package/types/TUICallService/UIKitModal/UIKitModal.d.ts +4 -0
- package/types/TUICallService/UIKitModal/index.d.ts +2 -0
- package/types/TUICallService/UIKitModal/type.d.ts +13 -0
- package/types/TUICallService/interface/ICallStore.d.ts +4 -0
- package/types/TUICallService/locales/en.d.ts +14 -0
- package/types/TUICallService/locales/ja_JP.d.ts +14 -0
- package/types/TUICallService/locales/zh-cn.d.ts +14 -0
- package/types/tsconfig.tsbuildinfo +1 -1
- package/src/Components/components/common/AIAssistant/AIAssistant.ts +0 -130
- package/src/Components/components/common/AIAssistant/index.ts +0 -11
- package/types/Components/components/common/AIAssistant/AIAssistant.d.ts +0 -40
- package/types/Components/components/common/AIAssistant/index.d.ts +0 -4
|
@@ -1,51 +1,297 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
/**
|
|
2
|
+
* AI Realtime Transcriber State Management
|
|
3
|
+
* @module AITranscriberState
|
|
4
|
+
* @description Manages realtime voice transcription state and operations, including message reception and history
|
|
5
|
+
*/
|
|
6
|
+
import { ITUIStore } from '../interface/ITUIStore';
|
|
7
|
+
import { StoreName, NAME } from '../const/index';
|
|
8
|
+
import TuiStore from '../TUIStore/tuiStore';
|
|
9
|
+
|
|
10
|
+
// AI Transcriber events
|
|
11
|
+
export enum RealtimeTranscriberEvent {
|
|
12
|
+
onReceiveTranscriberMessage = 'onReceiveTranscriberMessage',
|
|
13
|
+
onRealtimeTranscriberStarted = 'onRealtimeTranscriberStarted',
|
|
14
|
+
onRealtimeTranscriberStopped = 'onRealtimeTranscriberStopped',
|
|
15
|
+
onRealtimeTranscriberError = 'onRealtimeTranscriberError',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Transcriber language type
|
|
19
|
+
export type TranscriberLanguage = string;
|
|
20
|
+
|
|
21
|
+
// Transcriber message interface
|
|
22
|
+
export interface TranscriberMessage {
|
|
23
|
+
segmentId: string;
|
|
24
|
+
speakerUserId: string;
|
|
25
|
+
sourceText: string;
|
|
26
|
+
translationTexts?: Map<string, string>;
|
|
27
|
+
timestamp: number;
|
|
28
|
+
isCompleted: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Event callback types
|
|
32
|
+
export interface RealtimeTranscriberEventInfoMap {
|
|
33
|
+
[RealtimeTranscriberEvent.onReceiveTranscriberMessage]: {
|
|
34
|
+
roomId: string | number;
|
|
35
|
+
message: TranscriberMessage;
|
|
36
|
+
};
|
|
37
|
+
[RealtimeTranscriberEvent.onRealtimeTranscriberStarted]: {
|
|
38
|
+
roomId: string | number;
|
|
39
|
+
transcriberRobotId: string;
|
|
40
|
+
sourceLanguage: string;
|
|
41
|
+
};
|
|
42
|
+
[RealtimeTranscriberEvent.onRealtimeTranscriberStopped]: {
|
|
43
|
+
roomId: string | number;
|
|
44
|
+
transcriberRobotId: string;
|
|
45
|
+
};
|
|
46
|
+
[RealtimeTranscriberEvent.onRealtimeTranscriberError]: {
|
|
47
|
+
roomId: string | number;
|
|
48
|
+
transcriberRobotId: string;
|
|
49
|
+
error: number;
|
|
50
|
+
errorMessage: string;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type RealtimeTranscriberEventCallback = <T extends RealtimeTranscriberEvent>(
|
|
55
|
+
eventInfo: RealtimeTranscriberEventInfoMap[T]
|
|
56
|
+
) => void;
|
|
57
|
+
|
|
58
|
+
const TUIStore: ITUIStore = TuiStore.getInstance();
|
|
59
|
+
|
|
60
|
+
export default class AIAssistant {
|
|
61
|
+
static instance: AIAssistant;
|
|
62
|
+
private _callService: any;
|
|
63
|
+
private eventListeners = new Map<RealtimeTranscriberEvent, RealtimeTranscriberEventCallback[]>();
|
|
64
|
+
|
|
65
|
+
constructor(options: { callService: any }) {
|
|
66
|
+
this._callService = options.callService;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static getInstance(options: { callService: any }) {
|
|
17
70
|
if (!AIAssistant.instance) {
|
|
18
|
-
AIAssistant.instance = new AIAssistant();
|
|
71
|
+
AIAssistant.instance = new AIAssistant(options);
|
|
19
72
|
}
|
|
20
73
|
return AIAssistant.instance;
|
|
21
74
|
}
|
|
22
75
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Get AI Transcriber Manager instance
|
|
78
|
+
* @returns AITranscriberManager instance or null if not available
|
|
79
|
+
*/
|
|
80
|
+
private getTranscriberManager = () => {
|
|
81
|
+
const callEngine = this._callService?.getTUICallEngineInstance();
|
|
82
|
+
if (!callEngine) {
|
|
83
|
+
console.warn(`${NAME.PREFIX}Failed to get call engine instance.`);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
28
86
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
87
|
+
const trtcCloud = callEngine.getTRTCCloudInstance?.();
|
|
88
|
+
if (!trtcCloud || !trtcCloud.getAITranscriberManager) {
|
|
89
|
+
console.warn(`${NAME.PREFIX}AI Transcriber not supported.`);
|
|
90
|
+
return null;
|
|
33
91
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
92
|
+
|
|
93
|
+
return trtcCloud.getAITranscriberManager();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
private triggerEvent = <T extends RealtimeTranscriberEvent>(
|
|
97
|
+
event: T,
|
|
98
|
+
eventInfo: RealtimeTranscriberEventInfoMap[T],
|
|
99
|
+
): void => {
|
|
100
|
+
const listeners = this.eventListeners.get(event);
|
|
101
|
+
if (listeners) {
|
|
102
|
+
listeners.forEach((callback) => {
|
|
103
|
+
try {
|
|
104
|
+
callback(eventInfo);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`${NAME.PREFIX}Error in event callback for ${event}:`, error);
|
|
107
|
+
}
|
|
39
108
|
});
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
public startRealtimeTranscriber = async (config: {
|
|
113
|
+
sourceLanguage: TranscriberLanguage;
|
|
114
|
+
translationLanguages?: TranscriberLanguage[];
|
|
115
|
+
}) => {
|
|
116
|
+
const transcriberManager = this.getTranscriberManager();
|
|
117
|
+
if (!transcriberManager) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const transcriberRobotId = await transcriberManager.startRealtimeTranscriber(config);
|
|
123
|
+
|
|
124
|
+
TUIStore.update(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID, transcriberRobotId);
|
|
125
|
+
TUIStore.update(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_RUNNING, true);
|
|
126
|
+
return transcriberRobotId;
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(`${NAME.PREFIX}startRealtimeTranscriber error:`, error);
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
public stopRealtimeTranscriber = async () => {
|
|
134
|
+
const transcriberManager = this.getTranscriberManager();
|
|
135
|
+
if (!transcriberManager) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const transcriberRobotId = TUIStore.getData(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID);
|
|
141
|
+
|
|
142
|
+
if (transcriberRobotId) {
|
|
143
|
+
await transcriberManager.stopRealtimeTranscriber(transcriberRobotId);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
TUIStore.update(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID, null);
|
|
147
|
+
TUIStore.update(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_RUNNING, false);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error(`${NAME.PREFIX}stopRealtimeTranscriber error:`, error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
public updateRealTimeTranscriber = async (config: {
|
|
155
|
+
sourceLanguage: TranscriberLanguage;
|
|
156
|
+
translationLanguages?: TranscriberLanguage[];
|
|
157
|
+
}) => {
|
|
158
|
+
const transcriberManager = this.getTranscriberManager();
|
|
159
|
+
if (!transcriberManager) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
try {
|
|
164
|
+
const currentTranscriberRobotId = TUIStore.getData(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID);
|
|
165
|
+
|
|
166
|
+
if (currentTranscriberRobotId) {
|
|
167
|
+
await transcriberManager.stopRealtimeTranscriber(currentTranscriberRobotId);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const newTranscriberRobotId = await transcriberManager.startRealtimeTranscriber(config);
|
|
171
|
+
TUIStore.update(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID, newTranscriberRobotId);
|
|
172
|
+
|
|
173
|
+
return newTranscriberRobotId;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
console.error(`${NAME.PREFIX}updateRealTimeTranscriber error:`, error);
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
public subscribeEvent = (event: RealtimeTranscriberEvent, callback: RealtimeTranscriberEventCallback) => {
|
|
181
|
+
if (!this.eventListeners.has(event)) {
|
|
182
|
+
this.eventListeners.set(event, []);
|
|
183
|
+
}
|
|
184
|
+
this.eventListeners.get(event)?.push(callback);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
public unsubscribeEvent = (event: RealtimeTranscriberEvent, callback: RealtimeTranscriberEventCallback) => {
|
|
188
|
+
const listeners = this.eventListeners.get(event);
|
|
189
|
+
if (listeners) {
|
|
190
|
+
const index = listeners.indexOf(callback);
|
|
191
|
+
if (index > -1) {
|
|
192
|
+
listeners.splice(index, 1);
|
|
193
|
+
}
|
|
194
|
+
if (listeners.length === 0) {
|
|
195
|
+
this.eventListeners.delete(event);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
private onReceiveTranscriberMessage = (
|
|
201
|
+
_roomId: string | number,
|
|
202
|
+
message: {
|
|
203
|
+
segmentId: string;
|
|
204
|
+
speakerUserId: string;
|
|
205
|
+
sourceText: string;
|
|
206
|
+
translationTexts?: Map<string, string>;
|
|
207
|
+
timestamp: number;
|
|
208
|
+
isCompleted: boolean;
|
|
209
|
+
},
|
|
210
|
+
) => {
|
|
211
|
+
const { segmentId } = message;
|
|
212
|
+
let realtimeMessageList: TranscriberMessage[] = TUIStore.getData(StoreName.CALL, NAME.REALTIME_MESSAGE_LIST) || [];
|
|
213
|
+
|
|
214
|
+
const idx = realtimeMessageList.findIndex(msg => msg.segmentId === segmentId);
|
|
215
|
+
if (idx >= 0) {
|
|
216
|
+
realtimeMessageList[idx] = message;
|
|
40
217
|
} else {
|
|
41
|
-
|
|
218
|
+
realtimeMessageList.push(message);
|
|
42
219
|
}
|
|
43
|
-
|
|
220
|
+
|
|
221
|
+
TUIStore.update(StoreName.CALL, NAME.REALTIME_MESSAGE_LIST, [...realtimeMessageList]);
|
|
222
|
+
|
|
223
|
+
this.triggerEvent(RealtimeTranscriberEvent.onReceiveTranscriberMessage, {
|
|
224
|
+
roomId: _roomId,
|
|
225
|
+
message,
|
|
226
|
+
});
|
|
227
|
+
};
|
|
44
228
|
|
|
45
|
-
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
229
|
+
private onRealtimeTranscriberStarted = (_roomId: string | number, _transcriberRobotId: string, _sourceLanguage: string) => {
|
|
230
|
+
this.triggerEvent(RealtimeTranscriberEvent.onRealtimeTranscriberStarted, {
|
|
231
|
+
roomId: _roomId,
|
|
232
|
+
transcriberRobotId: _transcriberRobotId,
|
|
233
|
+
sourceLanguage: _sourceLanguage,
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
private onRealtimeTranscriberStopped = (_roomId: string | number, _transcriberRobotId: string) => {
|
|
238
|
+
this.triggerEvent(RealtimeTranscriberEvent.onRealtimeTranscriberStopped, {
|
|
239
|
+
roomId: _roomId,
|
|
240
|
+
transcriberRobotId: _transcriberRobotId,
|
|
241
|
+
});
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
private onRealtimeTranscriberError = (_roomId: string | number, _transcriberRobotId: string, error: number, errorMessage: string) => {
|
|
245
|
+
this.triggerEvent(RealtimeTranscriberEvent.onRealtimeTranscriberError, {
|
|
246
|
+
roomId: _roomId,
|
|
247
|
+
transcriberRobotId: _transcriberRobotId,
|
|
248
|
+
error,
|
|
249
|
+
errorMessage,
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
public bindEvent = () => {
|
|
254
|
+
const transcriberManager = this.getTranscriberManager();
|
|
255
|
+
if (!transcriberManager) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
transcriberManager.addListener({
|
|
261
|
+
onReceiveTranscriberMessage: this.onReceiveTranscriberMessage,
|
|
262
|
+
onRealtimeTranscriberStarted: this.onRealtimeTranscriberStarted,
|
|
263
|
+
onRealtimeTranscriberStopped: this.onRealtimeTranscriberStopped,
|
|
264
|
+
onRealtimeTranscriberError: this.onRealtimeTranscriberError,
|
|
265
|
+
});
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error(`${NAME.PREFIX}bindEvent error:`, error);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
public unbindEvent = () => {
|
|
272
|
+
const transcriberManager = this.getTranscriberManager();
|
|
273
|
+
if (!transcriberManager) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
transcriberManager.removeListener({
|
|
279
|
+
onReceiveTranscriberMessage: this.onReceiveTranscriberMessage,
|
|
280
|
+
onRealtimeTranscriberStarted: this.onRealtimeTranscriberStarted,
|
|
281
|
+
onRealtimeTranscriberStopped: this.onRealtimeTranscriberStopped,
|
|
282
|
+
onRealtimeTranscriberError: this.onRealtimeTranscriberError,
|
|
283
|
+
});
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error(`${NAME.PREFIX}unbindEvent error:`, error);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
public reset = () => {
|
|
290
|
+
TUIStore.update(StoreName.CALL, NAME.TRANSCRIBER_ROBOT_ID, null);
|
|
291
|
+
TUIStore.update(StoreName.CALL, NAME.REALTIME_MESSAGE_LIST, []);
|
|
292
|
+
TUIStore.update(StoreName.CALL, NAME.IS_AI_TRANSCRIBER_ENABLED, false);
|
|
293
|
+
this.eventListeners.clear();
|
|
294
|
+
};
|
|
51
295
|
}
|
|
296
|
+
|
|
297
|
+
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
|
|
1
2
|
import TuiStore from '../TUIStore/tuiStore';
|
|
2
3
|
import { StoreName } from '../const/call';
|
|
3
4
|
import { NAME } from '../const/index';
|
|
4
|
-
import { t } from '../locales'
|
|
5
|
+
import { t } from '../locales';
|
|
5
6
|
const TUIStore = TuiStore.getInstance();
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const WEB_MODAL_ERROR_CODES = [
|
|
8
9
|
-1001,
|
|
9
10
|
-1002,
|
|
10
11
|
-1101,
|
|
@@ -17,7 +18,7 @@ const MODAL_ERROR_CODES = [
|
|
|
17
18
|
101002,
|
|
18
19
|
];
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
+
const WEB_MODAL_ERROR_MAP = {
|
|
21
22
|
'-1001': {
|
|
22
23
|
id: 10001,
|
|
23
24
|
key: 'error.10001'
|
|
@@ -60,16 +61,22 @@ const MODAL_ERROR_MAP = {
|
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
|
|
64
|
+
|
|
63
65
|
export function handleModalError(error) {
|
|
64
66
|
if (!error || !error?.code) {
|
|
65
67
|
return;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
handleWebModalError(error);
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleWebModalError(error) {
|
|
75
|
+
if (!WEB_MODAL_ERROR_CODES.includes(error.code)) {
|
|
69
76
|
return;
|
|
70
77
|
}
|
|
71
78
|
|
|
72
|
-
const errorInfo =
|
|
79
|
+
const errorInfo = WEB_MODAL_ERROR_MAP[error.code.toString()];
|
|
73
80
|
if (errorInfo) {
|
|
74
81
|
let content = t(errorInfo.key);
|
|
75
82
|
TUIStore.update(StoreName.CALL, NAME.MODAL_ERROR, {
|
|
@@ -78,4 +85,5 @@ export function handleModalError(error) {
|
|
|
78
85
|
title: t('error')
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
|
-
}
|
|
88
|
+
}
|
|
89
|
+
|
|
@@ -10,6 +10,7 @@ export class BellContext {
|
|
|
10
10
|
private _calleeBellFilePath: string = DEFAULT_CALLEE_BELL_FILEPATH;
|
|
11
11
|
private _callRole: string = CallRole.UNKNOWN;
|
|
12
12
|
private _callStatus: string = CallStatus.IDLE;
|
|
13
|
+
private _isPlaying: boolean = false;
|
|
13
14
|
|
|
14
15
|
constructor() {
|
|
15
16
|
this._bellContext = new Audio();
|
|
@@ -39,14 +40,26 @@ export class BellContext {
|
|
|
39
40
|
async play() {
|
|
40
41
|
try {
|
|
41
42
|
if (this._callStatus !== CallStatus.CALLING) {
|
|
42
|
-
return
|
|
43
|
+
return;
|
|
43
44
|
}
|
|
45
|
+
// iOS 优化:增加更严格的状态检查
|
|
46
|
+
if (this._callStatus !== CallStatus.CALLING || this._isPlaying) {
|
|
47
|
+
console.warn(`${NAME.PREFIX}play skipped, callStatus: ${this._callStatus}, isPlaying: ${this._isPlaying}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this._isPlaying = true;
|
|
44
51
|
this.setBellSrc();
|
|
45
52
|
if (this._callRole === CallRole.CALLEE && !this._isMuteBell) {
|
|
53
|
+
// 再次检查状态,避免在设置过程中状态已变更
|
|
54
|
+
if (!this._isPlaying || this._callStatus !== CallStatus.CALLING) return;
|
|
46
55
|
await this._bellContext.play();
|
|
56
|
+
return;
|
|
47
57
|
}
|
|
48
58
|
if (this._callRole === CallRole.CALLER) {
|
|
59
|
+
// 再次检查状态,避免在设置过程中状态已变更
|
|
60
|
+
if (!this._isPlaying || this._callStatus !== CallStatus.CALLING) return;
|
|
49
61
|
await this._bellContext.play();
|
|
62
|
+
return;
|
|
50
63
|
}
|
|
51
64
|
} catch (error) {
|
|
52
65
|
console.warn(`${NAME.PREFIX}Failed to play audio file, ${error}`);
|
|
@@ -55,7 +68,8 @@ export class BellContext {
|
|
|
55
68
|
|
|
56
69
|
async stop() {
|
|
57
70
|
try {
|
|
58
|
-
|
|
71
|
+
this._isPlaying = false;
|
|
72
|
+
await this._bellContext?.pause();
|
|
59
73
|
} catch (error) {
|
|
60
74
|
console.warn(`${NAME.PREFIX}Failed to stop audio file, ${error}`);
|
|
61
75
|
}
|
|
@@ -78,11 +92,20 @@ export class BellContext {
|
|
|
78
92
|
this._calleeBellFilePath = '';
|
|
79
93
|
this._callRole = CallRole.UNKNOWN;
|
|
80
94
|
this._callStatus = CallStatus.IDLE;
|
|
95
|
+
this._isPlaying = false;
|
|
81
96
|
this._bellContext.pause();
|
|
82
97
|
this._bellContext = null;
|
|
83
98
|
} catch (error) {
|
|
84
99
|
console.warn(`${NAME.PREFIX}Failed to destroy, ${error}`);
|
|
85
100
|
}
|
|
86
101
|
}
|
|
102
|
+
|
|
103
|
+
private _delay(ms: number): any {
|
|
104
|
+
return new Promise((resolve: any) => setTimeout(resolve, ms));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private _delayCallback(callback: () => void, ms: number) {
|
|
108
|
+
setTimeout(callback, ms);
|
|
109
|
+
}
|
|
87
110
|
|
|
88
111
|
}
|
|
@@ -90,6 +90,9 @@ export default class EngineEventHandler {
|
|
|
90
90
|
const callStatus = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
|
|
91
91
|
|
|
92
92
|
if (callStatus === CallStatus.CALLING && callRole === CallRole.CALLER) {
|
|
93
|
+
// iOS 优化:主叫状态变更时立即停止铃声
|
|
94
|
+
this._callService?._bellContext?.stop();
|
|
95
|
+
|
|
93
96
|
TUIStore.update(StoreName.CALL, NAME.CALL_STATUS, CallStatus.CONNECTED);
|
|
94
97
|
this._callService?.startTimer();
|
|
95
98
|
}
|
|
@@ -183,14 +186,16 @@ export default class EngineEventHandler {
|
|
|
183
186
|
}, StoreName.CALL);
|
|
184
187
|
}
|
|
185
188
|
private async _handleOnCallBegin(event: any): Promise<void> {
|
|
189
|
+
// iOS 优化:ON_CALL_BEGIN 事件时立即停止铃声
|
|
190
|
+
this._callService?._bellContext?.stop();
|
|
186
191
|
this._callerChangeToConnected();
|
|
187
192
|
TUIStore.update(StoreName.CALL, NAME.CALL_TIPS, { text: 'answered', duration: 2000 });
|
|
188
193
|
await this._callService.openMicrophone();
|
|
189
194
|
console.log(`${NAME.PREFIX}accept event data: ${JSON.stringify(event)}.`);
|
|
190
195
|
}
|
|
191
196
|
private async _handleUserEnter(event: any): Promise<void> {
|
|
192
|
-
this._callerChangeToConnected();
|
|
193
197
|
const { userID: userId, data } = analyzeEventData(event);
|
|
198
|
+
this._callerChangeToConnected();
|
|
194
199
|
await this._addUserToRemoteUserInfoList(userId);
|
|
195
200
|
let remoteUserInfoList = TUIStore.getData(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST);
|
|
196
201
|
remoteUserInfoList = remoteUserInfoList.map((obj: IUserInfo) => {
|