下载文件准备
This commit is contained in:
parent
250cb75558
commit
76db877293
|
|
@ -14,6 +14,7 @@
|
|||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script type="module" src="/src/utils/package/agora.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
2
main.js
2
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,
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
343
preload.js
343
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)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
|
@ -24,3 +24,9 @@ export const GetRoomRtcToken = (roomNum: string) =>
|
|||
method: 'get',
|
||||
})
|
||||
|
||||
export const GetRoomInfo = (roomNum: string) =>
|
||||
request({
|
||||
url: `/room/${roomNum}`,
|
||||
method: 'get',
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<React.Key[]>([]);
|
||||
|
|
@ -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('修改成功')
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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={
|
||||
<div className='meetingContentFooterPopover'>
|
||||
<div onClick={() => {
|
||||
window.electron.leaveChannel()
|
||||
window.electron.stopScreenCapture()
|
||||
window.agora.leaveChannel()
|
||||
window.agora.stopScreenCapture()
|
||||
navigate(-1)
|
||||
}}>全员结束会议</div>
|
||||
<div onClick={() => {
|
||||
window.electron.leaveChannel()
|
||||
window.electron.stopScreenCapture()
|
||||
window.agora.leaveChannel()
|
||||
window.agora.stopScreenCapture()
|
||||
navigate(-1)
|
||||
}}>仅自己离开</div>
|
||||
<div onClick={() => { setOpen(false) }}>取消</div>
|
||||
|
|
@ -477,7 +477,7 @@ const Meeting: React.FC = () => {
|
|||
...audioDeviceManager,
|
||||
currentDevice: e
|
||||
})
|
||||
window.electron.setRecordingDevice(e);
|
||||
window.agora.setRecordingDevice(e);
|
||||
getAudioMediaList()
|
||||
}} />;
|
||||
<audio src="" id='startAudio'></audio>
|
||||
|
|
@ -489,7 +489,7 @@ const Meeting: React.FC = () => {
|
|||
...audioDeviceManager,
|
||||
currentVolume: e
|
||||
})
|
||||
window.electron.setRecordingDeviceVolume(e)
|
||||
window.agora.setRecordingDeviceVolume(e)
|
||||
}} style={{ flexGrow: 1 }} />
|
||||
</div> :
|
||||
<div>
|
||||
|
|
@ -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)
|
||||
})
|
||||
}}>下一步</Button>
|
||||
|
|
@ -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 = () => {
|
|||
<Column title="操作" render={(item) => (
|
||||
<>
|
||||
<VerticalAlignBottomOutlined title='下载' style={{ color: '#5575F2', cursor: 'pointer' }} onClick={() => {
|
||||
GetRoomFileDwUrl(item.fileUrl).then(res => {
|
||||
GetRoomFileDwUrl(item.fileUrl, item.id).then(res => {
|
||||
if (res.code === 200) {
|
||||
window.electron.dwFile(res.data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
// electron-env.d.ts
|
||||
export interface IElectronAPI {
|
||||
setMainWindowSize: (config: any) => void;
|
||||
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
||||
getIsMaximized: () => Promise<boolean>;
|
||||
setWriteText: (text: string) => void;
|
||||
dwFile: (url: string) => void;
|
||||
}
|
||||
export interface Agora {
|
||||
getDesktopCapturerVideo: () => Promise<void>;
|
||||
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<boolean>;
|
||||
setViewStatus: (status: 'quit' | 'maximize' | 'minimize' | 'unmaximize') => void;
|
||||
setJoinChannel: (data: { channelId: string, userid: string, token: string }) => Promise<void>;
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1,2 @@
|
|||
declare module 'react-dom/client';
|
||||
declare module 'react-dom/client';
|
||||
declare module 'crypto-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;
|
||||
Loading…
Reference in New Issue