UNPKG

@tencentcloud/roomkit-electron-vue3

Version:

<h1 align="center"> TUIRoomKit</h1> Conference (TUIRoomKit) is a product suitable for multi-person audio and video conversation scenarios such as business meetings, webinars, and online education. By integrating this product, you can add room management,

573 lines (526 loc) 18.6 kB
import mitt from 'mitt'; import useGetRoomEngine from '../hooks/useRoomEngine'; import { EventType, IRoomService, RoomInitData, RoomParam } from './types'; import TUIRoomEngine, { TRTCVideoFillMode, TRTCVideoMirrorType, TRTCVideoRotation, TUIKickedOutOfRoomReason, TUIRole, TUIRoomEvents, } from '@tencentcloud/tuiroom-engine-electron'; import { useBasicStore } from '../stores/basic'; import { UserInfo, useRoomStore } from '../stores/room'; import { useChatStore } from '../stores/chat'; import useDeviceManager from '../hooks/useDeviceManager'; import logger from '../utils/common/logger'; import { isMobile } from '../utils/environment'; import i18n from '../locales'; import { MESSAGE_DURATION } from '../constants/message'; import { ComponentConfig, ComponentManager, ComponentName, } from './manager/componentManager'; import { ConfigManager, LanguageOption, Theme } from './manager/configManager'; import { SelfInfoOptions, UserManager } from './manager/userManager'; import { LifeCycleManager } from './manager/lifeCycleManager'; import { MediaManager } from './manager/mediaManager'; import { TrackingManager } from './manager/trackingManager'; import { JoinParams, RoomActionManager, StartParams, RoomParamsInfo, } from './manager/roomActionManager'; import { WaterMark } from './function/waterMark'; import { VirtualBackground } from './function/virtualBackground'; import { BasicBeauty } from './function/basicBeauty'; import { ScheduleConferenceManager } from './manager/scheduleConferenceManager'; import { ConferenceInvitationManager } from './manager/conferenceInvitationManager'; import { DataReportManager } from './manager/dataReportManager'; import { ErrorHandler } from './function/errorHandler'; import { ChatManager } from './manager/chatManager'; import { WidgetsManager } from './manager/widgetsManager'; import { TUILogin } from '@tencentcloud/tui-core'; import { AITask } from './function/aiTask'; import initWidgets from '../components/common/widgets'; const { t } = i18n.global; const logPrefix = '[RoomService]'; export const roomEngine = useGetRoomEngine(); export class RoomService implements IRoomService { static instance?: RoomService; public roomEngine = roomEngine; public t = t; private emitter = mitt(); public componentManager = new ComponentManager(this); public configManager = new ConfigManager(this); public userManager = new UserManager(this); public mediaManager = new MediaManager(this); public lifeCycleManager: LifeCycleManager = new LifeCycleManager(this); public roomActionManager: RoomActionManager = new RoomActionManager(this); public waterMark = new WaterMark(this); public virtualBackground = new VirtualBackground(this); public basicBeauty = new BasicBeauty(this); public scheduleConferenceManager: ScheduleConferenceManager = new ScheduleConferenceManager(this); public conferenceInvitationManager: ConferenceInvitationManager = new ConferenceInvitationManager(this); public dataReportManager: DataReportManager = new DataReportManager(); public errorHandler: ErrorHandler = new ErrorHandler(this); public chatManager: ChatManager = new ChatManager(this); public aiTask: AITask = new AITask(this); public trackingManager: TrackingManager = new TrackingManager(); public widgetsManager: WidgetsManager = new WidgetsManager(this); get basicStore() { return useBasicStore(); } get roomStore() { return useRoomStore(); } get chatStore() { return useChatStore(); } constructor() { this.lifeCycleManager.start(); this.initEventCtx(); TUIRoomEngine.once('ready', () => { this.bindRoomEngineEvents(); this.handleRoomEngineReady(); this.emit(EventType.SERVICE_READY); }); } private initEventCtx() { this.onError = this.onError.bind(this); this.onRoomDismissed = this.onRoomDismissed.bind(this); this.onUserNetworkQualityChanged = this.onUserNetworkQualityChanged.bind(this); this.onKickedOutOfRoom = this.onKickedOutOfRoom.bind(this); this.onSendMessageForUserDisableChanged = this.onSendMessageForUserDisableChanged.bind(this); this.onUserSigExpired = this.onUserSigExpired.bind(this); this.onKickedOffLine = this.onKickedOffLine.bind(this); this.onAllUserCameraDisableChanged = this.onAllUserCameraDisableChanged.bind(this); this.onAllUserMicrophoneDisableChanged = this.onAllUserMicrophoneDisableChanged.bind(this); this.onScreenShareForAllUserDisableChanged = this.onScreenShareForAllUserDisableChanged.bind(this); this.onUserInfoChanged = this.onUserInfoChanged.bind(this); } static getInstance(): RoomService { if (!RoomService.instance) { RoomService.instance = new RoomService(); } return RoomService.instance; } static destroyInstance(): void { if (!RoomService.instance) return; RoomService.instance.lifeCycleManager.stop(); RoomService.instance.unBindRoomEngineEvents(); RoomService.instance.waterMark.dispose(); RoomService.instance.virtualBackground.dispose(); RoomService.instance.basicBeauty.dispose(); RoomService.instance.scheduleConferenceManager.dispose(); RoomService.instance.conferenceInvitationManager.dispose(); RoomService.instance.mediaManager.dispose(); RoomService.instance.chatManager.dispose(); RoomService.instance = undefined; } public useExtension(extension: any) { // eslint-disable-next-line no-underscore-dangle extension._bind(this); } public getRoomContainer(): HTMLElement | Element { return ( document.fullscreenElement || document.getElementById('roomContainer') || document.body ); } public initMediaDeviceList() { useDeviceManager({ listenForDeviceChange: true }); } public bindRoomEngineEvents() { roomEngine.instance?.on(TUIRoomEvents.onError, this.onError); roomEngine.instance?.on( TUIRoomEvents.onRoomDismissed, this.onRoomDismissed ); roomEngine.instance?.on( TUIRoomEvents.onUserNetworkQualityChanged, this.onUserNetworkQualityChanged ); roomEngine.instance?.on( TUIRoomEvents.onKickedOutOfRoom, this.onKickedOutOfRoom ); roomEngine.instance?.on( TUIRoomEvents.onSendMessageForUserDisableChanged, this.onSendMessageForUserDisableChanged ); roomEngine.instance?.on( TUIRoomEvents.onUserSigExpired, this.onUserSigExpired ); roomEngine.instance?.on( TUIRoomEvents.onKickedOffLine, this.onKickedOffLine ); roomEngine.instance?.on( TUIRoomEvents.onAllUserCameraDisableChanged, this.onAllUserCameraDisableChanged ); roomEngine.instance?.on( TUIRoomEvents.onAllUserMicrophoneDisableChanged, this.onAllUserMicrophoneDisableChanged ); roomEngine.instance?.on( TUIRoomEvents.onScreenShareForAllUserDisableChanged, this.onScreenShareForAllUserDisableChanged ); roomEngine.instance?.on( TUIRoomEvents.onUserInfoChanged, this.onUserInfoChanged ); } public unBindRoomEngineEvents() { roomEngine.instance?.off(TUIRoomEvents.onError, this.onError); roomEngine.instance?.off( TUIRoomEvents.onRoomDismissed, this.onRoomDismissed ); roomEngine.instance?.off( TUIRoomEvents.onUserNetworkQualityChanged, this.onUserNetworkQualityChanged ); roomEngine.instance?.off( TUIRoomEvents.onKickedOutOfRoom, this.onKickedOutOfRoom ); roomEngine.instance?.off( TUIRoomEvents.onSendMessageForUserDisableChanged, this.onSendMessageForUserDisableChanged ); roomEngine.instance?.off( TUIRoomEvents.onUserSigExpired, this.onUserSigExpired ); roomEngine.instance?.off( TUIRoomEvents.onKickedOffLine, this.onKickedOffLine ); roomEngine.instance?.off( TUIRoomEvents.onAllUserCameraDisableChanged, this.onAllUserCameraDisableChanged ); roomEngine.instance?.off( TUIRoomEvents.onAllUserMicrophoneDisableChanged, this.onAllUserMicrophoneDisableChanged ); roomEngine.instance?.off( TUIRoomEvents.onScreenShareForAllUserDisableChanged, this.onScreenShareForAllUserDisableChanged ); roomEngine.instance?.off( TUIRoomEvents.onUserInfoChanged, this.onUserInfoChanged ); } private onError(error: any) { logger.error('roomEngine.onError: ', error); this.errorHandler.handleError(error, 'onError'); } private onRoomDismissed(eventInfo: { roomId: string }) { const { roomId } = eventInfo; logger.log(`${logPrefix}onRoomDismissed:`, roomId); this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, { title: t('Note'), message: t('The host closed the room.'), confirmButtonText: t('Sure'), duration: 5000, callback: async () => { this.emit(EventType.ROOM_DISMISS, {}); this.resetStore(); }, }); } private onUserNetworkQualityChanged(eventInfo: { userNetworkList: [] }) { this.basicStore.setLocalQuality(eventInfo.userNetworkList); } private async onKickedOutOfRoom(eventInfo: { roomId: string; reason: TUIKickedOutOfRoomReason; message: string; }) { const { roomId, reason, message } = eventInfo; try { let notice = ''; switch (reason) { case TUIKickedOutOfRoomReason.kKickedByAdmin: notice = t('kicked out of the room by the host'); break; case TUIKickedOutOfRoomReason.kKickedByLoggedOnOtherDevice: notice = t('Kicked out of the room on other devices'); break; case TUIKickedOutOfRoomReason.kKickedByServer: notice = t('kicked out of the room by serve'); break; case TUIKickedOutOfRoomReason.kNetworkDisconnected: notice = t('Network disconnection timeout, exiting room'); break; case TUIKickedOutOfRoomReason.kJoinRoomStatusInvalidDuringOffline: notice = t( 'You have been kicked out of a room or the room has been disbanded while you were offline' ); break; case TUIKickedOutOfRoomReason.kCountOfJoinedRoomsExceedLimit: notice = t('The number of joined rooms has exceeded the limit'); break; default: notice = t('kicked out of the room'); } this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, { title: t('Note'), message: notice, confirmButtonText: t('Sure'), callback: async () => { this.emit(EventType.KICKED_OUT, { roomId, reason, message }); this.resetStore(); }, }); } catch (error) { logger.error(`${logPrefix}onKickedOutOfRoom error:`, error); } } private onSendMessageForUserDisableChanged(data: { userId: string; isDisable: boolean; }) { const { userId, isDisable } = data; if (userId === this.roomStore.localUser.userId) { const tipMessage = isDisable ? t('You have been banned from text chat') : t('You are allowed to text chat'); this.emit(EventType.ROOM_NOTICE_MESSAGE, { code: -1, type: 'warning', message: tipMessage, duration: MESSAGE_DURATION.NORMAL, }); this.chatStore.setSendMessageDisableChanged(isDisable); } this.roomStore.setMuteUserChat(userId, isDisable); } private onUserSigExpired() { this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, { title: t('Note'), message: t('userSig has expired'), confirmButtonText: t('Sure'), callback: () => { this.emit(EventType.USER_SIG_EXPIRED, {}); this.resetStore(); }, }); } private onKickedOffLine(eventInfo: { message: string }) { const { message } = eventInfo; this.emit(EventType.ROOM_NOTICE_MESSAGE_BOX, { title: t('Note'), message: t( 'The system has detected that your account has been kicked offline' ), confirmButtonText: t('Sure'), callback: async () => { this.emit(EventType.KICKED_OFFLINE, { message }); }, }); } private async onAllUserCameraDisableChanged(eventInfo: { roomId: string; isDisable: boolean; }) { const { isDisable } = eventInfo; if ( isDisable !== this.roomStore.isCameraDisableForAllUser && this.roomStore.localUser.userRole === TUIRole.kGeneralUser ) { this.roomStore.setCanControlSelfVideo(!isDisable); } this.handleVideoStateChange(isDisable); this.roomStore.setDisableCameraForAllUserByAdmin(isDisable); } private async handleVideoStateChange(isDisableVideo: boolean) { const tipMessage = isDisableVideo ? t('All videos disabled') : t('All videos enabled'); this.emit(EventType.ROOM_NOTICE_MESSAGE, { type: 'success', message: tipMessage, duration: MESSAGE_DURATION.NORMAL, }); /** * If the host lifts the full ban on video, users does not actively turn up the user camera, * If the host open and does not actively turn up the user camera * **/ if ( isDisableVideo && this.roomStore.localUser.userRole === TUIRole.kGeneralUser ) { await roomEngine.instance?.closeLocalCamera(); } } private async onUserInfoChanged(eventInfo: { userInfo: UserInfo }) { const { userId, nameCard } = eventInfo.userInfo; const oldNameCard = this.roomStore.userInfoObj[userId]?.nameCard; if (oldNameCard === nameCard) return; this.roomStore.updateUserInfo({ userId, nameCard }); } private async onAllUserMicrophoneDisableChanged(eventInfo: { roomId: string; isDisable: boolean; }) { const { isDisable } = eventInfo; if ( isDisable !== this.roomStore.isMicrophoneDisableForAllUser && this.roomStore.localUser.userRole === TUIRole.kGeneralUser ) { this.roomStore.setCanControlSelfAudio(!isDisable); } this.handleAudioStateChange(isDisable); this.roomStore.setDisableMicrophoneForAllUserByAdmin(isDisable); } private async handleAudioStateChange(isDisableAudio: boolean) { const tipMessage = isDisableAudio ? t('All audios disabled') : t('All audios enabled'); this.emit(EventType.ROOM_NOTICE_MESSAGE, { type: 'success', message: tipMessage, duration: MESSAGE_DURATION.NORMAL, }); /** * If the moderator unmutes the entire staff, users does not actively bring up the user's microphone; * if the moderator turns on the full staff mute, users actively turns off the user's microphone * **/ if ( isDisableAudio && this.roomStore.localUser.userRole === TUIRole.kGeneralUser ) { await roomEngine.instance?.muteLocalAudio(); } } private async onScreenShareForAllUserDisableChanged(eventInfo: { roomId: string; isDisable: boolean; }) { const { isDisable } = eventInfo; this.roomStore.setDisableScreenShareForAllUserByAdmin(isDisable); } public resetStore() { this.basicStore.reset(); this.chatStore.reset(); this.roomStore.reset(); } private storeInit(option: RoomInitData) { this.basicStore.setBasicInfo(option); this.userManager.setLocalUser(option); } public async initRoomKit(option: RoomInitData) { initWidgets(this.widgetsManager); this.storeInit(option); const { sdkAppId, userId, userSig } = option; TUILogin.login({ SDKAppID: sdkAppId, userID: userId, userSig, useUploadPlugin: true, }); const { chat } = TUILogin.getContext(); await TUIRoomEngine.login({ sdkAppId, userId, userSig, tim: chat }); this.emit(EventType.ROOM_LOGIN); } public async start(roomId: string, params?: StartParams) { return this.roomActionManager.start(roomId, params); } public async join(roomId: string, params?: JoinParams) { return this.roomActionManager.join(roomId, params); } public async createRoom(options: { roomId: string; roomName?: string; roomMode: 'FreeToSpeak' | 'SpeakAfterTakingSeat'; roomParam?: RoomParam; }) { await this.roomActionManager.createRoom(options); } public async enterRoom(options: { roomId: string; roomParam?: RoomParam }) { await this.roomActionManager.enterRoom(options); } public async leaveRoom() { await this.roomActionManager.leaveRoom(); } public async dismissRoom() { await this.roomActionManager.dismissRoom(); } public fetchRoomInfo(options?: RoomParamsInfo) { return this.roomActionManager.fetchRoomInfo(options); } public async handleRoomEngineReady() { const storageCurrentTheme = localStorage.getItem('tuiRoom-currentTheme'); storageCurrentTheme && this.basicStore.setDefaultTheme(storageCurrentTheme); // Set the default rendering mode of local video const trtcCloud = roomEngine.instance?.getTRTCCloud(); // eslint-disable-next-line no-nested-ternary const mirrorType = isMobile ? TRTCVideoMirrorType.TRTCVideoMirrorType_Auto : this.basicStore.isLocalStreamMirror ? TRTCVideoMirrorType.TRTCVideoMirrorType_Enable : TRTCVideoMirrorType.TRTCVideoMirrorType_Disable; await trtcCloud?.setLocalRenderParams({ mirrorType, rotation: TRTCVideoRotation.TRTCVideoRotation0, fillMode: TRTCVideoFillMode.TRTCVideoFillMode_Fill, }); } public logOut() { this.emit(EventType.USER_LOGOUT); this.resetStore(); } on(eventType: EventType, callback: (data?: any) => void) { this.emitter.on(eventType, callback); } off(eventType: EventType, callback: (data?: any) => void) { this.emitter.off(eventType, callback); } emit(eventType: EventType, data?: any) { this.emitter.emit(eventType, data); } // Component Manager public getComponentConfig(name: ComponentName) { return this.componentManager.getComponentConfig(name); } public setComponentConfig(options: Partial<ComponentConfig>) { return this.componentManager.setComponentConfig(options); } // Config Manager public setTheme(theme: Theme) { return this.configManager.setTheme(theme); } public setLanguage(language: LanguageOption) { return this.configManager.setLanguage(language); } // User Manager setSelfInfo(options: SelfInfoOptions) { return this.userManager.setSelfInfo(options); } getDisplayName(options: UserInfo) { return this.userManager.getDisplayName(options); } getMediaManager() { return this.mediaManager; } } export const roomService = RoomService.getInstance();