import { createAgoraRtcEngine, ClientRoleType, VideoSourceType, VideoViewSetupMode, ScreenCaptureSourceType, RenderModeType, ChannelProfileType, AudioAinsMode, SimulcastStreamMode, VideoStreamType, QualityType, RtcConnection, RtcStats, AudioVolumeInfo, UserOfflineReasonType, ConnectionStateType, ConnectionChangedReasonType, LocalVideoStreamReason, LocalVideoStreamState, BeautyOptions, ColorEnhanceOptions, LowlightEnhanceOptions, VirtualBackgroundSource } from "agora-electron-sdk"; import { GetRoomRtcToken, GetAgoraConf } from "@/api/Home/Index"; import { storage } from '@/utils'; import { role } from "@/config/role"; import path from "path"; const option: any = { appId: '', token: '', tokenA: '', channelId: '', uid: '', screenShareId: '', } let rtcEngine: any = ''; export const agora = { // 初始化 init: async (bool: boolean = false) => { const { data } = await GetAgoraConf(); if (data) { rtcEngine = createAgoraRtcEngine(); await rtcEngine.initialize({ appId: data, }); if (bool) { await agora.setDeviceManager() } } }, // 获取rtcEngine getRtcEngine: () => { return rtcEngine }, // 获取当前设备是否存在不存在就获取默认设备 setDeviceManager: async () => { const setting = await JSON.parse(storage.getItem('setting') as string) // 摄像头 if (setting.videoDeviceId) { await agora.getVideoDeviceManager().then(async (res) => { let item = res.list.find((item: any) => item.deviceId === setting.videoDeviceId); if (item) { await agora.setVideoDeviceManager(setting.videoDeviceId) } else { await agora.setVideoDeviceManager(await rtcEngine.getVideoDeviceManager().getDevice()) setting.videoDeviceId = await rtcEngine.getVideoDeviceManager().getDevice() } }) } else { await agora.setVideoDeviceManager(await rtcEngine.getVideoDeviceManager().getDevice()) setting.videoDeviceId = await rtcEngine.getVideoDeviceManager().getDevice() } // 播放设备 if (setting.playBackDeviceId) { await agora.getAudioMediaList().then(async (res) => { let item = res.playBackList.find((item: any) => item.deviceId === setting.playBackDeviceId); if (item) { await agora.setPlaybackDevice(setting.playBackDeviceId) } else { await agora.setPlaybackDevice(res.playBackItem.deviceId) setting.playBackDeviceId = res.playBackItem.deviceId } }) } else { let deviceId = await rtcEngine.getAudioDeviceManager().getPlaybackDefaultDevice().deviceId; await agora.setPlaybackDevice(deviceId) setting.playBackDeviceId = deviceId } // 音频设备 if (setting.ecordingDeviceId) { await agora.getAudioMediaList().then(async (res) => { let item = res.ecordingList.find((item: any) => item.deviceId === setting.ecordingDeviceId); if (item) { await agora.setRecordingDevice(setting.ecordingDeviceId) } else { await agora.setRecordingDevice(res.ecordingItem.deviceId) setting.ecordingDeviceId = res.ecordingItem.deviceId } }) } else { let deviceId = await rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice().deviceId; await agora.setRecordingDevice(deviceId) setting.ecordingDeviceId = deviceId } setTimeout(async () => { storage.setItem('setting', JSON.stringify(setting)) const settingData = await JSON.parse(storage.getItem('setting') as string) if (settingData.videoDeviceId) agora.setVideoDeviceManager(settingData.videoDeviceId) //指定摄像头头采集设备 if (settingData.playBackDeviceId) agora.setPlaybackDevice(settingData.playBackDeviceId) //指定播放设备 if (settingData.playBackVolume) agora.setPlaybackDeviceVolume(settingData.playBackVolume) // 设置播放设备音量 if (settingData.ecordingDeviceId) agora.setRecordingDevice(settingData.ecordingDeviceId) // 设置音频采集设备 if (settingData.ecordingVolume) agora.setRecordingDeviceVolume(settingData.ecordingVolume) // 设置音频设备音量 if (settingData.isAINoiseReduction) agora.setAINSMode(settingData.isAINoiseReduction, settingData.aINoiseReduction) // 设置ai降噪 agora.setBeautyEffectOptions(settingData.beautyEffect.isBeautyEffect, settingData.beautyEffect) agora.setColorEnhanceOptions(settingData.colorEnhancement.isColorEnhancement, settingData.colorEnhancement) agora.setLowlightEnhanceOptions(settingData.darkLightEnhancement.isDarkLightEnhancement, settingData.darkLightEnhancement) if (typeof settingData.virtualBackground.sourceIndex === 'number') { if (import.meta.env.VITE_ENV === 'development') { window.electron.getAppPath().then((res: string) => { const imagePath = path.join(res, 'src', 'assets', 'virtualBackground', `${settingData.virtualBackground.sourceIndex + 1}.png`); agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, { source: imagePath, background_source_type: 2, color: Number(settingData.virtualBackground.color), }) }) } else { const imagePath = path.join((process as any).resourcesPath, 'images', `${settingData.virtualBackground.sourceIndex + 1}.png`); agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, { source: imagePath, background_source_type: 2, color: Number(settingData.virtualBackground.color), }) } } else { agora.enableVirtualBackground(settingData.virtualBackground.isVirtualBackground, { background_source_type: 1, color: Number(settingData.virtualBackground.color), }) } }, 1000); }, // 事件回调 registerEventHandler: ({ onJoinChannelSuccess, onUserJoined, onUserOffline, onAudioVolumeIndication, onNetworkQuality, onRtcStats, onConnectionStateChanged, onLocalVideoStateChanged }: any) => { rtcEngine.registerEventHandler({ // 监听本地用户加入频道事件 onJoinChannelSuccess: async (connection: RtcConnection, elapsed: number) => { await onJoinChannelSuccess?.(connection, elapsed) }, // 监听远端用户加入频道事件 onUserJoined: async (connection: RtcConnection, remoteUid: number, elapsed: number) => { await onUserJoined?.(connection, remoteUid, elapsed) }, // 监听用户离开频道事件 onUserOffline: async (connection: RtcConnection, remoteUid: number, reason: UserOfflineReasonType) => { await onUserOffline?.(connection, remoteUid, reason) }, // // 视频发布状态改变回调 // onVideoPublishStateChanged: (source: any, channel: any, oldState: any, newState: any, elapseSinceLastState: any) => { // if (newState === 1) { // } // }, // // 音频发布状态改变回调 // onAudioPublishStateChanged: (channel: any, oldState: any, newState: any, elapseSinceLastState: any) => { // if (newState === 1) { // } // }, // // 用户音量提示回调。 onAudioVolumeIndication: async (_connection: RtcConnection, speakers: AudioVolumeInfo[], _speakerNumber: number, _totalVolume: number) => { await onAudioVolumeIndication?.(speakers) }, //通话中每个用户的网络上下行 last mile 质量报告回调。 onNetworkQuality: async (connection: RtcConnection, remoteUid: number, txQuality: QualityType, rxQuality: QualityType) => { await onNetworkQuality?.(connection, remoteUid, txQuality, rxQuality) }, //当前通话相关的统计信息回调。 onRtcStats: async (_connection: RtcConnection, stats: RtcStats) => { await onRtcStats?.(stats) }, // 网络连接状态已改变回调。 onConnectionStateChanged: async (connection: RtcConnection, state: ConnectionStateType, reason: ConnectionChangedReasonType) => { await onConnectionStateChanged?.(connection, state, reason) }, // 本地视频状态发生改变回调。 onLocalVideoStateChanged: async (source: VideoSourceType, state: LocalVideoStreamState, reason: LocalVideoStreamReason) => { await onLocalVideoStateChanged?.(source, state, reason) }, }); }, // 获取视图模式 getRrenderMode: (uid: number) => { if (String(uid).length === 9) { return RenderModeType.RenderModeFit } else { return RenderModeType.RenderModeHidden } }, // 本地加入 setupLocalVideo: async (item: any) => { if (item.view?.childNodes.length === 1 || item.type) { await rtcEngine.setupLocalVideo({ renderMode: agora.getRrenderMode(item.uid), sourceType: item.sourceType, uid: item.uid, view: item.view, setupMode: VideoViewSetupMode.VideoViewSetupAdd, }); } }, // 远端加入 setupRemoteVideoJoin: async (item: any) => { if (item.view?.childNodes.length === 1) { await rtcEngine.setupRemoteVideo( { renderMode: agora.getRrenderMode(item.uid), sourceType: VideoSourceType.VideoSourceRemote, uid: item.uid, view: item.view, setupMode: VideoViewSetupMode.VideoViewSetupAdd, }, { channelId: item.channelId }, ); } }, setupRemoteVideoEx: async (item: any) => { if (item.view?.childNodes.length === 1) { await rtcEngine.setupRemoteVideoEx( { renderMode: agora.getRrenderMode(item.uid), sourceType: VideoSourceType.VideoSourceRemote, uid: item.uid, view: item.view, setupMode: VideoViewSetupMode.VideoViewSetupAdd, }, { channelId: item.channelId }, ); } }, // 退出 setupRemoteVideo: async (item: any) => { await rtcEngine.setupRemoteVideo( { renderMode: agora.getRrenderMode(item.uid), sourceType: VideoSourceType.VideoSourceRemote, uid: item.uid, view: item.view, setupMode: VideoViewSetupMode.VideoViewSetupRemove, }, ); }, // 销毁 release: async () => { await rtcEngine.release() }, // 离开频道 leaveChannel: async () => { await rtcEngine.leaveChannel({ stopAudioMixing: true, stopAllEffect: true, stopMicrophoneRecording: true, }) agora.stopScreenCapture() agora.release() }, // 加入频道 joinChannel: async () => { await rtcEngine.enableAudioVolumeIndication(100, 3, true) await rtcEngine.joinChannel(option.token, option.channelId, option.uid); await rtcEngine.setDualStreamModeEx( SimulcastStreamMode.EnableSimulcastStream, { dimensions: { width: 320, height: 180 }, framerate: 5, }, { channelId: option.channelId, localUid: Number(option.uid) } ); }, // 更新频道配置 updateChannelMediaOptions: async (bool: boolean) => { await rtcEngine.updateChannelMediaOptions({ clientRoleType: bool ? ClientRoleType.ClientRoleBroadcaster : ClientRoleType.ClientRoleAudience, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 autoSubscribeAudio: true,//设置是否自动订阅所有音频流 autoSubscribeVideo: true,//设置是否自动订阅所有视频流 publishMicrophoneTrack: true,//设置是否发布麦克风采集到的音频 publishCameraTrack: true,//设置是否发布摄像头采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频 }) }, // 设置接收大小流 setRemoteVideoStreamType: async (uid: number, type: VideoStreamType, bool: boolean) => { await rtcEngine.setRemoteVideoStreamTypeEx( Number(uid), type, bool ? { channelId: option.channelId, localUid: Number(option.uid) } : { channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) } ) }, // 共享屏幕单独用户 joinChannelEx: async (uid: any) => { await agora.leaveChannelEx(uid) await rtcEngine.joinChannelEx( option.token, { channelId: option.channelId, localUid: Number(uid) }, { autoSubscribeAudio: false,//设置是否自动订阅所有音频流 autoSubscribeVideo: false,//设置是否自动订阅所有视频流 publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频 publishCameraTrack: false,//设置是否发布摄像头采集的视频 clientRoleType: ClientRoleType.ClientRoleBroadcaster,//用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 publishScreenTrack: true,//设置是否发布屏幕采集的视频 } ); }, // 所有用户加入的第二个房间 allJoinChannelEx: async (bool: boolean = false) => { const user = await JSON.parse(storage.getItem('user') as string) await agora.startCameraCapture(true) await rtcEngine.joinChannelEx( option.tokenA, { channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) }, { clientRoleType: bool ? ClientRoleType.ClientRoleAudience : ClientRoleType.ClientRoleBroadcaster, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 autoSubscribeAudio: false,//设置是否自动订阅所有音频流 autoSubscribeVideo: role.ID.includes(user.roleId) ? true : false,//设置是否自动订阅所有视频流 publishMicrophoneTrack: false,//设置是否发布麦克风采集到的音频 publishCameraTrack: true,//设置是否发布摄像头采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频 } ); await rtcEngine.setDualStreamModeEx( SimulcastStreamMode.EnableSimulcastStream, { dimensions: { width: 320, height: 180 }, framerate: 5, }, { channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) } ); }, // 退出第二个房间 allLeaveChannelEx: async () => { await agora.stopCameraCapture(); await rtcEngine.leaveChannelEx({ channelId: option.channelId + 'a', localUid: Number('1' + option.screenShareId) }) }, // 停止/恢复接收指定的视频流。 muteRemoteVideoStreamEx: async (uid: number, mute: boolean) => { await rtcEngine.muteRemoteVideoStreamEx(uid, mute, { channelId: option.channelId, localUid: Number(option.uid) }) }, // 取消或恢复订阅指定远端用户的音频流 muteRemoteVideoStream: async (uid: number, mute: boolean) => { rtcEngine.muteRemoteVideoStream(uid, mute) }, // 销毁视频渲染dom destroyRendererByConfig: async (uid: number, channelId: string) => { await rtcEngine.destroyRendererByConfig(VideoSourceType.VideoSourceRemote, channelId, uid); }, // ai降噪 setAINSMode: async (enabled: boolean, mode: AudioAinsMode) => { rtcEngine.setAINSMode(enabled, mode) }, // 离开共享屏幕频道 leaveChannelEx: async (uid: any) => { await rtcEngine.leaveChannelEx({ channelId: option.channelId, localUid: Number(uid) }) }, // 停止共享屏幕 stopScreenCapture: () => { rtcEngine.stopScreenCapture(); rtcEngine.enableLoopbackRecording(false) }, // 取消或恢复发布本地音频流 muteLocalAudioStream: async (data: any, publishMicrophoneTrack: boolean, publishCameraTrack: boolean) => { // await rtcEngine.muteLocalAudioStream(mute) await rtcEngine.updateChannelMediaOptions({ clientRoleType: data ? ClientRoleType.ClientRoleBroadcaster : ClientRoleType.ClientRoleAudience, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 autoSubscribeAudio: true,//设置是否自动订阅所有音频流 autoSubscribeVideo: true,//设置是否自动订阅所有视频流 publishMicrophoneTrack: publishMicrophoneTrack,//设置是否发布麦克风采集到的音频 publishCameraTrack: publishCameraTrack,//设置是否发布摄像头采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频 }) }, // 取消或恢复发布本地视频流 muteLocalVideoStream: async (data: any, publishMicrophoneTrack: boolean, publishCameraTrack: boolean) => { // await rtcEngine.muteLocalVideoStream(mute) await rtcEngine.updateChannelMediaOptions({ clientRoleType: data ? ClientRoleType.ClientRoleBroadcaster : ClientRoleType.ClientRoleAudience, //用户角色 ClientRoleBroadcaster 主播 ClientRoleAudience 观众 autoSubscribeAudio: true,//设置是否自动订阅所有音频流 autoSubscribeVideo: true,//设置是否自动订阅所有视频流 publishMicrophoneTrack: publishMicrophoneTrack,//设置是否发布麦克风采集到的音频 publishCameraTrack: publishCameraTrack,//设置是否发布摄像头采集的视频 publishScreenTrack: false,//设置是否发布屏幕采集的视频 }) }, // 摄像头采集 startCameraCapture: async (bool: boolean = false) => { await rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, { format: { width: bool ? 160 : 1280, height: bool ? 160 : 720, fps: 15, } }) }, // 停止采集摄像头 stopCameraCapture: async () => { await rtcEngine.stopCameraCapture() }, // 加入频道 setJoinChannel: async (data: any) => { option.token = data.token; option.tokenA = data.tokenA; option.channelId = data.channelId; option.uid = Number(data.uid); option.screenShareId = data.screenShareId; await agora.joinChannel() }, // 桌面捕获音频和视频的媒体源的信息 getDesktopCapturerVideo: async (thumbSize: any, iconSize: any, includeScreen: boolean) => { return await rtcEngine.getScreenCaptureSources(thumbSize, iconSize, includeScreen) }, // 共享屏幕采集 setDesktopCapturerVideo: async (targetSource: any, isComputerAudio: boolean, isFluencyPriority: boolean) => { const user = JSON.parse(storage.getItem('user') as string) agora.stopScreenCapture(); if (isComputerAudio) { rtcEngine.enableLoopbackRecording(true) } let data = { frameRate: isFluencyPriority ? 30 : 15, dimensions: { width: 1920, height: 1080, } } if ( targetSource.type === ScreenCaptureSourceType.ScreencapturesourcetypeScreen ) { rtcEngine.startScreenCaptureByDisplayId( targetSource.sourceId, {}, { windowFocus: true, ...data } ); } else { rtcEngine.startScreenCaptureByWindowId( targetSource.sourceId, {}, { windowFocus: true, ...data } ); } await agora.joinChannelEx(user.screenShareId) }, // 获取系统中所有的视频设备列表。 getVideoDeviceManager: async (): Promise => { return { list: rtcEngine.getVideoDeviceManager().enumerateVideoDevices(), item: rtcEngine.getVideoDeviceManager().getDevice() } }, // 通过设备 ID 指定视频采集设备。 setVideoDeviceManager: async (deviceIdUTF8: string) => { await rtcEngine.getVideoDeviceManager().setDevice(deviceIdUTF8) }, // 开启本地视频预览 startPreview: async (id: string, uid: number): Promise => { rtcEngine.enableVideo(); rtcEngine.startPreview(); await GetRoomRtcToken(`${+new Date()}`).then(async (res) => { await rtcEngine.joinChannelEx(res.data, { channelId: `${+new Date() + uid}`, localUid: uid, }, { channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, clientRoleType: ClientRoleType.ClientRoleBroadcaster, publishMicrophoneTrack: true, publishCameraTrack: true, autoSubscribeAudio: true, autoSubscribeVideo: true, }); rtcEngine.setupLocalVideo({ sourceType: VideoSourceType.VideoSourceCameraPrimary, uid, view: document.getElementById(id), setupMode: VideoViewSetupMode.VideoViewSetupAdd, }); }) }, // 获取输入输出设备列表 getAudioMediaList: async () => { return { playBackList: rtcEngine.getAudioDeviceManager().enumeratePlaybackDevices(), ecordingList: rtcEngine.getAudioDeviceManager().enumerateRecordingDevices(), playBackItem: rtcEngine.getAudioDeviceManager().getPlaybackDefaultDevice(), ecordingItem: rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice(), ecordingVolume: rtcEngine.getAudioDeviceManager().getRecordingDeviceVolume(), } }, // 启动音频播放设备测试。 startPlaybackDeviceTest: async () => { await rtcEngine.getAudioDeviceManager().startPlaybackDeviceTest('https://wgshare.oss-cn-chengdu.aliyuncs.com/TestAudio.mp3') }, // 停止音频播放设备测试。 stopPlaybackDeviceTest: async () => { await rtcEngine.getAudioDeviceManager().stopPlaybackDeviceTest() }, // 设置播放设备音量 setPlaybackDeviceVolume: async (volume: number) => { await rtcEngine.getAudioDeviceManager().setPlaybackDeviceVolume(volume) }, // 指定播放设备 setPlaybackDevice: async (deviceId: string) => { await rtcEngine.getAudioDeviceManager().setPlaybackDevice(deviceId) }, // 启动音频采集设备测试 startRecordingDeviceTest: async (indicationInterval: number) => { await rtcEngine.getAudioDeviceManager().startRecordingDeviceTest(indicationInterval) }, // 设置音频设备音量 setRecordingDeviceVolume: async (volume: number) => { await rtcEngine.getAudioDeviceManager().setRecordingDeviceVolume(volume) }, // 设置音频采集设备 setRecordingDevice: async (deviceId: string) => { await rtcEngine.getAudioDeviceManager().setRecordingDevice(deviceId) }, // 停止音频采集设备测试 stopRecordingDeviceTest: async () => { await rtcEngine.getAudioDeviceManager().stopRecordingDeviceTest() }, // 设置美颜效果 setBeautyEffectOptions: async (enabled: boolean, options: BeautyOptions) => { await rtcEngine.setBeautyEffectOptions(enabled, options) }, // 设置色彩增强 setColorEnhanceOptions: async (enabled: boolean, options: ColorEnhanceOptions) => { await rtcEngine.setColorEnhanceOptions(enabled, options) }, // 设置暗光增强 setLowlightEnhanceOptions: async (enabled: boolean, options: LowlightEnhanceOptions) => { await rtcEngine.setLowlightEnhanceOptions(enabled, options) }, // 开启/关闭虚拟背景。 enableVirtualBackground: async (enabled: boolean, backgroundSource: VirtualBackgroundSource) => { await rtcEngine.enableVirtualBackground(enabled, backgroundSource, { greenCapacity: 1 }) }, }