Skip to content

Commit

Permalink
feat(web): 优化监控帧率选择,优化监控获取算法
Browse files Browse the repository at this point in the history
  • Loading branch information
enncy committed Dec 21, 2023
1 parent 751c84c commit 2d656b0
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 53 deletions.
9 changes: 7 additions & 2 deletions packages/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import { task } from './src/utils';
import { handleError } from './src/tasks/error.handler';
import { updater } from './src/tasks/updater';
import { startupServer } from './src/tasks/startup.server';
import { store } from './src/store';

app.setName('ocs');

// 设置 webrtc 的影像帧率比例,最高100,太高会造成卡顿,默认50
app.commandLine.appendSwitch('webrtc-max-cpu-consumption-percentage', '100');
// 防止软件崩溃以及兼容
app.commandLine.appendSwitch('no-sandbox');
app.commandLine.appendSwitch('disable-gpu');
Expand Down Expand Up @@ -42,6 +41,12 @@ function bootstrap() {
}),
task('初始化自动启动', () => autoLaunch()),
task('启动渲染进程', async () => {
// 设置 webrtc 的影像帧率比例,最高100,太高会造成卡顿,参数默认50
app.commandLine.appendSwitch(
'webrtc-max-cpu-consumption-percentage',
(store?.store?.render?.dashboard?.video?.frameRate ?? 1).toString()
);

await app.whenReady();
const window = createWindow();

Expand Down
3 changes: 2 additions & 1 deletion packages/app/src/worker/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,10 @@ export class ScriptWorker {
document.body.innerHTML = `正在获取图像中,请勿操作。`;
}, this.uid)
.catch(console.error);

setTimeout(() => {
send('webrtc-page-loaded');
}, 3000);
}, 100);
}
}

Expand Down
163 changes: 113 additions & 50 deletions packages/web/src/pages/dashboard/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@
</template>

<a-tooltip
content="显示每个浏览器的图像,如果太多浏览器可能会造成电脑卡顿"
:content="
launchedProcesses.length === 0
? '暂无运行浏览器,无法开始监控'
: '显示每个浏览器的图像,如果太多浏览器可能会造成电脑卡顿'
"
position="bl"
>
<a-button
size="mini"
type="outline"
:disabled="launchedProcesses.length === 0 || state.loading"
@click="state.show = !state.show"
>
<template v-if="state.loading"> 加载中... </template>
<template v-else> {{ state.show ? '暂停' : '开始' }}监控 </template>
</a-button>
<div>
<a-button
size="mini"
type="outline"
:disabled="launchedProcesses.length === 0 || state.loading"
@click="state.show = !state.show"
>
<template v-if="state.loading"> 加载中... </template>
<template v-else> {{ state.show ? '暂停' : '开始' }}监控 </template>
</a-button>
</div>
</a-tooltip>

<a-switch v-model="store.render.dashboard.details.tags">
Expand Down Expand Up @@ -58,12 +64,12 @@
<a-select
v-model="store.render.dashboard.video.frameRate"
size="mini"
style="width: 220px"
style="width: 180px"
:options="[
{ label: '节能', value: 0.1 },
{ label: '流畅', value: 1 },
{ label: '高帧(CPU占比高)', value: 10 },
{ label: '最高(CPU占比高)', value: 99 }
{ label: '节能', value: 1 },
{ label: '流畅', value: 4 },
{ label: '高帧(消耗CPU)', value: 20 },
{ label: '最高(很耗CPU)', value: 100 }
]"
>
<template #prefix> 帧率 </template>
Expand Down Expand Up @@ -226,7 +232,7 @@
</template>

