From 76db8772931907448557ebe728e050002a0a7da2 Mon Sep 17 00:00:00 2001 From: yj <1336058017@qq.com> Date: Wed, 10 Jul 2024 17:56:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E6=96=87=E4=BB=B6=E5=87=86?= =?UTF-8?q?=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + main.js | 2 +- package-lock.json | 118 ++++++------ package.json | 2 +- preload.js | 343 +++------------------------------- src/api/Home/Index/index.ts | 6 + src/api/Meeting/index.ts | 4 +- src/page/Home/Index/index.tsx | 23 ++- src/page/Home/User/index.tsx | 7 +- src/page/Login/index.tsx | 6 +- src/page/Meeting/index.tsx | 54 +++--- src/render.d.ts | 16 +- src/shims-react.d.ts | 3 +- src/utils/package/agora.js | 295 +++++++++++++++++++++++++++++ 14 files changed, 448 insertions(+), 432 deletions(-) create mode 100644 src/utils/package/agora.js diff --git a/index.html b/index.html index e3ab5f4..304fe77 100644 --- a/index.html +++ b/index.html @@ -14,6 +14,7 @@
+ \ No newline at end of file diff --git a/main.js b/main.js index 016846c..594d454 100644 --- a/main.js +++ b/main.js @@ -8,7 +8,7 @@ class AppWindow extends BrowserWindow { constructor(config) { const basicConfig = { webPreferences: { - contextIsolation: true, + contextIsolation: false, nodeIntegration: true, enableRemoteModule: true, nodeIntegrationInWorker: true, diff --git a/package-lock.json b/package-lock.json index 54a8447..f079aeb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,9 @@ "agora-electron-sdk": "^4.3.2", "antd": "^5.18.2", "axios": "^1.7.2", + "crypto-js": "^4.2.0", "dayjs": "^1.11.11", "electron-squirrel-startup": "^1.0.1", - "js-md5": "^0.8.3", "path": "^0.12.7", "postcss-px-to-viewport-8-plugin": "^1.2.5", "react": "^18.3.1", @@ -1408,9 +1408,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -1446,9 +1446,9 @@ } }, "node_modules/@microsoft/signalr": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz", - "integrity": "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA==", + "version": "8.0.7", + "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.7.tgz", + "integrity": "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==", "dependencies": { "abort-controller": "^3.0.0", "eventsource": "^2.0.2", @@ -4132,9 +4132,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.23.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", "dev": true, "funding": [ { @@ -4151,10 +4151,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -4393,9 +4393,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001640", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", - "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "version": "1.0.30001641", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", + "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", "dev": true, "funding": [ { @@ -5024,6 +5024,11 @@ "node": ">=12.10" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", @@ -6126,9 +6131,9 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/electron-to-chromium": { - "version": "1.4.819", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.819.tgz", - "integrity": "sha512-8RwI6gKUokbHWcN3iRij/qpvf/wCbIVY5slODi85werwqUQwpFXM+dvUBND93Qh7SB0pW3Hlq3/wZsqQ3M9Jaw==", + "version": "1.4.823", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz", + "integrity": "sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==", "dev": true }, "node_modules/electron-winstaller": { @@ -8847,11 +8852,6 @@ "node": ">= 4" } }, - "node_modules/js-md5": { - "version": "0.8.3", - "resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz", - "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==" - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", @@ -11200,9 +11200,9 @@ } }, "node_modules/rc-picker": { - "version": "4.6.7", - "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.7.tgz", - "integrity": "sha512-ZntxLH863jdNPZq2i6e2+1iXpRfYKHjNfUGgoObA1YExuWAnTCHpZzOkBuS43GnVcnp2MPDp78pH9OZJFd2hLw==", + "version": "4.6.8", + "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.8.tgz", + "integrity": "sha512-Lq2m68YGcmWXhzAmxTcL3vOjik7NQjcZ6fmZqBlgdrMCg3VnuKHmtk5CHGWd3wCiy2qNxSYIqWAidB1EQViPpQ==", "dependencies": { "@babel/runtime": "^7.24.7", "@rc-component/trigger": "^2.0.0", @@ -12311,9 +12311,9 @@ "optional": true }, "node_modules/sass": { - "version": "1.77.6", - "resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.6.tgz", - "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "version": "1.77.7", + "resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.7.tgz", + "integrity": "sha512-9ywH75cO+rLjbrZ6en3Gp8qAMwPGBapFtlsMJoDTkcMU/bSe5a6cjKVUn5Jr4Gzg5GbP3HE8cm+02pLCgcoMow==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -15660,9 +15660,9 @@ "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "@jridgewell/trace-mapping": { @@ -15685,9 +15685,9 @@ } }, "@microsoft/signalr": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.0.tgz", - "integrity": "sha512-K/wS/VmzRWePCGqGh8MU8OWbS1Zvu7DG7LSJS62fBB8rJUXwwj4axQtqrAAwKGUZHQF6CuteuQR9xMsVpM2JNA==", + "version": "8.0.7", + "resolved": "https://registry.npmmirror.com/@microsoft/signalr/-/signalr-8.0.7.tgz", + "integrity": "sha512-PHcdMv8v5hJlBkRHAuKG5trGViQEkPYee36LnJQx4xHOQ5LL4X0nEWIxOp5cCtZ7tu+30quz5V3k0b1YNuc6lw==", "requires": { "abort-controller": "^3.0.0", "eventsource": "^2.0.2", @@ -17419,15 +17419,15 @@ } }, "browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.23.2", + "resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "update-browserslist-db": "^1.1.0" } }, "buffer": { @@ -17604,9 +17604,9 @@ "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==" }, "caniuse-lite": { - "version": "1.0.30001640", - "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", - "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "version": "1.0.30001641", + "resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", + "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", "dev": true }, "canvas-size": { @@ -18073,6 +18073,11 @@ "integrity": "sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==", "dev": true }, + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "csstype": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz", @@ -18973,9 +18978,9 @@ } }, "electron-to-chromium": { - "version": "1.4.819", - "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.819.tgz", - "integrity": "sha512-8RwI6gKUokbHWcN3iRij/qpvf/wCbIVY5slODi85werwqUQwpFXM+dvUBND93Qh7SB0pW3Hlq3/wZsqQ3M9Jaw==", + "version": "1.4.823", + "resolved": "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.823.tgz", + "integrity": "sha512-4h+oPeAiGQOHFyUJOqpoEcPj/xxlicxBzOErVeYVMMmAiXUXsGpsFd0QXBMaUUbnD8hhSfLf9uw+MlsoIA7j5w==", "dev": true }, "electron-winstaller": { @@ -20916,11 +20921,6 @@ "is-object": "^1.0.1" } }, - "js-md5": { - "version": "0.8.3", - "resolved": "https://registry.npmmirror.com/js-md5/-/js-md5-0.8.3.tgz", - "integrity": "sha512-qR0HB5uP6wCuRMrWPTrkMaev7MJZwJuuw4fnwAzRgP4J4/F8RwtodOKpGp4XpqsLBFzzgqIO42efFAyz2Et6KQ==" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", @@ -22669,9 +22669,9 @@ } }, "rc-picker": { - "version": "4.6.7", - "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.7.tgz", - "integrity": "sha512-ZntxLH863jdNPZq2i6e2+1iXpRfYKHjNfUGgoObA1YExuWAnTCHpZzOkBuS43GnVcnp2MPDp78pH9OZJFd2hLw==", + "version": "4.6.8", + "resolved": "https://registry.npmmirror.com/rc-picker/-/rc-picker-4.6.8.tgz", + "integrity": "sha512-Lq2m68YGcmWXhzAmxTcL3vOjik7NQjcZ6fmZqBlgdrMCg3VnuKHmtk5CHGWd3wCiy2qNxSYIqWAidB1EQViPpQ==", "requires": { "@babel/runtime": "^7.24.7", "@rc-component/trigger": "^2.0.0", @@ -23430,9 +23430,9 @@ "optional": true }, "sass": { - "version": "1.77.6", - "resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.6.tgz", - "integrity": "sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==", + "version": "1.77.7", + "resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.7.tgz", + "integrity": "sha512-9ywH75cO+rLjbrZ6en3Gp8qAMwPGBapFtlsMJoDTkcMU/bSe5a6cjKVUn5Jr4Gzg5GbP3HE8cm+02pLCgcoMow==", "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", diff --git a/package.json b/package.json index f852f22..32ce17f 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,9 @@ "agora-electron-sdk": "^4.3.2", "antd": "^5.18.2", "axios": "^1.7.2", + "crypto-js": "^4.2.0", "dayjs": "^1.11.11", "electron-squirrel-startup": "^1.0.1", - "js-md5": "^0.8.3", "path": "^0.12.7", "postcss-px-to-viewport-8-plugin": "^1.2.5", "react": "^18.3.1", diff --git a/preload.js b/preload.js index 5f0913c..da07739 100644 --- a/preload.js +++ b/preload.js @@ -1,321 +1,24 @@ -// 在 preload 脚本中。 -const { ipcRenderer, contextBridge } = require('electron') -const { - createAgoraRtcEngine, - ClientRoleType, - VideoSourceType, - VideoViewSetupMode, - ScreenCaptureSourceType, - RenderModeType, - ChannelProfileType, - MediaRecorderContainerFormat, - MediaRecorderStreamType -} = require("agora-electron-sdk"); -const { message } = require('antd'); -const rtcEngine = createAgoraRtcEngine(); -const option = { - appId: 'dcfc466a6ecb4a1f972630065dfb1e75', - token: '', - channelId: '', - userid: '', -} -rtcEngine.initialize({ - appId: option.appId, -}); - -let videoID = ''; -let iMediaRecorder = ''; - -const getDom = () => { - return document.getElementById('video-1'); -} -// 离开频道 -const leaveChannel = () => { - rtcEngine.leaveChannel({ - stopAudioMixing: true, - stopAllEffect: true, - stopMicrophoneRecording: true, - }) -} -// 离开频道 -const joinChannel = (bool) => { - if (bool) { - rtcEngine.joinChannel(option.token, option.channelId, option.userid, { - channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 - clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众 - publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频 - publishCameraTrack: false, //设置是否发布摄像头采集的视频 - publishScreenTrack: true, //设置是否发布屏幕采集的视频 - autoSubscribeAudio: true, //设置是否自动订阅所有音频流 - autoSubscribeVideo: true, //设置是否自动订阅所有视频流 - }); - } else { - rtcEngine.joinChannel(option.token, option.channelId, option.userid, { - channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 - clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可 - publishMicrophoneTrack: true, //发布麦克风采集的音频 - publishCameraTrack: true, //发布摄像头采集的视频 - publishScreenTrack: false, //设置是否发布屏幕采集的视频 - autoSubscribeAudio: true, //自动订阅所有音频流 - autoSubscribeVideo: true, //自动订阅所有视频流 - }); +// // 在 preload 脚本中。 +const { ipcRenderer } = require('electron') +window.electron = { + // 设置窗口大小 + setMainWindowSize: (config) => { + ipcRenderer.invoke('setMainWindowSize', { ...config }) + }, + // 设置窗口状态 + setViewStatus: (status) => { + ipcRenderer.invoke('setViewStatus', status) + }, + // 获取当前是否全屏 + getIsMaximized: () => { + return ipcRenderer.invoke('getIsMaximized') + }, + // 复制文字 + setWriteText: (text) => { + return ipcRenderer.invoke('setWriteText', text) + }, + // 下载文件并放置选择的文件夹 + dwFile: (url) => { + ipcRenderer.invoke('dwFile', url) } -} - -// 停止共享屏幕 -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, - } - ); - } - joinChannel(true) - }, - // 摄像头采集 - setCameraCapture: () => { - rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) - joinChannel(false) - }, - // 加入频道 - setJoinChannel: (data) => { - option.token = data.token; - option.channelId = data.channelId; - option.userid = Number(data.userid); - rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) - joinChannel(false) - }, - // 离开频道 - 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: option.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) - }, - // 下载文件并放置选择的文件夹 - dwFile: (url) => { - ipcRenderer.invoke('dwFile', url) - }, - } -) - +} \ No newline at end of file diff --git a/src/api/Home/Index/index.ts b/src/api/Home/Index/index.ts index 2dfc1e7..5b4acf6 100644 --- a/src/api/Home/Index/index.ts +++ b/src/api/Home/Index/index.ts @@ -24,3 +24,9 @@ export const GetRoomRtcToken = (roomNum: string) => method: 'get', }) +export const GetRoomInfo = (roomNum: string) => + request({ + url: `/room/${roomNum}`, + method: 'get', + }) + diff --git a/src/api/Meeting/index.ts b/src/api/Meeting/index.ts index aed9674..544ffb4 100644 --- a/src/api/Meeting/index.ts +++ b/src/api/Meeting/index.ts @@ -26,9 +26,9 @@ export const GetRoomUpFileurl = (roomNum: string, fileSuffix: string) => method: 'get' }) -export const GetRoomFileDwUrl = (fileUrl: string) => +export const GetRoomFileDwUrl = (fileUrl: string, fileId: string) => request({ - url: `/room/file-dw-url?fileUrl=${fileUrl}`, + url: `/room/file-dw-url?fileUrl=${fileUrl}&fileId=${fileId}`, method: 'get' }) diff --git a/src/page/Home/Index/index.tsx b/src/page/Home/Index/index.tsx index 15b4996..483c8a9 100644 --- a/src/page/Home/Index/index.tsx +++ b/src/page/Home/Index/index.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import Operation from '@/components/Operation'; import { useNavigate } from 'react-router-dom'; import { Button, Input, Modal, Pagination, Empty, message } from "antd"; -import { GetRoom, PostRomm, GetCheckoutRoomNum, GetRoomRtcToken } from '@/api/Home/Index'; +import { GetRoom, PostRomm, GetCheckoutRoomNum, GetRoomRtcToken, GetRoomInfo } from '@/api/Home/Index'; const Index: React.FC = () => { const navigate = useNavigate(); const [list, setList] = useState({ @@ -119,7 +119,8 @@ const Index: React.FC = () => { navigate(`/meeting`, { state: { channelId: item.roomNum, - token: res + token: res, + roomId: item.id } }) } @@ -249,12 +250,18 @@ const Index: React.FC = () => { } isGetCheckoutRoomNum(joinRoomFrom, (bool: boolean) => { if (bool) { - getRoomRtcToken(joinRoomFrom, (res: any) => { - if (res) { - navigate(`/meeting`, { - state: { - channelId: joinRoomFrom, - token: res + getRoomRtcToken(joinRoomFrom, (token: string) => { + if (token) { + setJoinRoomModal(false) + GetRoomInfo(joinRoomFrom).then(res => { + if (res.code === 200) { + navigate(`/meeting`, { + state: { + channelId: joinRoomFrom, + token, + roomId: res.data.id + } + }) } }) } diff --git a/src/page/Home/User/index.tsx b/src/page/Home/User/index.tsx index 6d29ed1..86fa208 100644 --- a/src/page/Home/User/index.tsx +++ b/src/page/Home/User/index.tsx @@ -4,7 +4,7 @@ import Operation from '@/components/Operation'; import { Button, Input, Table, Pagination, Modal, message, Select } from "antd"; import { SearchOutlined } from '@ant-design/icons'; import { GetUserList, PostUser, PutUser, DeleteUser, PutUserPwd, GetRoleDpList } from '@/api/Home/User'; -import { md5 } from 'js-md5'; +import * as CryptoJS from 'crypto-js'; const { Column } = Table const User: React.FC = () => { const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -288,7 +288,7 @@ const User: React.FC = () => { if (isCreateUser) { await PostUser({ ...addUserFrom, - Pwd: md5(addUserFrom.Pwd) + Pwd: CryptoJS.MD5(addUserFrom.Pwd).toString(CryptoJS.enc.Hex) }).then(res => { if (res.code === 200) { setAddUserModal(false) @@ -356,7 +356,8 @@ const User: React.FC = () => { if (changeUserPawFrom.Pwd !== changeUserPawFrom.newPwd) { return message.error('新密码与确认密码不一致!') } - await PutUserPwd({ id: addUserFrom.Id, pwd: md5(changeUserPawFrom.Pwd) }).then(res => { + + await PutUserPwd({ id: addUserFrom.Id, pwd: CryptoJS.MD5(changeUserPawFrom.Pwd).toString(CryptoJS.enc.Hex) }).then(res => { if (res.code === 200) { setChangeUserPawModal(false) message.success('修改成功') diff --git a/src/page/Login/index.tsx b/src/page/Login/index.tsx index f8c0500..96131b9 100644 --- a/src/page/Login/index.tsx +++ b/src/page/Login/index.tsx @@ -5,7 +5,7 @@ import { useNavigate } from 'react-router-dom'; import { Input, Button, Checkbox, message } from "antd" import { storage } from '@/utils' import { GetCheckUser, PostLogin } from '@/api/Login' -import { md5 } from 'js-md5'; +import * as CryptoJS from 'crypto-js'; import { startSignalr } from '@/utils/package/signalr' const Login: React.FC = () => { const navigate = useNavigate(); @@ -102,7 +102,7 @@ const Login: React.FC = () => { const loginClick = (): void => { PostLogin({ account: operation.account, - pwd: md5(operation.password) + pwd: CryptoJS.MD5(operation.password).toString(CryptoJS.enc.Hex) }).then(res => { if (res.code === 200) { message.success('登录成功!') @@ -118,8 +118,8 @@ const Login: React.FC = () => { width: 1200, height: 800, }) - startSignalr() navigate('/home') + startSignalr() } }) } diff --git a/src/page/Meeting/index.tsx b/src/page/Meeting/index.tsx index 73a4bbb..5e27013 100644 --- a/src/page/Meeting/index.tsx +++ b/src/page/Meeting/index.tsx @@ -114,7 +114,7 @@ const Meeting: React.FC = () => { useEffect(() => { if (isInit) { setUser(JSON.parse(storage.getItem('user') as string)) - // window.electron.setJoinChannel({ + // window.agora.setJoinChannel({ // channelId: state.channelId, // userid: user.userName, // token: state.token, @@ -149,49 +149,49 @@ const Meeting: React.FC = () => { setIsSharedScreenModal(true) break; case '停止共享': - window.electron.stopScreenCapture() + window.agora.stopScreenCapture() footerListTemplate[itemIndex][rowIndex].title = '共享屏幕' break; case '关闭声音': footerListTemplate[itemIndex][rowIndex].title = '开启声音' footerListTemplate[itemIndex][rowIndex].active = true setFooterList(footerListTemplate) - window.electron.muteLocalAudioStream(true) + window.agora.muteLocalAudioStream(true) break; case '开启声音': footerListTemplate[itemIndex][rowIndex].title = '关闭声音' footerListTemplate[itemIndex][rowIndex].active = false setFooterList(footerListTemplate) - window.electron.muteLocalAudioStream(false) + window.agora.muteLocalAudioStream(false) break; case '关闭视频': footerListTemplate[itemIndex][rowIndex].title = '开启视频' footerListTemplate[itemIndex][rowIndex].active = true setFooterList(footerListTemplate) - window.electron.muteLocalVideoStream(true) + window.agora.muteLocalVideoStream(true) break; case '开启视频': footerListTemplate[itemIndex][rowIndex].title = '关闭视频' footerListTemplate[itemIndex][rowIndex].active = false setFooterList(footerListTemplate) - window.electron.muteLocalVideoStream(false) + window.agora.muteLocalVideoStream(false) break; case '设置向导': getAudioMediaList() - window.electron.startRecordingDeviceTest(200) + window.agora.startRecordingDeviceTest(200) setIsStupWizard(true) break; case '录制': footerListTemplate[itemIndex][rowIndex].title = '录制中' footerListTemplate[itemIndex][rowIndex].active = true setFooterList(footerListTemplate) - window.electron.startRecording() + window.agora.startRecording() break; case '录制中': footerListTemplate[itemIndex][rowIndex].title = '录制' footerListTemplate[itemIndex][rowIndex].active = false setFooterList(footerListTemplate) - window.electron.stopRecording() + window.agora.stopRecording() break; case '共享文件': await getRoomFile() @@ -209,8 +209,8 @@ const Meeting: React.FC = () => { const footerListTemplate = [...footerList] footerListTemplate[footerListIndex.itemIndex][footerListIndex.rowIndex].title = '停止共享' setIsSharedScreenModal(false) - window.electron.setDesktopCapturerVideo(sharedScreenItem) - setVideoID(window.electron.getVideoId()) + window.agora.setDesktopCapturerVideo(sharedScreenItem) + setVideoID(window.agora.getVideoId()) } else { message.error('请选择应用!') } @@ -218,7 +218,7 @@ const Meeting: React.FC = () => { } const getDesktopCapturerVideo = (): void => { - window.electron.getDesktopCapturerVideo().then((res: any) => { + window.agora.getDesktopCapturerVideo().then((res: any) => { if (sharedScreenList.length !== res.length) { res.forEach((item: any) => { if (item.thumbImage.buffer) { @@ -234,7 +234,7 @@ const Meeting: React.FC = () => { }; const getAudioMediaList = (): void => { - const { currentDevices, currentDevice, currentVolume } = window.electron.getAudioMediaList(); + const { currentDevices, currentDevice, currentVolume } = window.agora.getAudioMediaList(); setAudioDeviceManager({ currentDevices: currentDevices.map((row: any) => { return { @@ -252,7 +252,7 @@ const Meeting: React.FC = () => { pageIndex: fileList.pageIndex, pageSize: fileList.pageSize, keyword: fileList.keyword, - roomId: state.channelId + roomId: state.roomId }).then(res => { if (res.code === 200) { setFileList({ @@ -400,13 +400,13 @@ const Meeting: React.FC = () => { content={
{ - window.electron.leaveChannel() - window.electron.stopScreenCapture() + window.agora.leaveChannel() + window.agora.stopScreenCapture() navigate(-1) }}>全员结束会议
{ - window.electron.leaveChannel() - window.electron.stopScreenCapture() + window.agora.leaveChannel() + window.agora.stopScreenCapture() navigate(-1) }}>仅自己离开
{ setOpen(false) }}>取消
@@ -477,7 +477,7 @@ const Meeting: React.FC = () => { ...audioDeviceManager, currentDevice: e }) - window.electron.setRecordingDevice(e); + window.agora.setRecordingDevice(e); getAudioMediaList() }} />; @@ -489,7 +489,7 @@ const Meeting: React.FC = () => { ...audioDeviceManager, currentVolume: e }) - window.electron.setRecordingDeviceVolume(e) + window.agora.setRecordingDeviceVolume(e) }} style={{ flexGrow: 1 }} />
:
@@ -526,7 +526,7 @@ const Meeting: React.FC = () => { audio.srcObject = null; } setStepsStatus(false) - window.electron.startPreview().then((res: boolean) => { + window.agora.startPreview().then((res: boolean) => { setIsVideoLoad(res) }) }}>下一步 @@ -538,9 +538,9 @@ const Meeting: React.FC = () => { onClick={() => { if (isVideoLoad) { setIsVideoLoad(false) - window.electron.stopAudioDeviceLoopbackTest() + window.agora.stopAudioDeviceLoopbackTest() setStepsStatus(true) - window.electron.startRecordingDeviceTest(200) + window.agora.startRecordingDeviceTest(200) } else { message.error('视频加载中!') } @@ -551,8 +551,8 @@ const Meeting: React.FC = () => { className='m-ant-btn' onClick={() => { if (isVideoLoad) { - window.electron.stopAudioDeviceLoopbackTest() - window.electron.setRecordingDeviceVolume(audioDeviceManager.currentVolume) + window.agora.stopAudioDeviceLoopbackTest() + window.agora.setRecordingDeviceVolume(audioDeviceManager.currentVolume) setIsStupWizard(false) setStepsStatus(true) setIsVideoLoad(false) @@ -654,7 +654,7 @@ const Meeting: React.FC = () => { fileUrl: res.data.key, size: fileInfo.size, fileName: fileInfo.name, - roomId: state.channelId + roomId: state.roomId }) getRoomFile() }) @@ -696,7 +696,7 @@ const Meeting: React.FC = () => { ( <> { - GetRoomFileDwUrl(item.fileUrl).then(res => { + GetRoomFileDwUrl(item.fileUrl, item.id).then(res => { if (res.code === 200) { window.electron.dwFile(res.data) } diff --git a/src/render.d.ts b/src/render.d.ts index a9625e2..b6dbe0b 100644 --- a/src/render.d.ts +++ b/src/render.d.ts @@ -1,14 +1,18 @@ // electron-env.d.ts export interface IElectronAPI { + setMainWindowSize: (config: any) => void; + setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void; + getIsMaximized: () => Promise; + setWriteText: (text: string) => void; + dwFile: (url: string) => void; +} +export interface Agora { getDesktopCapturerVideo: () => Promise; setDesktopCapturerVideo: (data: any) => void; setCameraCapture: (data: any) => void; getAudioMediaList: () => { currentDevice: any, currentDevices: any, currentVolume: number }; setRecordingDeviceVolume: (volume: number) => void; setRecordingDevice: (deviceId: string) => void; - setMainWindowSize: (config: any) => void; - getIsMaximized: () => Promise; - setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void; setJoinChannel: (data: { channelId: string, userid: string, token: string }) => Promise; getVideoId: () => string; startRecordingDeviceTest: (indicationInterval: number) => void; @@ -20,12 +24,10 @@ export interface IElectronAPI { stopScreenCapture: () => void; muteLocalAudioStream: (mute: boolean) => void; muteLocalVideoStream: (mute: boolean) => void; - setWriteText: (text: string) => void; - dwFile: (url: string) => void; } - declare global { interface Window { electron: IElectronAPI; + agora: Agora } -} +} \ No newline at end of file diff --git a/src/shims-react.d.ts b/src/shims-react.d.ts index 754eb11..efafa2a 100644 --- a/src/shims-react.d.ts +++ b/src/shims-react.d.ts @@ -1 +1,2 @@ -declare module 'react-dom/client'; \ No newline at end of file +declare module 'react-dom/client'; +declare module 'crypto-js'; \ No newline at end of file diff --git a/src/utils/package/agora.js b/src/utils/package/agora.js new file mode 100644 index 0000000..2e07b48 --- /dev/null +++ b/src/utils/package/agora.js @@ -0,0 +1,295 @@ +const { + createAgoraRtcEngine, + ClientRoleType, + VideoSourceType, + VideoViewSetupMode, + ScreenCaptureSourceType, + RenderModeType, + ChannelProfileType, + MediaRecorderContainerFormat, + MediaRecorderStreamType +} = require("agora-electron-sdk"); +const { message } = require('antd'); +const rtcEngine = createAgoraRtcEngine(); +const option = { + appId: 'dcfc466a6ecb4a1f972630065dfb1e75', + token: '', + channelId: '', + userid: '', +} +rtcEngine.initialize({ + appId: option.appId, +}); + +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}%` + } + } +}); + +let videoID = ''; +let iMediaRecorder = ''; + +const agora = { + getDom: () => { + return document.getElementById('video-1'); + }, + // 离开频道 + leaveChannel: () => { + rtcEngine.leaveChannel({ + stopAudioMixing: true, + stopAllEffect: true, + stopMicrophoneRecording: true, + }) + }, + // 加入频道 + joinChannel: (bool) => { + if (bool) { + rtcEngine.joinChannel(option.token, option.channelId, option.userid, { + channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 + clientRoleType: ClientRoleType.ClientRoleBroadcaster, //用户角色 1主播 2观众 + publishMicrophoneTrack: true, //设置是否发布麦克风采集到的音频 + publishCameraTrack: false, //设置是否发布摄像头采集的视频 + publishScreenTrack: true, //设置是否发布屏幕采集的视频 + autoSubscribeAudio: true, //设置是否自动订阅所有音频流 + autoSubscribeVideo: true, //设置是否自动订阅所有视频流 + }); + } else { + rtcEngine.joinChannel(option.token, option.channelId, option.userid, { + channelProfile: ChannelProfileType.ChannelProfileLiveBroadcasting, //设置频道场景为直播场景 + clientRoleType: ClientRoleType.ClientRoleBroadcaster, //设置用户角色为主播;如果要将用户角色设置为观众,保持默认值即可 + publishMicrophoneTrack: true, //发布麦克风采集的音频 + publishCameraTrack: true, //发布摄像头采集的视频 + publishScreenTrack: false, //设置是否发布屏幕采集的视频 + autoSubscribeAudio: true, //自动订阅所有音频流 + autoSubscribeVideo: true, //自动订阅所有视频流 + }); + } + }, + // 停止录制音视频 + stopRecording: () => { + iMediaRecorder.stopRecording() + rtcEngine.destroyMediaRecorder(iMediaRecorder) + iMediaRecorder = "" + }, + // 开始录制音视频 + startRecording: () => { + iMediaRecorder = rtcEngine.createMediaRecorder({ + channelId: option.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 + }) + }, + // 停止共享屏幕 + stopScreenCapture: () => { + rtcEngine.stopScreenCapture(); + }, + // 开启本地视频预览 + 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) + }); + }) + }, + // 停止音频设备回路测试 + 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; + } + }, + // 启动音频采集设备测试 + 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('无法获取麦克风!'); + }); + }, + // 获取音频设备列表 + 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) + }, + // 摄像头采集 + setCameraCapture: () => { + rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) + // joinChannel(false) + }, + // 加入频道 + setJoinChannel: (data) => { + option.token = data.token; + option.channelId = data.channelId; + option.userid = Number(data.userid); + rtcEngine.startCameraCapture(VideoSourceType.VideoSourceCamera, {}) + // joinChannel(false) + }, + // 离开频道 + leaveChannel: () => { + // leaveChannel() + }, + // 停止共享屏幕 + stopScreenCapture: () => { + // stopScreenCapture() + }, + // 取消或恢复发布本地音频流 + muteLocalAudioStream: (mute) => { + rtcEngine.muteLocalAudioStream(mute) + }, + // 取消或恢复发布本地视频流 + muteLocalVideoStream: (mute) => { + rtcEngine.muteLocalVideoStream(mute) + }, + // 获取当前生成的视频id + getVideoId: () => { + return videoID; + }, + // 桌面捕获音频和视频的媒体源的信息 + 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, + } + ); + } + // joinChannel(true) + }, +} + +window.agora = agora; \ No newline at end of file