Files
zyt/TUICallKit-Vue3/TUIKit/states/TUICallService/CallService/index.ts
T
2026-03-11 09:49:47 +08:00

544 lines
24 KiB
TypeScript

import { IUserInfo, ISelfInfoParams, IInitParams } from '../interface/ICallService';
import { CallMediaType, CameraPosition, AudioPlayBackDevice, LOG_LEVEL, devicePermissions } from '@trtc/call-engine-lite-wx';
import { ICallsParam, IInviteUserParam } from '@trtc/call-engine-lite-wx';
import { StoreName, CallStatus, NAME, CALL_DATA_KEY, CallRole, COMPONENT, FeatureButton, ButtonState } from '../const/index';
import { TUICallEngine } from '@trtc/call-engine-lite-wx';
import { beforeCall, handlePackageError } from './miniProgram';
import { CallTips, t } from '../locales/index';
import { handleModalError } from './UIKitModal';
import { handleRepeatedCallError, performanceNow } from '../utils/common-utils';
import { getRemoteUserProfile, noDevicePermissionToast, setLocalUserInfoAudioVideoAvailable } from './utils';
import { ITUIStore } from '../interface/index';
import TuiStore from '../TUIStore/tuiStore';
import ChatCombine from './chatCombine';
import EngineEventHandler from './engineEventHandler';
const TUIStore: ITUIStore = TuiStore.getInstance();
const version = '<@VERSION@>';
export { TUIStore };
const defaultOfflinePushInfo = { title: '', description: t('you have a new call') };
export default class TUICallService {
static instance: TUICallService;
public _tuiCallEngine: any;
private _tim: any = null;
private _timerId: any = -1;
private _startTimeStamp: number = performanceNow();
private _isFromChat: boolean = false;
private _offlinePushInfo = null;
private _permissionCheckTimer: any = null;
private _chatCombine: any = null;
private _engineEventHandler: any = null;
constructor() {
console.log(`${NAME.PREFIX}version: ${version}`);
this._watchTUIStore();
this._engineEventHandler = EngineEventHandler.getInstance({ callService: this });
this._chatCombine = ChatCombine.getInstance({ callService: this });
}
static getInstance() {
if (!TUICallService.instance) {
TUICallService.instance = new TUICallService();
}
return TUICallService.instance;
}
public async init(params: IInitParams) {
try {
if (this._tuiCallEngine) return;
// @ts-ignore
let { userID, tim, userSig, sdkAppID, SDKAppID, isFromChat, component = COMPONENT.TUI_CALL_KIT } = params;
this._tim = tim;
console.log(`${NAME.PREFIX}init sdkAppId: ${sdkAppID || SDKAppID}, userId: ${userID}`);
this._tuiCallEngine = TUICallEngine.createInstance({
tim,
sdkAppID: sdkAppID || SDKAppID, // 兼容传入 SDKAppID 的问题
callkitVersion: version,
isFromChat: isFromChat || false,
component,
scene: 'wx-uniapp-vue3-lite',
});
this._addListenTuiCallEngineEvent();
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { userId: userID });
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { userId: userID });
await this._tuiCallEngine.login({ userID, userSig, assetsPath: '' }); // web && mini
const uiConfig = TUIStore.getData(StoreName.CALL, NAME.CUSTOM_UI_CONFIG);
this._tuiCallEngine?.reportLog?.({
name: 'TUICallkit.init',
data: {
uiConfig,
}
});
} catch (error) {
console.error(`${NAME.PREFIX}init failed, error: ${error}.`);
throw error;
}
}
// component destroy
public async destroyed() {
try {
const currentCallStatus = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
if (currentCallStatus !== CallStatus.IDLE) {
throw new Error(`please destroyed when status is idle, current status: ${currentCallStatus}`);
}
if (this._tuiCallEngine) {
this._removeListenTuiCallEngineEvent();
await this._tuiCallEngine.destroyInstance();
this._tuiCallEngine = null;
this._unwatchTUIStore();
}
} catch (error) {
console.error(`${NAME.PREFIX}destroyed failed, error: ${error}.`);
throw error;
}
}
// ===============================【通话操作】===============================
public async calls(callsParams: ICallsParam) {
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) !== CallStatus.IDLE) return; // avoid double click when application stuck
try {
TUIStore.update(StoreName.CALL, NAME.PUSHER_ID, NAME.NEW_PUSHER);
const { userIDList, type, chatGroupID, offlinePushInfo } = callsParams;
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) !== CallStatus.IDLE) return;
const remoteUserInfoList = userIDList.map(userId => ({ userId }));
await this._updateCallStoreBeforeCall(type, remoteUserInfoList, chatGroupID);
callsParams.offlinePushInfo = { ...defaultOfflinePushInfo, ...offlinePushInfo };
const response = await this._tuiCallEngine.calls(callsParams);
await this._updateCallStoreAfterCall(userIDList, response);
} catch (error: any) {
handleModalError(error);
this._handleCallError(error, 'calls');
}
}
// public async inviteUser(params: IInviteUserParam) {
// if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.IDLE) return; // avoid double click when application stuck
// try {
// const { userIDList } = params;
// let inviteUserInfoList = await getRemoteUserProfile(userIDList, this.getTim());
// const remoteUserInfoList = TUIStore.getData(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST);
// const userIDListNotInRemoteUserInfoList = userIDList.filter(userId => {
// return !remoteUserInfoList.some(remoteUserInfo => remoteUserInfo.userId === userId);
// });
// if (userIDListNotInRemoteUserInfoList.length === 0) {
// return;
// }
// TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST, [...remoteUserInfoList, ...inviteUserInfoList]);
// TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_EXCLUDE_VOLUMN_LIST, [...remoteUserInfoList, ...inviteUserInfoList]);
// this._tuiCallEngine && await this._tuiCallEngine.inviteUser(params);
// } catch (error: any) {
// console.error(`${NAME.PREFIX}inviteUser failed, error: ${error}.`);
// }
// }
// public async join(params) {
// if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.CONNECTED) return; // avoid double click when application stuck
// try {
// const response = await this._tuiCallEngine.join(params);
// TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
// this.startTimer();
// const updateStoreParams = {
// [NAME.CALL_ROLE]: CallRole.CALLEE,
// [NAME.IS_GROUP]: true,
// [NAME.CALL_STATUS]: CallStatus.CONNECTED,
// [NAME.CALL_MEDIA_TYPE]: TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE) || CallMediaType.AUDIO, // default audio callMediaType
// };
// TUIStore.updateStore(updateStoreParams, StoreName.CALL);
// this.setSoundMode(params.type === CallMediaType.AUDIO ? AudioPlayBackDevice.EAR : AudioPlayBackDevice.SPEAKER);
// const localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
// TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { ...localUserInfo, isEnter: true });
// TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { ...localUserInfo, isEnter: true });
// await this.openMicrophone();
// setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO);
// } catch (error) {
// this._handleCallError(error, 'join');
// }
// }
// ===============================【其它对外接口】===============================
public getTUICallEngineInstance(): any {
return this?._tuiCallEngine || null;
}
public setLogLevel(level: LOG_LEVEL) {
this?._tuiCallEngine?.setLogLevel(level);
}
public enableFloatWindow(enable: boolean) {
TUIStore.update(StoreName.CALL, NAME.ENABLE_FLOAT_WINDOW, enable);
}
public async setSelfInfo(params: ISelfInfoParams) {
const { nickName, avatar } = params;
try {
await this._tuiCallEngine.setSelfInfo(nickName, avatar);
} catch (error) {
console.error(`${NAME.PREFIX}setSelfInfo failed, error: ${error}.`);
}
}
public async enableMuteMode(enable: boolean) {
try {
} catch (error) {
console.warn(`${NAME.PREFIX}enableMuteMode failed, error: ${error}.`);
}
}
// =============================【实验性接口】=============================
public callExperimentalAPI(jsonStr: string) {
const jsonObj = JSON.parse(jsonStr);
if (jsonObj === jsonStr) return;
const { api, params } = jsonObj;
if (!api || !params) return;
try {
switch(api) {
case 'forceUseV2API':
const { enable } = params;
TUIStore.update(StoreName.CALL, NAME.IS_FORCE_USE_V2_API, !!enable);
break;
default:
break;
}
} catch (error) {
this._tuiCallEngine?.reportLog?.({ name: 'TUICallKit.callExperimentalAPI.fail', data: { error } });
}
}
// =============================【内部按钮操作方法】=============================
public async accept() {
const callStatus = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
this._tuiCallEngine?.reportLog?.({
name: 'TUICallKit.accept.start',
data: { callStatus },
});
if (callStatus === CallStatus.CONNECTED) return; // avoid double click when application stuck, especially for miniProgram
try {
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
const deviceMap = {
microphone: true,
camera: callMediaType === CallMediaType.VIDEO,
};
const currentDevicePermission = await this._tuiCallEngine.deviceCheck(deviceMap);
if (!currentDevicePermission) {
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
if (typeof devicePermissions === 'function') {
await devicePermissions(callMediaType);
}
}
TUIStore.update(StoreName.CALL, NAME.PUSHER_ID, NAME.NEW_PUSHER);
const response = await this._tuiCallEngine.accept();
await this._handleAcceptResponse(response);
} catch (error) {
this._tuiCallEngine?.reportLog?.({
name: 'TUICallKit.accept.fail',
level: 'error',
error,
});
if (handleRepeatedCallError(error)) return;
handleModalError(error);
noDevicePermissionToast(error, CallMediaType.AUDIO, this._tuiCallEngine);
this._resetCallStore();
}
}
private async _handleAcceptResponse(response) {
if (response) {
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.CONNECTED) return;
// 小程序接通时会进行授权弹框, 状态需要放在 accept 后, 否则先接通后再拉起权限设置
TUIStore.update(StoreName.CALL, NAME.CALL_STATUS, CallStatus.CONNECTED);
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
this.startTimer();
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
const isCameraDefaultStateClose = this._getFeatureButtonDefaultState(FeatureButton.Camera) === ButtonState.Close;
(callMediaType === CallMediaType.VIDEO) && !isCameraDefaultStateClose && await this.openCamera(NAME.LOCAL_VIDEO);
this.setSoundMode(callMediaType === CallMediaType.AUDIO ? AudioPlayBackDevice.EAR : AudioPlayBackDevice.SPEAKER);
const localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { ...localUserInfo, isEnter: true });
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { ...localUserInfo, isEnter: true });
setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO); // web && mini default open audio
}
}
public async hangup() {
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.IDLE) return; // avoid double click when application stuck
await this._tuiCallEngine.hangup();
this._resetCallStore();
}
public async reject() {
if (TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS) === CallStatus.IDLE) return; // avoid double click when application stuck
await this._tuiCallEngine.reject();
this._resetCallStore();
}
public async openCamera(videoViewDomID: string) {
try {
const currentPosition = TUIStore.getData(StoreName.CALL, NAME.CAMERA_POSITION);
const isFrontCamera = currentPosition === CameraPosition.FRONT ? true : false;
this._tuiCallEngine.openCamera(videoViewDomID, isFrontCamera);
setLocalUserInfoAudioVideoAvailable(true, NAME.VIDEO);
} catch (error: any) {
noDevicePermissionToast(error, CallMediaType.VIDEO, this._tuiCallEngine);
console.error(`${NAME.PREFIX}openCamera error: ${error}.`);
}
}
public async closeCamera() {
try {
await this._tuiCallEngine.closeCamera();
setLocalUserInfoAudioVideoAvailable(false, NAME.VIDEO);
} catch (error: any) {
console.error(`${NAME.PREFIX}closeCamera error: ${error}.`);
}
}
public async openMicrophone() {
try {
await this._tuiCallEngine.openMicrophone();
setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO);
} catch (error: any) {
console.error(`${NAME.PREFIX}openMicrophone failed, error: ${error}.`);
}
}
public async closeMicrophone() {
try {
await this._tuiCallEngine.closeMicrophone();
setLocalUserInfoAudioVideoAvailable(false, NAME.AUDIO);
} catch (error: any) {
console.error(`${NAME.PREFIX}closeMicrophone failed, error: ${error}.`);
}
}
public switchScreen(userId: string) {
if(!userId) return;
TUIStore.update(StoreName.CALL, NAME.BIG_SCREEN_USER_ID, userId);
}
public async switchCamera() {
const currentPosition = TUIStore.getData(StoreName.CALL, NAME.CAMERA_POSITION);
const targetPosition = currentPosition === CameraPosition.BACK ? CameraPosition.FRONT : CameraPosition.BACK;
try {
await this._tuiCallEngine.switchCamera(targetPosition);
TUIStore.update(StoreName.CALL, NAME.CAMERA_POSITION, targetPosition);
} catch (error) {
console.error(`${NAME.PREFIX}_switchCamera failed, error: ${error}.`);
}
}
public setSoundMode(type?: string): void {
try {
let isEarPhone = TUIStore.getData(StoreName.CALL, NAME.IS_EAR_PHONE);
const soundMode = type || (isEarPhone ? AudioPlayBackDevice.SPEAKER : AudioPlayBackDevice.EAR); // UI 层切换时传参数
this._tuiCallEngine?.selectAudioPlaybackDevice(soundMode);
if (type) {
isEarPhone = type === AudioPlayBackDevice.EAR;
} else {
isEarPhone = !isEarPhone;
}
TUIStore.update(StoreName.CALL, NAME.IS_EAR_PHONE, isEarPhone);
} catch (error) {
console.error(`${NAME.PREFIX}setSoundMode failed, error: ${error}.`);
}
}
// ==========================【TUICallEngine 事件处理】==========================
private _addListenTuiCallEngineEvent() {
this._engineEventHandler.addListenTuiCallEngineEvent();
}
private _removeListenTuiCallEngineEvent() {
this._engineEventHandler.removeListenTuiCallEngineEvent();
}
// 处理用户异常退出的情况, 小程序 ”右滑“、"左上角退出"; web 页面关闭浏览器或关闭 tab 页面
public async handleExceptionExit(event?: any) {
try {
const callStatus = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
const callRole = TUIStore.getData(StoreName.CALL, NAME.CALL_ROLE);
this._tuiCallEngine?.reportLog?.({ name: 'TUICallkit.handleExceptionExit', data: { callStatus, callRole } });
if (callStatus === CallStatus.IDLE) return;
// 在呼叫状态下,被叫调用 reject,主叫调用 hangup
if (callStatus === CallStatus.CALLING) {
if (callRole === CallRole.CALLER) {
await this?.hangup();
} else {
await this?.reject();
}
}
if (callStatus === CallStatus.CONNECTED) {
await this?.hangup();
}
this?._resetCallStore();
} catch (error) {
console.error(`${NAME.PREFIX} handleExceptionExit failed, error: ${error}.`);
}
if (event) {
event.returnValue = '';
}
}
// 通话时长更新
public startTimer(): void {
if (this._timerId === -1) {
this._startTimeStamp = performanceNow();
this._timerId = setInterval(() => this._updateCallDuration(), 1000);
}
}
private _stopTimer(): void {
if (this._timerId !== -1) {
clearInterval(this._timerId);
this._timerId = -1;
}
}
// =========================【private methods for service use】=========================
// 处理 “呼叫” 抛出的异常
private _handleCallError(error: any, methodName?: string) {
this._permissionCheckTimer && clearInterval(this._permissionCheckTimer);
if (handleRepeatedCallError(error)) return;
noDevicePermissionToast(error, CallMediaType.AUDIO, this._tuiCallEngine);
console.error(`${NAME.PREFIX}${methodName} failed, error: ${error}.`);
this._resetCallStore();
throw error;
}
private async _updateCallStoreBeforeCall(type: number, remoteUserInfoList: IUserInfo[], groupID?: string): Promise<void> {
let callTips = CallTips.CALLER_CALLING_MSG;
let updateStoreParams: any = {
[NAME.CALL_MEDIA_TYPE]: type,
[NAME.CALL_ROLE]: CallRole.CALLER,
[NAME.REMOTE_USER_INFO_LIST]: remoteUserInfoList,
[NAME.REMOTE_USER_INFO_EXCLUDE_VOLUMN_LIST]: remoteUserInfoList,
[NAME.IS_GROUP]: (!!groupID || remoteUserInfoList.length > 1),
[NAME.CALL_TIPS]: callTips,
[NAME.GROUP_ID]: groupID
};
const callStatus = await beforeCall(type, this); // 如果没有权限, 此时为 false. 因此需要在 call 后设置为 calling. 和 web 存在差异
console.log(`${NAME.PREFIX}mini beforeCall return callStatus: ${callStatus}.`);
TUIStore.updateStore({ ...updateStoreParams, [NAME.CALL_STATUS]: callStatus }, StoreName.CALL);
const remoteUserInfoLists = await getRemoteUserProfile(remoteUserInfoList.map(obj => obj.userId), this.getTim());
if (remoteUserInfoLists.length > 0) {
TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST, remoteUserInfoLists);
TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_EXCLUDE_VOLUMN_LIST, remoteUserInfoLists);
}
const deviceMap = {
microphone: true,
camera: type === CallMediaType.VIDEO,
};
let hasDevicePermission = await this._tuiCallEngine.deviceCheck(deviceMap);
if (!hasDevicePermission) {
this._permissionCheckTimer && clearInterval(this._permissionCheckTimer);
this._permissionCheckTimer = setInterval(async () => {
hasDevicePermission = await this._tuiCallEngine.deviceCheck(deviceMap);
if (hasDevicePermission && this._permissionCheckTimer) {
clearInterval(this._permissionCheckTimer);
TUIStore.update(StoreName.CALL, NAME.CALL_STATUS, CallStatus.CALLING);
}
}, 500);
}
}
private async _updateCallStoreAfterCall(userIdList: string[], response: any) {
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
let localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
TUIStore.update(StoreName.CALL, NAME.CALL_INFO, { mediaType: callMediaType, inviterId: localUserInfo.userId });
if (response) {
TUIStore.update(StoreName.CALL, NAME.IS_CLICKABLE, true);
this.setSoundMode(callMediaType === CallMediaType.AUDIO ? AudioPlayBackDevice.EAR : AudioPlayBackDevice.SPEAKER);
const isCameraDefaultStateClose = this._getFeatureButtonDefaultState(FeatureButton.Camera) === ButtonState.Close;
if((callMediaType === CallMediaType.VIDEO) && !isCameraDefaultStateClose) {
await this.openCamera(NAME.LOCAL_VIDEO);
}
localUserInfo = TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO);
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, { ...localUserInfo, isEnter: true });
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, { ...localUserInfo, isEnter: true });
setLocalUserInfoAudioVideoAvailable(true, NAME.AUDIO); // web && mini, default open audio
} else {
this._permissionCheckTimer && clearInterval(this._permissionCheckTimer);
this._permissionCheckTimer = null;
this._resetCallStore();
}
}
private _getFeatureButtonDefaultState(buttonName: FeatureButton) {
const { button: buttonConfig } = TUIStore.getData(StoreName.CALL, NAME.CUSTOM_UI_CONFIG);
return buttonConfig?.[buttonName]?.state;
}
private _updateCallDuration(): void {
TUIStore.update(StoreName.CALL, NAME.DURATION, Math.round((performanceNow() - this._startTimeStamp) / 1000));
}
private _resetCallStore() {
this._stopTimer();
// localUserInfo, language 在通话结束后不需要清除
// callStatus 清除需要通知; isMinimized 也需要通知(basic-vue3 中切小窗关闭后, 再呼叫还是小窗, 因此需要通知到组件侧)
// isGroup 也不清除(engine 先抛 cancel 事件, 再抛 reject 事件)
// displayMode、videoResolution 也不能清除, 组件不卸载, 这些属性也需保留, 否则采用默认值.
// enableFloatWindow 不清除:开启/关闭悬浮窗功能。
let notResetOrNotifyKeys = Object.keys(CALL_DATA_KEY).filter((key) => {
switch (CALL_DATA_KEY[key]) {
case NAME.CALL_STATUS:
case NAME.LANGUAGE:
case NAME.IS_GROUP:
case NAME.ENABLE_FLOAT_WINDOW:
case NAME.LOCAL_USER_INFO:
case NAME.IS_FORCE_USE_V2_API:
case NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN: {
return false;
}
default: {
return true;
}
}
});
notResetOrNotifyKeys = notResetOrNotifyKeys.map(key => CALL_DATA_KEY[key]);
TUIStore.reset(StoreName.CALL, notResetOrNotifyKeys);
const callStatus = TUIStore.getData(StoreName.CALL, NAME.CALL_STATUS);
callStatus !== CallStatus.IDLE && TUIStore.reset(StoreName.CALL, [NAME.CALL_STATUS], true); // callStatus reset need notify
TUIStore.reset(StoreName.CALL, [NAME.IS_MINIMIZED], true); // isMinimized reset need notify
TUIStore.reset(StoreName.CALL, [NAME.IS_EAR_PHONE], true); // isEarPhone reset need notify
TUIStore.reset(StoreName.CALL, [NAME.PUSHER_ID], true); // pusher unload reset need notify
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO, {
...TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO),
isVideoAvailable: false,
isAudioAvailable: false,
});
TUIStore.update(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN, {
...TUIStore.getData(StoreName.CALL, NAME.LOCAL_USER_INFO_EXCLUDE_VOLUMN),
isVideoAvailable: false,
isAudioAvailable: false,
});
TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST, []);
TUIStore.update(StoreName.CALL, NAME.REMOTE_USER_INFO_EXCLUDE_VOLUMN_LIST, []);
TUIStore.update(StoreName.CALL, NAME.CAMERA_POSITION, CameraPosition.FRONT);
TUIStore.update(StoreName.CALL, NAME.CALL_INFO, {});
}
// =========================【监听 TUIStore 中的状态及处理】=========================
private _handleCallStatusChange = async (value: CallStatus) => {
try {
if (value === CallStatus.CALLING) {
} else {
// 状态变更通知
if (value === CallStatus.CONNECTED) {
const isGroup = TUIStore.getData(StoreName.CALL, NAME.IS_GROUP);
const callMediaType = TUIStore.getData(StoreName.CALL, NAME.CALL_MEDIA_TYPE);
const remoteUserInfoList = TUIStore.getData(StoreName.CALL, NAME.REMOTE_USER_INFO_LIST);
TUIStore.update(StoreName.CALL, NAME.CALL_TIPS, '');
if (!isGroup && callMediaType === CallMediaType.VIDEO) {
this.switchScreen(remoteUserInfoList[0].domId);
}
}
}
} catch (error) {
console.warn(`${NAME.PREFIX}handleCallStatusChange, ${error}.`);
}
};
private _watchTUIStore() {
TUIStore?.watch(StoreName.CALL, {
[NAME.CALL_STATUS]: this._handleCallStatusChange,
});
}
private _unwatchTUIStore() {
TUIStore?.unwatch(StoreName.CALL, {
[NAME.CALL_STATUS]: this._handleCallStatusChange,
});
}
// =========================【set、get methods】=========================
public getTim() {
if (this._tim) return this._tim;
if (!this._tuiCallEngine) {
console.warn(`${NAME.PREFIX}getTim warning: _tuiCallEngine Instance is not available.`);
return null;
}
return this._tuiCallEngine?.tim || this._tuiCallEngine?.getTim(); // mini support getTim interface
}
public setIsFromChat(isFromChat: boolean) {
this._isFromChat = isFromChat;
}
}