<script setup lang="ts">
import { onDeactivated, watch, reactive, computed, onActivated } from 'vue';
import { onDeactivated, watch, reactive, computed, onActivated, onMounted } from 'vue';
import { Process, processes } from '../../utils/process';
import BrowserOperators from '../../components/browsers/BrowserOperators.vue';
import { store } from '../../store';
Expand Down Expand Up @@ -273,7 +279,7 @@ watch(
() => store.render.dashboard.video.frameRate,
() => {
Modal.info({
content: '修改帧率后请 重新开启监控/重启软件 才可生效。'
content: '修改帧率后请 重启软件 才可生效。'
});
}
);
Expand Down Expand Up @@ -302,6 +308,15 @@ onDeactivated(() => {
}
});
onMounted(() => {
// 持续挂载视频,防止丢失
setInterval(() => {
for (const process of processes) {
mountVideo(process);
}
}, 3000);
});
/**
* 关闭视频显示
*/
Expand Down Expand Up @@ -331,43 +346,83 @@ async function refreshVideo() {
)
);
// 抓取屏幕
const sources: DesktopCapturerSource[] = await remote.desktopCapturer.call('getSources', { types: ['window'] });
console.log('sources', sources);
const processStatus: Map<string, boolean> = new Map();
for (const process of processes) {
const res = await getBrowserVideo(process.uid, sources);
if (res) {
process.stream = res.stream;
process.stream?.getTracks().forEach((track) => {
track.applyConstraints({
/** 尽量减低帧率不占用高内存 */
frameRate: store.render.dashboard.video.frameRate ?? 1,
/** 横纵比 */
aspectRatio:
store.render.dashboard.video.aspectRatio === 0 ? undefined : store.render.dashboard.video.aspectRatio
});
});
process.video = res.video;
}
// 挂载视频
const slot = document.querySelector(`#video-${process.uid}`);
if (slot && process.video) {
slot.replaceChildren(process.video);
}
processStatus.set(process.uid, false);
}
await Promise.all(
processes.map(
(process) =>
new Promise<void>((resolve) => {
process.once('webrtc-page-closed', resolve);
process.worker?.('closeWebRTCPage');
let retryCount = 20;
async function loop() {
retryCount--;
console.log('looping', retryCount);
// 抓取屏幕
const sources: DesktopCapturerSource[] = await remote.desktopCapturer.call('getSources', { types: ['window'] });
// 未完成的进程抓取屏幕
await Promise.all(
processes
.filter((p) => processStatus.get(p.uid) === false)
.map((process) => {
return new Promise<void>((resolve, reject) => {
getBrowserVideo(process.uid, sources)
.then((res) => {
if (!res) {
return resolve();
}
process.stream = res.stream;
process.stream?.getTracks().forEach((track) => {
track.applyConstraints({
/** 尽量减低帧率不占用高内存 */
frameRate: store.render.dashboard.video.frameRate ?? 1,
/** 横纵比 */
aspectRatio:
store.render.dashboard.video.aspectRatio === 0
? undefined
: store.render.dashboard.video.aspectRatio
});
});
process.video = res.video;
// 挂载视频
mountVideo(process);
processStatus.set(process.uid, true);
resolve();
})
.catch((err) => {
console.error(err);
resolve();
});
});
})
)
);
);
// 已完成的进程关闭 webrtc 对接页面
await Promise.all(
processes
.filter((p) => processStatus.get(p.uid) === true)
.map(
(process) =>
new Promise<void>((resolve) => {
process.once('webrtc-page-closed', resolve);
process.worker?.('closeWebRTCPage');
})
)
);
// 如果还有未完成的进程,则等待 3s 后再次执行
if (processes.filter((p) => processStatus.get(p.uid) === false).length !== 0 && retryCount > 0) {
await new Promise((resolve) => setTimeout(resolve, 3000));
await loop();
}
}
await loop();
state.loading = false;
}
Expand Down Expand Up @@ -402,6 +457,14 @@ async function getBrowserVideo(uid: string, sources: DesktopCapturerSource[]) {
}
}
}
// 挂载视频
function mountVideo(process: Process) {
const slot = document.querySelector(`#video-${process.uid}`);
// 如果 slot.children.length === 0 说明没有挂载视频
if (slot && slot.children.length === 0 && process.video) {
slot.replaceChildren(process.video);
}
}
function openBrowser(uid: string) {
Process.from(uid)?.bringToFront();
Expand Down

0 comments on commit 2d656b0

Please # to comment.