// 在 preload 脚本中。 const { ipcRenderer, contextBridge } = require('electron') const { createAgoraRtcEngine, ClientRoleType, VideoSourceType, VideoViewSetupMode, ScreenCaptureSourceType, RenderModeType, ChannelProfileType, MediaRecorderContainerFormat, MediaRecorderStreamType } = require("agora-electron-sdk"); const agoraAonfig = require('./src/utils/package/agoraConfig'); const { message } = require('antd'); const rtcEngine = createAgoraRtcEngine(); rtcEngine.initialize({ appId: agoraAonfig.appid, }); let videoID = ''; let iMediaRecorder = ''; const getDom = () => { return document.getElementById(videoID); } // 离开频道 const leaveChannel = () => { rtcEngine.leaveChannel({ stopAudioMixing: true, stopAllEffect: true, stopMicrophoneRecording: true, }) } // 离开频道 const joinChannel = (bool) => { if (bool) { rtcEngine.joinChannel(agoraAonfig.token, agoraAonfig.channelId, 123, { channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众 publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频 publishCameraTrack: false, //设置是否发布摄像头采集的视频 publishScreenTrack: true, //设置是否发布屏幕采集的视频 autoSubscribeAudio: true, //设置是否自动订阅所有音频流 autoSubscribeVideo: true, //设置是否自动订阅所有视频流 }); } else { rtcEngine.joinChannel(agoraAonfig.token, agoraAonfig.channelId, 123, { channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可 publishMicrophoneTrack: true, //发布麦克风采集的音频 publishCameraTrack: true, //发布摄像头采集的视频 publishScreenTrack: false, //设置是否发布屏幕采集的视频 autoSubscribeAudio: true, //自动订阅所有音频流 autoSubscribeVideo: true, //自动订阅所有视频流 }); } } // 停止共享屏幕 const stopScreenCapture = () => { rtcEngine.stopScreenCapture(); } rtcEngine.registerEventHandler({ // 监听本地用户加入频道事件 onJoinChannelSuccess: ({ channelId, localUid }, elapsed) => { console.log({ channelId, localUid }, elapsed, '加入房间'); // 本地用户加入频道后,设置本地视频窗口 rtcEngine.setupLocalVideo({ renderMode: RenderModeType.RenderModeFit, sourceType: VideoSourceType.VideoSourceScreen, // sourceType: VideoSourceType.VideoSourceCameraPrimary, uid: localUid, view: getDom(), setupMode: VideoViewSetupMode.VideoViewSetupAdd, }); }, // 监听远端用户加入频道事件 onUserJoined: ({ channelId, localUid }, remoteUid, elapsed) => { // 远端用户加入频道后,设置远端视频窗口 rtcEngine.setupRemoteVideo( { renderMode: RenderModeType.RenderModeFit, sourceType: VideoSourceType.VideoSourceRemote, uid: remoteUid, view: getDom(), setupMode: VideoViewSetupMode.VideoViewSetupAdd, }, { channelId }, ); }, // 视频发布状态改变回调 onVideoPublishStateChanged: (source, channel, oldState, newState, elapseSinceLastState) => { if (newState === 1) { } }, // 音频发布状态改变回调 onAudioPublishStateChanged: (channel, oldState, newState, elapseSinceLastState) => { if (newState === 1) { } }, // 监听用户离开频道事件 onUserOffline: ({ channelId, localUid }, remoteUid, reason) => { // 远端用户离开频道后,关闭远端视频窗口 rtcEngine.setupRemoteVideo( { renderMode: RenderModeType.RenderModeFit, sourceType: VideoSourceType.VideoSourceRemote, uid: remoteUid, view: getDom(), setupMode: VideoViewSetupMode.VideoViewSetupRemove, }, ); }, // 用户音量提示回调。 onAudioVolumeIndication: (connection, speakers, speakerNumber, totalVolume) => { const percentage = (totalVolume / 255) * 100 if (document.getElementById('recordingDeviceTest')) { document.getElementById('recordingDeviceTest').style.width = `${percentage}%` } } }); contextBridge.exposeInMainWorld( 'electron', { // 桌面捕获音频和视频的媒体源的信息 getDesktopCapturerVideo: async () => { return rtcEngine.getScreenCaptureSources({ width: 300, height: 300 }, { width: 300, height: 300 }, true); }, // 共享屏幕采集 setDesktopCapturerVideo: (targetSource) => { stopScreenCapture() if ( targetSource.type === ScreenCaptureSourceType.ScreencapturesourcetypeScreen ) { rtcEngine.startScreenCaptureByDisplayId( targetSource.sourceId, {}, { windowFocus: true, enableHighLight: true, highLightColor: 0xFF99CC00, } ); } else { rtcEngine.startScreenCaptureByWindowId( targetSource.sourceId, {}, { windowFocus: true, enableHighLight: true, highLightColor: 0xFF99CC00, } ); } videoID = `vidoe-${123}-${agoraAonfig.channelId}`; joinChannel(true) }, // 摄像头采集 setCameraCapture: () => { rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) videoID = `vidoe-${123}-${agoraAonfig.channelId}`; joinChannel(false) }, // 加入频道 setJoinChannel: (data) => { // videoID = `vidoe-${data.userid}-${data.channelId}`; rtcEngine.joinChannelEx(agoraAonfig.token, { channelId: data.channelId, localUid: data.userid, }, { autoSubscribeAudio: true, //设置是否自动订阅所有音频流 autoSubscribeVideo: true, //设置是否自动订阅所有视频流 publishMicrophoneTrack: false, //设置是否发布麦克风采集到的音频 publishCameraTrack: false, //设置是否发布摄像头采集的视频 clientRoleType: ClientRoleType.ClientRoleAudience, //用户角色 1主播 2观众 publishScreenTrack: true, //设置是否发布屏幕采集的视频 }); }, // 离开频道 leaveChannel: () => { leaveChannel() }, // 停止共享屏幕 stopScreenCapture: () => { stopScreenCapture() }, // 取消或恢复发布本地音频流 muteLocalAudioStream: (mute) => { rtcEngine.muteLocalAudioStream(mute) }, // 取消或恢复发布本地视频流 muteLocalVideoStream: (mute) => { rtcEngine.muteLocalVideoStream(mute) }, // 获取当前生成的视频id getVideoId: () => { return videoID; }, // 获取音频设备列表 getAudioMediaList: () => { return { currentDevice: rtcEngine.getAudioDeviceManager().getRecordingDefaultDevice(), currentDevices: rtcEngine.getAudioDeviceManager().enumerateRecordingDevices(), currentVolume: rtcEngine.getAudioDeviceManager().getRecordingDeviceVolume() } }, // 设置音频设备音量 setRecordingDeviceVolume: (volume) => { rtcEngine.getAudioDeviceManager().setRecordingDeviceVolume(volume) }, // 设置音频采集设备 setRecordingDevice: (deviceId) => { rtcEngine.getAudioDeviceManager().setRecordingDevice(deviceId) }, // 启动音频采集设备测试 startRecordingDeviceTest: (indicationInterval) => { rtcEngine.getAudioDeviceManager().startRecordingDeviceTest(indicationInterval) navigator.mediaDevices.getUserMedia({ audio: true }) .then((stream) => { let dom = document.getElementById('startAudio'); dom.srcObject = stream; dom.play() }) .catch((error) => { message.error('无法获取麦克风!'); }); }, // 停止音频设备回路测试 stopAudioDeviceLoopbackTest: () => { rtcEngine.getAudioDeviceManager().stopAudioDeviceLoopbackTest() rtcEngine.getAudioDeviceManager().stopRecordingDeviceTest() let video = document.getElementById('startPreview'); if (video.srcObject) { const tracks = video.srcObject.getTracks(); tracks.forEach((track) => { track.stop(); }); video.srcObject = null; } let audio = document.getElementById('startAudio'); if (audio.srcObject) { const tracks = audio.srcObject.getTracks(); tracks.forEach((track) => { track.stop(); }); audio.srcObject = null; } }, // 开启本地视频预览 startPreview: async () => { return new Promise((resolve, reject) => { navigator.mediaDevices.getUserMedia({ video: true, audio: true, }).then((stream) => { let dom = document.getElementById('startPreview'); dom.srcObject = stream; dom.play() resolve(true) }).catch((error) => { message.error('无法获取摄像头!'); resolve(true) }); }) }, // 开始录制音视频 startRecording: () => { iMediaRecorder = rtcEngine.createMediaRecorder({ channelId: agoraAonfig.channelId, uid: 123, }) iMediaRecorder.setMediaRecorderObserver({ // 录制状态发生改变回调。 onRecorderStateChanged: (channelId, uid, state, reason) => { console.log(channelId, uid, state, reason, '录制状态发生改变回调。'); }, // 录制信息更新回调。 onRecorderInfoUpdated: (channelId, uid, info) => { console.log(channelId, uid, info, '录制信息更新回调。'); }, }) iMediaRecorder.startRecording({ storagePath: `D:/word/${+new Date()}.mp4`, //录音文件在本地保存的绝对路径,需精确到文件名及格式 containerFormat: MediaRecorderContainerFormat.FormatMp4, //录制文件的格式 streamType: MediaRecorderStreamType.StreamTypeBoth, //录制内容 maxDurationMs: 7200000, //maxDurationMs }) }, // 停止录制音视频 stopRecording: () => { iMediaRecorder.stopRecording() rtcEngine.destroyMediaRecorder(iMediaRecorder) iMediaRecorder = "" }, // 设置窗口大小 setMainWindowSize: (config) => { ipcRenderer.invoke('setMainWindowSize', { ...config }) }, // 设置窗口状态 setViewStatus: (status) => { ipcRenderer.invoke('setViewStatus', status) }, // 获取当前是否全屏 getIsMaximized: () => { return ipcRenderer.invoke('getIsMaximized') }, // 复制文字 setWriteText: (text) => { return ipcRenderer.invoke('setWriteText', text) } } )