mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-09-13 19:14:24 +08:00
fix: 修复无信号状态同步与采集管线阻塞
- 使用非阻塞 V4L2 句柄并类型化采集错误 - 完善视频管线生命周期,避免复用停止中的管线 - 区分音视频事件并支持 REST/WebSocket 状态快照 - 修复信号丢失后保留最后一帧及刷新后黑屏问题 - 优化无信号提示、状态展示优先级及相关界面细节 - 降低重复 OTG 错误日志级别
This commit is contained in:
@@ -27,7 +27,7 @@ import { formatFpsValue } from '@/lib/fps'
|
||||
import { videoDebugLog } from '@/lib/debugLog'
|
||||
import { formatVideoDeviceLabel } from '@/lib/video-device-label'
|
||||
import { isAudioDeviceLostStateReason, isAudioStreamDeviceLostPayload } from '@/lib/streamSignal'
|
||||
import type { StreamDeviceLostEventData } from '@/types/websocket'
|
||||
import type { StreamDeviceLostEventData, StreamStateChangedEventData } from '@/types/websocket'
|
||||
import type { VideoMode } from '@/components/VideoConfigPopover.vue'
|
||||
|
||||
import StatusCard, { type StatusDetail } from '@/components/StatusCard.vue'
|
||||
@@ -1356,7 +1356,7 @@ function handleStreamModeSwitching(data: { transition_id: string; to_mode: strin
|
||||
videoSession.onModeSwitching(data)
|
||||
}
|
||||
|
||||
function handleStreamStateChanged(data: any) {
|
||||
function handleStreamStateChanged(data: StreamStateChangedEventData) {
|
||||
videoDebugLog('Stream state changed event', {
|
||||
data,
|
||||
videoMode: videoMode.value,
|
||||
@@ -1468,8 +1468,8 @@ const signalOverlayInfo = computed(() => {
|
||||
case 'no_signal':
|
||||
return {
|
||||
title: t('console.signal.noSignal.title'),
|
||||
detail: t('console.signal.noSignal.detail'),
|
||||
hint,
|
||||
detail: hint || t('console.signal.noSignal.detail'),
|
||||
hint: '',
|
||||
tone: 'info' as const,
|
||||
}
|
||||
case 'device_lost':
|
||||
@@ -3083,6 +3083,10 @@ onMounted(async () => {
|
||||
}, { immediate: true })
|
||||
|
||||
await systemStore.startStream().catch(() => {})
|
||||
const initialStreamStatus = await streamApi.status().catch(() => null)
|
||||
if (initialStreamStatus) {
|
||||
handleStreamStateChanged(initialStreamStatus)
|
||||
}
|
||||
await systemStore.fetchSystemInfo().catch(() => {})
|
||||
await systemStore.fetchAllStates()
|
||||
await configStore.refreshHid().then(() => {
|
||||
@@ -3398,7 +3402,7 @@ onUnmounted(() => {
|
||||
</div>
|
||||
<Transition name="fade">
|
||||
<div
|
||||
v-if="videoLoading"
|
||||
v-if="videoLoading && !showSignalOverlay && !videoError"
|
||||
class="absolute inset-0 flex flex-col items-center justify-center bg-black/70 backdrop-blur-sm transition-opacity duration-300"
|
||||
>
|
||||
<div class="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
@@ -3443,7 +3447,7 @@ onUnmounted(() => {
|
||||
</Transition>
|
||||
<Transition name="fade">
|
||||
<div
|
||||
v-if="showSignalOverlay && !videoLoading && !videoError"
|
||||
v-if="showSignalOverlay && !videoError"
|
||||
class="absolute inset-0 flex flex-col items-center justify-center gap-3 p-4 transition-opacity duration-300 pointer-events-none"
|
||||
:class="{
|
||||
'bg-black/80 backdrop-blur-sm': signalOverlayInfo.tone === 'error',
|
||||
|
||||
@@ -2717,7 +2717,6 @@ watch(isWindows, () => {
|
||||
<Sidebar class="top-10 h-[calc(100dvh-2.5rem)] sm:top-14 sm:h-[calc(100dvh-3.5rem)]" collapsible="offcanvas">
|
||||
<SidebarHeader class="gap-1 px-6 pt-4 pb-2 text-foreground md:pt-6">
|
||||
<h1 class="text-xl font-semibold">{{ t('settings.title') }}</h1>
|
||||
<p class="text-xs text-muted-foreground">{{ t('settings.sidebarSubtitle') }}</p>
|
||||
</SidebarHeader>
|
||||
<SidebarContent class="px-3 pb-6 md:pb-10">
|
||||
<SidebarGroup v-for="group in navGroups" :key="group.title" class="px-0 py-1">
|
||||
|
||||
Reference in New Issue
Block a user