Files
BetterDesk/web-nodejs/views/cdap-device.ejs
T
UNITRONIX 15bca36787 feat(codec): GPU multi-codec video for CDAP rdclient incl. plain HTTP
Enables hardware-accelerated video for the CDAP/OS-agent rdclient path instead of being stuck on 1-2fps MJPEG, including over plain HTTP (no HTTPS/domain/cert required).

Browser viewers (web-nodejs): cdap-adapter.js and cdap-desktop.js now decode video via the shared RDVideo pipeline. WebCodecs (AV1/VP9/H264, hardware-accelerated) is used in secure contexts (HTTPS/localhost); over plain HTTP, H.264 is decoded through JMuxer/MSE using the browser's native (usually GPU) decoder. Viewers advertise decodableCodecs() in the desktop_start init payload so the agent sends a real GPU stream; MJPEG/WebP remain safe fallbacks. cdap-device.ejs preloads jmuxer + RDVideo.

Go agent (betterdesk-agent): codec.go + codec_framing.go add multi-codec engine with GPU encoder probing and selection order AV1 -> VP9 -> H264 -> WebP; desktop.go intersects the operator-advertised codec list with local encoder ability and emits honest desktop_meta (format + codec_string); config.go adds codec config fields.

Go server (betterdesk-server): cdap_handlers.go + cdap/desktop.go thread the codecs[] / video_codec fields through desktop_start so operator codec advertisement reaches the agent.

Tauri agent-client: config.rs/sidecar.rs/commands.rs codec plumbing, SettingsPanel codec dropdown + en/pl/zh i18n, refreshed agent sidecar binary.

Note: AV1/VP9 still require WebCodecs (HTTPS/localhost); H.264-over-MSE covers the plain-HTTP case. Self-signed HTTPS (installer SSL menu option C) unlocks all codecs. Fully backward compatible.

This commit was made possible thanks to Insolve.
2026-05-31 02:29:53 +02:00

117 lines
5.4 KiB
HTML

<%- include('layouts/main', {
title: _('cdap.device_detail'),
pageStyles: ['cdap'],
pageScripts: ['vendor/jmuxer.min', 'rdclient/video', 'cdap-widgets', 'cdap-commands', 'cdap-terminal', 'cdap-desktop', 'cdap-video', 'cdap-filebrowser', 'cdap-audio'],
currentPage: 'devices',
breadcrumb: [
{ label: _('nav.devices'), href: '/devices' },
{ label: _('cdap.device_detail') }
],
body: `
<div class="cdap-device-page" data-device-id="${deviceId}">
<!-- Device Header -->
<div class="cdap-device-header">
<div class="cdap-device-title">
<a href="/devices" class="btn-icon cdap-back-btn" title="${_('common.back')}">
<span class="material-icons">arrow_back</span>
</a>
<div class="cdap-device-identity">
<h1 id="cdap-device-name">${deviceId}</h1>
<div class="cdap-device-meta" id="cdap-device-meta">
<span class="cdap-meta-item" id="cdap-device-type">
<span class="material-icons">memory</span>
<span></span>
</span>
<span class="cdap-meta-item" id="cdap-device-version">
<span class="material-icons">info_outline</span>
<span></span>
</span>
<span class="cdap-meta-item" id="cdap-device-uptime">
<span class="material-icons">schedule</span>
<span></span>
</span>
</div>
</div>
</div>
<div class="cdap-device-status" id="cdap-device-status">
<span class="cdap-status-dot"></span>
<span class="cdap-status-text">${_('cdap.loading')}</span>
</div>
</div>
<!-- Connection Banner (shown when disconnected) -->
<div class="cdap-offline-banner hidden" id="cdap-offline-banner">
<span class="material-icons">cloud_off</span>
<span>${_('cdap.device_offline_msg')}</span>
</div>
<!-- Active Alerts Panel -->
<div class="cdap-alerts-panel hidden" id="cdap-alerts-panel">
<div class="cdap-alerts-header">
<h3>
<span class="material-icons">warning</span>
${_('cdap.active_alerts')}
<span class="cdap-alerts-count" id="cdap-alerts-count">0</span>
</h3>
</div>
<div class="cdap-alerts-list" id="cdap-alerts-list">
<!-- Alert items rendered by cdap-widgets.js -->
</div>
</div>
<!-- Linked Devices Panel -->
<div class="cdap-linked-panel" id="cdap-linked-panel">
<div class="cdap-linked-header">
<h3>
<span class="material-icons">device_hub</span>
${_('cdap.linked_devices')}
<span class="cdap-linked-count" id="cdap-linked-count">0</span>
</h3>
<button class="btn-sm btn-accent" id="cdap-link-btn" title="${_('cdap.link_device')}">
<span class="material-icons">add_link</span>
<span>${_('cdap.link_device')}</span>
</button>
</div>
<div class="cdap-linked-list" id="cdap-linked-list">
<div class="cdap-linked-empty" id="cdap-linked-empty">
<span class="material-icons">link_off</span>
<span>${_('cdap.no_linked_devices')}</span>
</div>
</div>
</div>
<!-- Widget Grid -->
<div class="cdap-widget-grid" id="cdap-widget-grid">
<!-- Widgets rendered by cdap-widgets.js -->
<div class="cdap-loading" id="cdap-loading">
<div class="cdap-loading-spinner"></div>
<p>${_('cdap.loading_widgets')}</p>
</div>
</div>
<!-- Empty State (no manifest) -->
<div class="cdap-empty hidden" id="cdap-empty">
<span class="material-icons cdap-empty-icon">widgets</span>
<h3>${_('cdap.no_widgets')}</h3>
<p>${_('cdap.no_widgets_desc')}</p>
</div>
<!-- Command Log -->
<div class="cdap-command-log hidden" id="cdap-command-log">
<div class="cdap-command-log-header">
<h3>
<span class="material-icons">terminal</span>
${_('cdap.command_log')}
</h3>
<button class="btn-icon" id="cdap-clear-log" title="${_('cdap.clear_log')}">
<span class="material-icons">delete_sweep</span>
</button>
</div>
<div class="cdap-command-log-entries" id="cdap-log-entries">
<!-- Command log entries appended by cdap-commands.js -->
</div>
</div>
</div>
`
}) %>