initial commit
This commit is contained in:
47
overlay/entrypoint.sh
Normal file
47
overlay/entrypoint.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
###
|
||||
# File: entrypoint.sh
|
||||
# Project: docker-steamos
|
||||
# File Created: Saturday, 8th January 2022 7:08:46 pm
|
||||
# Author: Josh.5 (jsunnex@gmail.com)
|
||||
# -----
|
||||
# Last Modified: Tuesday, 11th January 2022 1:02:16 am
|
||||
# Modified By: Josh.5 (jsunnex@gmail.com)
|
||||
###
|
||||
|
||||
set -e
|
||||
|
||||
# If a command was passed, run that instead of the usual init process
|
||||
if [ ! -z "$@" ]; then
|
||||
exec $@
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Execute all init scripts
|
||||
for init_script in /scripts/*.sh ; do
|
||||
echo
|
||||
echo "[ ${init_script}: executing... ]"
|
||||
sed -i 's/\r$//' "${init_script}"
|
||||
source "${init_script}"
|
||||
done
|
||||
|
||||
# Execute any user generated init scripts
|
||||
mkdir -p ${USER_HOME}/init.d
|
||||
chown -R ${USER} ${USER_HOME}/init.d
|
||||
for user_init_script in ${USER_HOME}/init.d/*.sh ; do
|
||||
|
||||
# Check that a file was found
|
||||
# (If no files exist in this directory, then user_init_script will be empty)
|
||||
if [[ -e "${user_init_script}" ]]; then
|
||||
|
||||
echo
|
||||
echo "[ USER:${user_init_script}: executing... ]"
|
||||
sed -i 's/\r$//' "${user_init_script}"
|
||||
source "${user_init_script}"
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
echo "**** Starting supervisord ****";
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf --nodaemon
|
||||
9
overlay/etc/home_directory_template/.bashrc
Normal file
9
overlay/etc/home_directory_template/.bashrc
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# ~/.bashrc
|
||||
#
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
alias ls='ls --color=auto'
|
||||
PS1='[\u@\h \W]\$ '
|
||||
@@ -0,0 +1,14 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Version=0.9.4
|
||||
Type=Application
|
||||
Name=Steam
|
||||
Comment=launch steam on login
|
||||
Exec=/usr/games/steam %U
|
||||
Icon=steam
|
||||
OnlyShowIn=XFCE;
|
||||
RunHook=0
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
Hidden=false
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<channel name="xfce4-desktop" version="1.0">
|
||||
<property name="backdrop" type="empty">
|
||||
<property name="screen0" type="empty">
|
||||
<property name="monitor0" type="empty">
|
||||
<property name="brightness" type="empty"/>
|
||||
<property name="color1" type="empty"/>
|
||||
<property name="color2" type="empty"/>
|
||||
<property name="color-style" type="empty"/>
|
||||
<property name="image-path" type="empty"/>
|
||||
<property name="image-show" type="empty"/>
|
||||
<property name="last-image" type="empty"/>
|
||||
<property name="last-single-image" type="empty"/>
|
||||
</property>
|
||||
<property name="monitor1" type="empty">
|
||||
<property name="brightness" type="empty"/>
|
||||
<property name="color1" type="empty"/>
|
||||
<property name="color2" type="empty"/>
|
||||
<property name="color-style" type="empty"/>
|
||||
<property name="image-path" type="empty"/>
|
||||
<property name="image-show" type="empty"/>
|
||||
<property name="last-image" type="empty"/>
|
||||
<property name="last-single-image" type="empty"/>
|
||||
</property>
|
||||
<property name="monitorDVI-D-0" type="empty">
|
||||
<property name="workspace0" type="empty">
|
||||
<property name="color-style" type="int" value="1"/>
|
||||
<property name="image-style" type="int" value="5"/>
|
||||
<property name="last-image" type="string" value="/usr/share/images/desktop-base/default"/>
|
||||
</property>
|
||||
<property name="workspace1" type="empty">
|
||||
<property name="color-style" type="int" value="1"/>
|
||||
<property name="image-style" type="int" value="5"/>
|
||||
<property name="last-image" type="string" value="/usr/share/images/desktop-base/default"/>
|
||||
</property>
|
||||
<property name="workspace2" type="empty">
|
||||
<property name="color-style" type="int" value="1"/>
|
||||
<property name="image-style" type="int" value="5"/>
|
||||
<property name="last-image" type="string" value="/usr/share/images/desktop-base/default"/>
|
||||
</property>
|
||||
<property name="workspace3" type="empty">
|
||||
<property name="color-style" type="int" value="1"/>
|
||||
<property name="image-style" type="int" value="5"/>
|
||||
<property name="last-image" type="string" value="/usr/share/images/desktop-base/default"/>
|
||||
</property>
|
||||
</property>
|
||||
</property>
|
||||
</property>
|
||||
</channel>
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<channel name="xfce4-panel" version="1.0">
|
||||
<property name="configver" type="int" value="2"/>
|
||||
<property name="panels" type="array">
|
||||
<value type="int" value="1"/>
|
||||
<property name="dark-mode" type="bool" value="true"/>
|
||||
<property name="panel-1" type="empty">
|
||||
<property name="position" type="string" value="p=6;x=0;y=0"/>
|
||||
<property name="length" type="uint" value="100"/>
|
||||
<property name="position-locked" type="bool" value="true"/>
|
||||
<property name="icon-size" type="uint" value="16"/>
|
||||
<property name="size" type="uint" value="26"/>
|
||||
<property name="plugin-ids" type="array">
|
||||
<value type="int" value="1"/>
|
||||
<value type="int" value="2"/>
|
||||
<value type="int" value="3"/>
|
||||
<value type="int" value="4"/>
|
||||
<value type="int" value="5"/>
|
||||
<value type="int" value="6"/>
|
||||
<value type="int" value="8"/>
|
||||
<value type="int" value="10"/>
|
||||
<value type="int" value="11"/>
|
||||
<value type="int" value="12"/>
|
||||
<value type="int" value="13"/>
|
||||
<value type="int" value="14"/>
|
||||
</property>
|
||||
<property name="background-style" type="uint" value="0"/>
|
||||
</property>
|
||||
</property>
|
||||
<property name="plugins" type="empty">
|
||||
<property name="plugin-1" type="string" value="applicationsmenu"/>
|
||||
<property name="plugin-2" type="string" value="tasklist">
|
||||
<property name="grouping" type="uint" value="1"/>
|
||||
</property>
|
||||
<property name="plugin-3" type="string" value="separator">
|
||||
<property name="expand" type="bool" value="true"/>
|
||||
<property name="style" type="uint" value="0"/>
|
||||
</property>
|
||||
<property name="plugin-4" type="string" value="pager"/>
|
||||
<property name="plugin-5" type="string" value="separator">
|
||||
<property name="style" type="uint" value="0"/>
|
||||
</property>
|
||||
<property name="plugin-6" type="string" value="systray">
|
||||
<property name="square-icons" type="bool" value="true"/>
|
||||
</property>
|
||||
<property name="plugin-8" type="string" value="pulseaudio">
|
||||
<property name="enable-keyboard-shortcuts" type="bool" value="true"/>
|
||||
<property name="show-notifications" type="bool" value="true"/>
|
||||
</property>
|
||||
<property name="plugin-9" type="string" value="power-manager-plugin"/>
|
||||
<property name="plugin-10" type="string" value="notification-plugin"/>
|
||||
<property name="plugin-11" type="string" value="separator">
|
||||
<property name="style" type="uint" value="0"/>
|
||||
</property>
|
||||
<property name="plugin-12" type="string" value="clock"/>
|
||||
<property name="plugin-13" type="string" value="separator">
|
||||
<property name="style" type="uint" value="0"/>
|
||||
</property>
|
||||
<property name="plugin-14" type="string" value="actions"/>
|
||||
</property>
|
||||
</channel>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<channel name="xsettings" version="1.0">
|
||||
<property name="Net" type="empty">
|
||||
<property name="ThemeName" type="string" value="Adwaita-dark"/>
|
||||
<property name="IconThemeName" type="string" value="Adwaita"/>
|
||||
<property name="DoubleClickTime" type="empty"/>
|
||||
<property name="DoubleClickDistance" type="empty"/>
|
||||
<property name="DndDragThreshold" type="empty"/>
|
||||
<property name="CursorBlink" type="empty"/>
|
||||
<property name="CursorBlinkTime" type="empty"/>
|
||||
<property name="SoundThemeName" type="empty"/>
|
||||
<property name="EnableEventSounds" type="empty"/>
|
||||
<property name="EnableInputFeedbackSounds" type="empty"/>
|
||||
</property>
|
||||
<property name="Xft" type="empty">
|
||||
<property name="DPI" type="empty"/>
|
||||
<property name="Antialias" type="empty"/>
|
||||
<property name="Hinting" type="empty"/>
|
||||
<property name="HintStyle" type="empty"/>
|
||||
<property name="RGBA" type="empty"/>
|
||||
</property>
|
||||
<property name="Gtk" type="empty">
|
||||
<property name="CanChangeAccels" type="empty"/>
|
||||
<property name="ColorPalette" type="empty"/>
|
||||
<property name="FontName" type="empty"/>
|
||||
<property name="MonospaceFontName" type="empty"/>
|
||||
<property name="IconSizes" type="empty"/>
|
||||
<property name="KeyThemeName" type="empty"/>
|
||||
<property name="ToolbarStyle" type="empty"/>
|
||||
<property name="ToolbarIconSize" type="empty"/>
|
||||
<property name="MenuImages" type="empty"/>
|
||||
<property name="ButtonImages" type="empty"/>
|
||||
<property name="MenuBarAccel" type="empty"/>
|
||||
<property name="CursorThemeName" type="empty"/>
|
||||
<property name="CursorThemeSize" type="empty"/>
|
||||
<property name="DecorationLayout" type="empty"/>
|
||||
<property name="DialogsUseHeader" type="empty"/>
|
||||
<property name="TitlebarMiddleClick" type="empty"/>
|
||||
</property>
|
||||
<property name="Gdk" type="empty">
|
||||
<property name="WindowScalingFactor" type="empty"/>
|
||||
</property>
|
||||
</channel>
|
||||
@@ -0,0 +1,12 @@
|
||||
# Hide application from menu
|
||||
[Desktop Entry]
|
||||
Name=X11VNC Server
|
||||
Comment=Share this desktop by VNC
|
||||
Exec=x11vnc -gui tray=setpass -rfbport PROMPT -bg -o %%HOME/.x11vnc.log.%%VNCDISPLAY
|
||||
Icon=computer
|
||||
Terminal=false
|
||||
Type=Application
|
||||
StartupNotify=false
|
||||
#StartupWMClass=x11vnc_port_prompt
|
||||
Categories=Network;RemoteAccess;
|
||||
Hidden=true
|
||||
130
overlay/etc/supervisor/conf.d/services.conf
Normal file
130
overlay/etc/supervisor/conf.d/services.conf
Normal file
@@ -0,0 +1,130 @@
|
||||
[supervisord]
|
||||
user=root
|
||||
nodaemon=true
|
||||
|
||||
[program:ssh]
|
||||
autostart=true
|
||||
priority=10
|
||||
directory=/
|
||||
command=/usr/sbin/sshd -D
|
||||
user=root
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
|
||||
[program:dbus]
|
||||
autostart=true
|
||||
priority=10
|
||||
directory=/
|
||||
command=dbus-daemon --config-file=/usr/share/dbus-1/system.conf --nofork --nopidfile
|
||||
user=%(ENV_USER)s
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s"
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
|
||||
[program:pulseaudio]
|
||||
autostart=true
|
||||
priority=10
|
||||
directory=/
|
||||
command=/usr/bin/pulseaudio -vvvv --disallow-module-loading --disallow-exit --exit-idle-time=-1
|
||||
user=%(ENV_USER)s
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s"
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/pulseaudio.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/pulseaudio.err
|
||||
|
||||
[program:audiostream]
|
||||
autostart=true
|
||||
priority=10
|
||||
command=tcpserver localhost 5901 gst-launch-1.0 -q pulsesrc server=/tmp/pulseaudio.socket ! audio/x-raw, channels=2, rate=24000 ! cutter ! opusenc ! webmmux ! fdsink fd=1
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/audiostream.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/audiostream.err
|
||||
|
||||
[program:audiowebsock]
|
||||
autostart=true
|
||||
priority=10
|
||||
command=/usr/local/bin/websockify 32123 localhost:5901
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/audiowebsock.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/audiowebsock.err
|
||||
|
||||
[program:xorg]
|
||||
autostart=true
|
||||
priority=20
|
||||
directory=/
|
||||
command=/usr/bin/Xorg vt7 -novtswitch -sharevts -dpi "%(ENV_DISPLAY_DPI)s" +extension "MIT-SHM" %(ENV_DISPLAY)s
|
||||
#command=/usr/bin/Xorg -novtswitch -sharevts -dpi "%(ENV_DISPLAY_DPI)s" +extension "MIT-SHM" "%(ENV_DISPLAY)s"
|
||||
user=%(ENV_USER)s
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s",XDG_RUNTIME_DIR="/tmp/xdg",RUNLEVEL="3"
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/xorg.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/xorg.err
|
||||
|
||||
# Dont use xvfb as it does not work with nvidia X11 configuration
|
||||
# [program:xvfb]
|
||||
# autostart=false
|
||||
# priority=20
|
||||
# directory=/
|
||||
# command=/usr/bin/Xvfb %(ENV_DISPLAY)s -screen 0 1920x1080x24
|
||||
# user=%(ENV_USER)s
|
||||
# environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s"
|
||||
# autorestart=true
|
||||
# stopsignal=QUIT
|
||||
# stdout_logfile=/home/%(ENV_USER)s/.cache/log/xvfb.log
|
||||
# stderr_logfile=/home/%(ENV_USER)s/.cache/log/xvfb.err
|
||||
|
||||
[program:x11vnc]
|
||||
autostart=true
|
||||
priority=30
|
||||
directory=/
|
||||
#command=/usr/bin/x11vnc -display %(ENV_DISPLAY)s -xkb
|
||||
command=/usr/bin/x11vnc -display %(ENV_DISPLAY)s -rfbport 5900 -shared -forever
|
||||
user=%(ENV_USER)s
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/x11vnc.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/x11vnc.err
|
||||
|
||||
[program:de]
|
||||
autostart=true
|
||||
priority=50
|
||||
directory=/home/%(ENV_USER)s
|
||||
command=/usr/bin/startxfce4
|
||||
#command=/usr/bin/mate-session
|
||||
#command=/usr/bin/startlxqt
|
||||
#command=/usr/bin/dbus-launch startxfce4
|
||||
#command=/usr/bin/dbus-launch xfce4-session
|
||||
#command=/usr/bin/dbus-launch startplasma-x11
|
||||
user=%(ENV_USER)s
|
||||
autorestart=true
|
||||
stopsignal=QUIT
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
stdout_logfile=/home/%(ENV_USER)s/.cache/log/de.log
|
||||
stderr_logfile=/home/%(ENV_USER)s/.cache/log/de.err
|
||||
|
||||
## Experimental launch directly to steam big picture... (this is cool, but not ideal for headless)
|
||||
# [program:steam]
|
||||
# autostart=true
|
||||
# priority=50
|
||||
# directory=/home/%(ENV_USER)s
|
||||
# command=/usr/bin/steam -bigpicture
|
||||
# user=%(ENV_USER)s
|
||||
# autorestart=true
|
||||
# stopsignal=QUIT
|
||||
# environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s",DISPLAY="%(ENV_DISPLAY)s"
|
||||
# stdout_logfile=/home/%(ENV_USER)s/.cache/log/steam.log
|
||||
# stderr_logfile=/home/%(ENV_USER)s/.cache/log/steam.err
|
||||
|
||||
[program:novnc]
|
||||
autostart=true
|
||||
priority=100
|
||||
command=/opt/noVNC/utils/launch.sh --vnc localhost:5900 --listen 8083
|
||||
#command=/usr/share/novnc/utils/launch.sh --vnc localhost:5900 --listen 8083
|
||||
#command=/usr/local/bin/websockify -D --web=/usr/share/novnc/ --cert=/etc/ssl/novnc.pem 8083 localhost:5900
|
||||
user=%(ENV_USER)s
|
||||
environment=HOME="/home/%(ENV_USER)s",USER="%(ENV_USER)s"
|
||||
autorestart=true
|
||||
416
overlay/opt/noVNC/audio.patch
Normal file
416
overlay/opt/noVNC/audio.patch
Normal file
@@ -0,0 +1,416 @@
|
||||
diff --git a/app/styles/base.css b/app/styles/base.css
|
||||
index adad415..dfefa6a 100644
|
||||
--- a/app/styles/base.css
|
||||
+++ b/app/styles/base.css
|
||||
@@ -683,7 +683,7 @@ select:active {
|
||||
#noVNC_setting_port {
|
||||
width: 80px;
|
||||
}
|
||||
-#noVNC_setting_path {
|
||||
+#noVNC_setting_path #noVNC_setting_apath {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
diff --git a/app/ui.js b/app/ui.js
|
||||
index cb6a9fd..4d599e1 100644
|
||||
--- a/app/ui.js
|
||||
+++ b/app/ui.js
|
||||
@@ -15,6 +15,7 @@ import KeyTable from "../core/input/keysym.js";
|
||||
import keysyms from "../core/input/keysymdef.js";
|
||||
import Keyboard from "../core/input/keyboard.js";
|
||||
import RFB from "../core/rfb.js";
|
||||
+import WebAudio from "../core/webaudio.js";
|
||||
import * as WebUtil from "./webutil.js";
|
||||
|
||||
const PAGE_TITLE = "noVNC";
|
||||
@@ -40,6 +41,7 @@ const UI = {
|
||||
inhibitReconnect: true,
|
||||
reconnectCallback: null,
|
||||
reconnectPassword: null,
|
||||
+ webaudio: null,
|
||||
|
||||
prime() {
|
||||
return WebUtil.initSettings().then(() => {
|
||||
@@ -171,6 +173,7 @@ const UI = {
|
||||
UI.initSetting('compression', 2);
|
||||
UI.initSetting('shared', true);
|
||||
UI.initSetting('view_only', false);
|
||||
+ UI.initSetting('audio', true);
|
||||
UI.initSetting('show_dot', false);
|
||||
UI.initSetting('path', 'websockify');
|
||||
UI.initSetting('repeaterID', '');
|
||||
@@ -200,6 +203,20 @@ const UI = {
|
||||
}
|
||||
},
|
||||
|
||||
+ toggleAudio() {
|
||||
+ console.log('here');
|
||||
+ const audio = UI.getSetting('audio');
|
||||
+ if (audio) {
|
||||
+ UI.webaudio.start();
|
||||
+ } else {
|
||||
+ if(UI.webaudio !== null) {
|
||||
+ if (UI.webaudio.connected) {
|
||||
+ UI.webaudio.stop();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ },
|
||||
+
|
||||
/* ------^-------
|
||||
* /INIT
|
||||
* ==============
|
||||
@@ -356,6 +373,8 @@ const UI = {
|
||||
UI.addSettingChangeHandler('shared');
|
||||
UI.addSettingChangeHandler('view_only');
|
||||
UI.addSettingChangeHandler('view_only', UI.updateViewOnly);
|
||||
+ UI.addSettingChangeHandler('audio');
|
||||
+ UI.addSettingChangeHandler('audio', UI.updateEnableAudio);
|
||||
UI.addSettingChangeHandler('show_dot');
|
||||
UI.addSettingChangeHandler('show_dot', UI.updateShowDotCursor);
|
||||
UI.addSettingChangeHandler('host');
|
||||
@@ -841,6 +860,7 @@ const UI = {
|
||||
UI.updateSetting('compression');
|
||||
UI.updateSetting('shared');
|
||||
UI.updateSetting('view_only');
|
||||
+ UI.updateSetting('audio');
|
||||
UI.updateSetting('path');
|
||||
UI.updateSetting('repeaterID');
|
||||
UI.updateSetting('logging');
|
||||
@@ -1041,6 +1061,7 @@ const UI = {
|
||||
UI.rfb.resizeSession = UI.getSetting('resize') === 'remote';
|
||||
UI.rfb.qualityLevel = parseInt(UI.getSetting('quality'));
|
||||
UI.rfb.compressionLevel = parseInt(UI.getSetting('compression'));
|
||||
+ UI.rfb.enableAudio = UI.getSetting('audio');
|
||||
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
||||
|
||||
UI.updateViewOnly(); // requires UI.rfb
|
||||
@@ -1056,6 +1077,10 @@ const UI = {
|
||||
|
||||
UI.updateVisualState('disconnecting');
|
||||
|
||||
+ if(UI.webaudio !== null && UI.webaudio.socket !== null) {
|
||||
+ UI.webaudio.socket.close();
|
||||
+ }
|
||||
+
|
||||
// Don't display the connection settings until we're actually disconnected
|
||||
},
|
||||
|
||||
@@ -1097,6 +1122,19 @@ const UI = {
|
||||
|
||||
// Do this last because it can only be used on rendered elements
|
||||
UI.rfb.focus();
|
||||
+
|
||||
+ let audio_url;
|
||||
+ let host = window.location.hostname;
|
||||
+ let port = 32123;
|
||||
+ if (window.location.protocol === "https:") {
|
||||
+ audio_url = 'wss';
|
||||
+ } else {
|
||||
+ audio_url = 'ws';
|
||||
+ }
|
||||
+ audio_url += '://' + host + ':' + port;
|
||||
+
|
||||
+ UI.webaudio = new WebAudio(audio_url);
|
||||
+ UI.toggleAudio();
|
||||
},
|
||||
|
||||
disconnectFinished(e) {
|
||||
@@ -1647,6 +1685,12 @@ const UI = {
|
||||
}
|
||||
},
|
||||
|
||||
+ updateEnableAudio() {
|
||||
+ if (!UI.rfb) return;
|
||||
+ UI.rfb.enableAudio = UI.getSetting('audio');
|
||||
+ UI.toggleAudio();
|
||||
+ },
|
||||
+
|
||||
updateShowDotCursor() {
|
||||
if (!UI.rfb) return;
|
||||
UI.rfb.showDotCursor = UI.getSetting('show_dot');
|
||||
diff --git a/core/webaudio.js b/core/webaudio.js
|
||||
new file mode 100644
|
||||
index 0000000..28c71ac
|
||||
--- /dev/null
|
||||
+++ b/core/webaudio.js
|
||||
@@ -0,0 +1,142 @@
|
||||
+export default class WebAudio {
|
||||
+ constructor(url) {
|
||||
+ this.url = url
|
||||
+
|
||||
+ this.connected = false;
|
||||
+
|
||||
+ //constants for audio behavoir
|
||||
+ this.maximumAudioLag = 1.5; //amount of seconds we can potentially be behind the server audio stream
|
||||
+ this.syncLagInterval = 5000; //check every x milliseconds if we are behind the server audio stream
|
||||
+ this.updateBufferEvery = 20; //add recieved data to the player buffer every x milliseconds
|
||||
+ this.reduceBufferInterval = 500; //trim the output audio stream buffer every x milliseconds so we don't overflow
|
||||
+ this.maximumSecondsOfBuffering = 1; //maximum amount of data to store in the play buffer
|
||||
+ this.connectionCheckInterval = 500; //check the connection every x milliseconds
|
||||
+
|
||||
+ //register all our background timers. these need to be created only once - and will run independent of the object's streams/properties
|
||||
+ this.updateCheck = null;
|
||||
+ this.syncCheck = null;
|
||||
+ this.reduceCheck = null;
|
||||
+ this.ConnCheck = null;
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ //registers all the event handlers for when this stream is closed - or when data arrives.
|
||||
+ registerHandlers() {
|
||||
+ this.mediaSource.addEventListener('sourceended', e => this.socketDisconnected(e))
|
||||
+ this.mediaSource.addEventListener('sourceclose', e => this.socketDisconnected(e))
|
||||
+ this.mediaSource.addEventListener('error', e => this.socketDisconnected(e))
|
||||
+ this.buffer.addEventListener('error', e => this.socketDisconnected(e))
|
||||
+ this.buffer.addEventListener('abort', e => this.socketDisconnected(e))
|
||||
+ }
|
||||
+
|
||||
+ //starts the web audio stream. only call this method on button click.
|
||||
+ start() {
|
||||
+ if (!!this.connected) return;
|
||||
+ if (!!this.audio) this.audio.remove();
|
||||
+ this.queue = null;
|
||||
+
|
||||
+ if (this.updateCheck === null) this.updateCheck = setInterval(() => this.updateQueue(), this.updateBufferEvery);
|
||||
+ if (this.syncCheck === null) this.syncCheck = setInterval(() => this.syncInterval(), this.syncLagInterval);
|
||||
+ if (this.reduceCheck === null) this.reduceCheck = setInterval(() => this.reduceBuffer(), this.reduceBufferInterval);
|
||||
+ if (this.ConnCheck === null) this.ConnCheck = setInterval(() => this.tryLastPacket(), this.connectionCheckInterval);
|
||||
+
|
||||
+ this.mediaSource = new MediaSource()
|
||||
+ this.mediaSource.addEventListener('sourceopen', e => this.onSourceOpen())
|
||||
+ //first we need a media source - and an audio object that contains it.
|
||||
+ this.audio = document.createElement('audio');
|
||||
+ this.audio.src = window.URL.createObjectURL(this.mediaSource);
|
||||
+
|
||||
+ //start our stream - we can only do this on user input
|
||||
+ this.audio.play();
|
||||
+ }
|
||||
+
|
||||
+ stop() {
|
||||
+ // Clear all interval timers
|
||||
+ clearInterval(this.updateCheck);
|
||||
+ clearInterval(this.syncCheck);
|
||||
+ clearInterval(this.reduceCheck);
|
||||
+ clearInterval(this.ConnCheck);
|
||||
+ // Close the socket
|
||||
+ this.socket.close();
|
||||
+ this.connected = false;
|
||||
+ // Reset timers to null
|
||||
+ this.updateCheck = null;
|
||||
+ this.syncCheck = null;
|
||||
+ this.reduceCheck = null;
|
||||
+ this.ConnCheck = null;
|
||||
+ }
|
||||
+
|
||||
+ wsConnect() {
|
||||
+ if (!!this.socket) this.socket.close();
|
||||
+
|
||||
+ this.socket = new WebSocket(this.url, ['binary', 'base64'])
|
||||
+ this.socket.binaryType = 'arraybuffer'
|
||||
+ this.socket.addEventListener('message', e => this.websocketDataArrived(e), false);
|
||||
+ }
|
||||
+
|
||||
+ //this is called when the media source contains data
|
||||
+ onSourceOpen(e) {
|
||||
+ this.buffer = this.mediaSource.addSourceBuffer('audio/webm; codecs="opus"')
|
||||
+ this.registerHandlers();
|
||||
+ this.wsConnect();
|
||||
+ }
|
||||
+
|
||||
+ //whenever data arrives in our websocket this is called.
|
||||
+ websocketDataArrived(e) {
|
||||
+ this.lastPacket = Date.now();
|
||||
+ this.connected = true;
|
||||
+ this.queue = this.queue == null ? e.data : this.concat(this.queue, e.data);
|
||||
+ }
|
||||
+
|
||||
+ //whenever a disconnect happens this is called.
|
||||
+ socketDisconnected(e) {
|
||||
+ console.log(e);
|
||||
+ this.connected = false;
|
||||
+ }
|
||||
+
|
||||
+ tryLastPacket() {
|
||||
+ if (this.lastPacket == null) return;
|
||||
+ if ((Date.now() - this.lastPacket) > 1000) {
|
||||
+ this.socketDisconnected('timeout');
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ //this updates the buffer with the data from our queue
|
||||
+ updateQueue() {
|
||||
+ if (!(!!this.queue && !!this.buffer && !this.buffer.updating)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ this.buffer.appendBuffer(this.queue);
|
||||
+ this.queue = null;
|
||||
+ }
|
||||
+
|
||||
+ //reduces the stream buffer to the minimal size that we need for streaming
|
||||
+ reduceBuffer() {
|
||||
+ if (!(this.buffer && !this.buffer.updating && !!this.audio && !!this.audio.currentTime && this.audio.currentTime > 1)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ this.buffer.remove(0, this.audio.currentTime - 1);
|
||||
+ }
|
||||
+
|
||||
+ //synchronizes the current time of the stream with the server
|
||||
+ syncInterval() {
|
||||
+ if (!(this.audio && this.audio.currentTime && this.audio.currentTime > 1 && this.buffer && this.buffer.buffered && this.buffer.buffered.length > 1)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ var currentTime = this.audio.currentTime;
|
||||
+ var targetTime = this.buffer.buffered.end(this.buffer.buffered.length - 1);
|
||||
+
|
||||
+ if (targetTime > (currentTime + this.maximumAudioLag)) this.audio.fastSeek(targetTime);
|
||||
+ }
|
||||
+
|
||||
+ //joins two data arrays - helper function
|
||||
+ concat(buffer1, buffer2) {
|
||||
+ var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
|
||||
+ tmp.set(new Uint8Array(buffer1), 0);
|
||||
+ tmp.set(new Uint8Array(buffer2), buffer1.byteLength);
|
||||
+ return tmp.buffer;
|
||||
+ };
|
||||
+}
|
||||
diff --git a/vnc.html b/vnc.html
|
||||
index c678c2a..d1652a0 100644
|
||||
--- a/vnc.html
|
||||
+++ b/vnc.html
|
||||
@@ -170,6 +170,10 @@
|
||||
<label><input id="noVNC_setting_view_only" type="checkbox"> View Only</label>
|
||||
</li>
|
||||
<li><hr></li>
|
||||
+ <li>
|
||||
+ <label><input id="noVNC_setting_audio" type="checkbox"> Enable Audio</label>
|
||||
+ </li>
|
||||
+ <li><hr></li>
|
||||
<li>
|
||||
<label><input id="noVNC_setting_view_clip" type="checkbox"> Clip to Window</label>
|
||||
</li>
|
||||
diff --git a/vnc_lite.html b/vnc_lite.html
|
||||
index 8e2f5cb..d3cf6ab 100644
|
||||
--- a/vnc_lite.html
|
||||
+++ b/vnc_lite.html
|
||||
@@ -41,6 +41,15 @@
|
||||
#status {
|
||||
text-align: center;
|
||||
}
|
||||
+ #toggleAudioButton {
|
||||
+ position: fixed;
|
||||
+ top: 0px;
|
||||
+ left: 0px;
|
||||
+ border: 1px outset;
|
||||
+ padding: 5px 5px 4px 5px;
|
||||
+ cursor: pointer;
|
||||
+ display: none;
|
||||
+ }
|
||||
#sendCtrlAltDelButton {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
@@ -60,18 +69,38 @@
|
||||
<script type="module" crossorigin="anonymous">
|
||||
// RFB holds the API to connect and communicate with a VNC server
|
||||
import RFB from './core/rfb.js';
|
||||
+ import WebAudio from './core/webaudio.js';
|
||||
|
||||
let rfb;
|
||||
let desktopName;
|
||||
+ let wa;
|
||||
|
||||
// When this function is called we have
|
||||
// successfully connected to a server
|
||||
function connectedToServer(e) {
|
||||
+ let audio_url;
|
||||
+ let host = window.location.hostname;
|
||||
+ let port = 32123;
|
||||
+ if (window.location.protocol === "https:") {
|
||||
+ audio_url = 'wss';
|
||||
+ } else {
|
||||
+ audio_url = 'ws';
|
||||
+ }
|
||||
+ audio_url += '://' + host + ':' + port;
|
||||
+
|
||||
+ wa = new WebAudio(audio_url);
|
||||
+ document.getElementById('toggleAudioButton').style.display = "block";
|
||||
+
|
||||
status("Connected to " + desktopName);
|
||||
}
|
||||
|
||||
// This function is called when we are disconnected
|
||||
function disconnectedFromServer(e) {
|
||||
+ if(wa !== null) {
|
||||
+ wa.stop();
|
||||
+ wa = null;
|
||||
+ document.getElementById('toggleAudioButton').style.display = "none";
|
||||
+ }
|
||||
if (e.detail.clean) {
|
||||
status("Disconnected");
|
||||
} else {
|
||||
@@ -100,6 +129,19 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // Enable the audio websocket
|
||||
+ function toggleAudio() {
|
||||
+ if (wa.connected) {
|
||||
+ console.log('Stopping audio...')
|
||||
+ wa.stop();
|
||||
+ document.getElementById('toggleAudioButton').innerText = "Enable Audio (requires access to port 32123)";
|
||||
+ } else {
|
||||
+ console.log('Starting audio websocket on: ' + audio_url)
|
||||
+ wa.start();
|
||||
+ document.getElementById('toggleAudioButton').innerText = "Disable Audio";
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// Show a status text in the top bar
|
||||
function status(text) {
|
||||
document.getElementById('status').textContent = text;
|
||||
@@ -135,12 +177,16 @@
|
||||
document.getElementById('sendCtrlAltDelButton')
|
||||
.onclick = sendCtrlAltDel;
|
||||
|
||||
+ document.getElementById('toggleAudioButton')
|
||||
+ .onclick = toggleAudio;
|
||||
+
|
||||
// Read parameters specified in the URL query string
|
||||
// By default, use the host and port of server that served this file
|
||||
const host = readQueryVariable('host', window.location.hostname);
|
||||
let port = readQueryVariable('port', window.location.port);
|
||||
const password = readQueryVariable('password');
|
||||
const path = readQueryVariable('path', 'websockify');
|
||||
+ const audio_path = readQueryVariable('audio_path', '');
|
||||
|
||||
// | | | | | |
|
||||
// | | | Connect | | |
|
||||
@@ -150,6 +196,7 @@
|
||||
|
||||
// Build the websocket URL used to connect
|
||||
let url;
|
||||
+ let audio_url;
|
||||
if (window.location.protocol === "https:") {
|
||||
url = 'wss';
|
||||
} else {
|
||||
@@ -159,6 +206,9 @@
|
||||
if(port) {
|
||||
url += ':' + port;
|
||||
}
|
||||
+ if(audio_path !== '') {
|
||||
+ audio_url = url + '/' + audio_path;
|
||||
+ }
|
||||
url += '/' + path;
|
||||
|
||||
// Creating a new RFB object will start a new connection
|
||||
@@ -179,6 +229,7 @@
|
||||
|
||||
<body>
|
||||
<div id="top_bar">
|
||||
+ <div id="toggleAudioButton">Enable Audio (requires access to port 32123)</div>
|
||||
<div id="status">Loading</div>
|
||||
<div id="sendCtrlAltDelButton">Send CtrlAltDel</div>
|
||||
</div>
|
||||
31
overlay/scripts/10-setup_user.sh
Normal file
31
overlay/scripts/10-setup_user.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
PUID=${PUID:-99}
|
||||
PGID=${PGID:-100}
|
||||
UMASK=${UMASK:-000}
|
||||
USER_PASSWORD=${USER_PASSWORD:-password}
|
||||
|
||||
echo "**** Configure default user ****"
|
||||
|
||||
echo "Setting run user uid=${PGID}(${USER}) gid=${PUID}(${USER})"
|
||||
groupmod -o -g "${PGID}" ${USER}
|
||||
usermod -o -u "${PUID}" ${USER}
|
||||
|
||||
|
||||
echo "Setting umask to ${UMASK}";
|
||||
umask ${UMASK}
|
||||
|
||||
|
||||
# Setup home directory and permissions
|
||||
echo "Adding default home directory template"
|
||||
mkdir -p ${USER_HOME}
|
||||
chown -R ${PUID}:${PGID} /etc/home_directory_template
|
||||
rsync -aq /etc/home_directory_template/ ${USER_HOME}/
|
||||
|
||||
|
||||
# Set the root and user password
|
||||
echo "Setting root password"
|
||||
echo "root:${USER_PASSWORD}" | chpasswd
|
||||
echo "Setting user password"
|
||||
echo "${USER}:${USER_PASSWORD}" | chpasswd
|
||||
|
||||
echo "DONE"
|
||||
10
overlay/scripts/20-configre_sshd.sh
Normal file
10
overlay/scripts/20-configre_sshd.sh
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
# Generate new SSH host keys if they dont exist
|
||||
if [[ ! -f /etc/ssh/ssh_host_rsa_key ]]; then
|
||||
echo "**** Generating SSH keys ****";
|
||||
/usr/bin/ssh-keygen -A
|
||||
fi
|
||||
mkdir -p /run/sshd
|
||||
chmod 744 /run/sshd
|
||||
|
||||
echo "DONE"
|
||||
32
overlay/scripts/30-configure_system_paths.sh
Normal file
32
overlay/scripts/30-configure_system_paths.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
# Configure system paths
|
||||
echo "**** Configure system paths ****";
|
||||
sed -i "/ <user>/c\ <user>${USER}</user>" /usr/share/dbus-1/system.conf
|
||||
if [ ! -d /tmp/xdg ]; then
|
||||
mkdir -p /tmp/xdg
|
||||
fi
|
||||
|
||||
echo "Configure dbus";
|
||||
# Remove old dbus session
|
||||
rm -rf ${USER_HOME}/.dbus/session-bus/* 2> /dev/null
|
||||
# Remove old dbus pids
|
||||
mkdir -p /var/run/dbus
|
||||
chown -R ${PUID}:${PGID} /var/run/dbus/
|
||||
chmod -R 770 /var/run/dbus/
|
||||
# Generate a dbus machine ID
|
||||
dbus-uuidgen > /var/lib/dbus/machine-id
|
||||
|
||||
echo "Configure X Windows context"
|
||||
chown -R ${PUID}:${PGID} /tmp/xdg
|
||||
chmod -R 0700 /tmp/xdg
|
||||
|
||||
echo "Configure X Windows session"
|
||||
rm -rfv /tmp/.ICE-unix*
|
||||
mkdir -p /tmp/.ICE-unix
|
||||
chown root:root /tmp/.ICE-unix/
|
||||
chmod 1777 /tmp/.ICE-unix/
|
||||
|
||||
echo "Remove old lockfiles"
|
||||
find /var/run/dbus -name "pid" -exec rm -f {} \;
|
||||
find /tmp -name ".X99*" -exec rm -f {} \;
|
||||
|
||||
echo "DONE"
|
||||
19
overlay/scripts/40-setup_locale.sh
Normal file
19
overlay/scripts/40-setup_locale.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
current_local=$(head -n 1 /etc/locale.gen)
|
||||
user_local=$(echo ${USER_LOCALES} | cut -d ' ' -f 1)
|
||||
|
||||
if [ "${current_local}" != "${USER_LOCALES}" ]; then
|
||||
echo "**** Configuring Locales to ${USER_LOCALES} ****";
|
||||
rm /etc/locale.gen
|
||||
echo -e "${USER_LOCALES}\nen_US.UTF-8 UTF-8" > "/etc/locale.gen"
|
||||
export LANGUAGE="${user_local}"
|
||||
export LANG="${user_local}"
|
||||
export LC_ALL="${user_local}" 2> /dev/null
|
||||
sleep 2
|
||||
locale-gen
|
||||
update-locale LC_ALL="${user_local}"
|
||||
else
|
||||
echo "**** Locales already set correctly to ${USER_LOCALES} ****";
|
||||
fi
|
||||
|
||||
echo "DONE"
|
||||
20
overlay/scripts/50-configure_audio.sh
Normal file
20
overlay/scripts/50-configure_audio.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
echo "**** Configure pulseaudio socket ****"
|
||||
sed -i 's|^; default-server.*$|default-server = unix:/tmp/pulseaudio.socket|' /etc/pulse/client.conf
|
||||
sed -i 's|^load-module module-native-protocol-unix.*$|load-module module-native-protocol-unix socket=/tmp/pulseaudio.socket auth-anonymous=1|' \
|
||||
/etc/pulse/default.pa
|
||||
chown -R ${USER} /etc/pulse
|
||||
|
||||
# Credits for this audio patch:
|
||||
# - https://github.com/novnc/noVNC/issues/302
|
||||
# - https://github.com/vexingcodes/dwarf-fortress-docker
|
||||
# - https://github.com/calebj/noVNC
|
||||
if [ -f /opt/noVNC/audio.patch ]; then
|
||||
echo "**** Patching noVNC with audio websocket ****"
|
||||
pushd /opt/noVNC/ &> /dev/null
|
||||
patch -p1 --input=/opt/noVNC/audio.patch --batch --quiet
|
||||
popd &> /dev/null
|
||||
rm /opt/noVNC/audio.patch
|
||||
fi
|
||||
|
||||
echo "DONE"
|
||||
64
overlay/scripts/80-configure_nvidia_driver.sh
Normal file
64
overlay/scripts/80-configure_nvidia_driver.sh
Normal file
@@ -0,0 +1,64 @@
|
||||
|
||||
# Fech NVIDIA GPU device (if one exists)
|
||||
if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
elif [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
else
|
||||
export gpu_select=$(nvidia-smi --format=csv --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid | sed -n 2p)
|
||||
if [ -z "$gpu_select" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
fi
|
||||
fi
|
||||
|
||||
export nvidia_pci_address="$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select}" 2> /dev/null | sed -n 2p | cut -d ':' -f2,3)"
|
||||
export nvidia_gpu_name=$(nvidia-smi --format=csv --query-gpu=name --id="${gpu_select}" | sed -n 2p 2> /dev/null)
|
||||
export nvidia_host_driver_version="$(nvidia-smi 2> /dev/null | grep NVIDIA-SMI | cut -d ' ' -f3)"
|
||||
|
||||
function download_driver {
|
||||
mkdir -p ${USER_HOME}/.cache/nvidia
|
||||
|
||||
if [[ ! -f "${USER_HOME}/.cache/nvidia/NVIDIA_${nvidia_host_driver_version}.run" ]]; then
|
||||
echo "Downloading driver"
|
||||
wget -q --show-progress --progress=bar:force:noscroll \
|
||||
-O /tmp/NVIDIA.run \
|
||||
http://download.nvidia.com/XFree86/Linux-x86_64/${nvidia_host_driver_version}/NVIDIA-Linux-x86_64-${nvidia_host_driver_version}.run
|
||||
[[ $? -gt 0 ]] && echo "Error downloading driver. Exit!" && return 1
|
||||
|
||||
mv /tmp/NVIDIA.run ${USER_HOME}/.cache/nvidia/NVIDIA_${nvidia_host_driver_version}.run
|
||||
fi
|
||||
}
|
||||
|
||||
function install_driver {
|
||||
# Check here if the currently installed version matches using nvidia-settings
|
||||
nvidia_settings_version=$(nvidia-settings --version 2> /dev/null | grep version | cut -d ' ' -f 4)
|
||||
[[ "${nvidia_settings_version}x" == "${nvidia_host_driver_version}x" ]] && return 0
|
||||
|
||||
# Download the driver (if it does not yet exist locally)
|
||||
download_driver
|
||||
|
||||
echo "Installing driver"
|
||||
chmod +x ${USER_HOME}/.cache/nvidia/NVIDIA_${nvidia_host_driver_version}.run
|
||||
${USER_HOME}/.cache/nvidia/NVIDIA_${nvidia_host_driver_version}.run \
|
||||
--silent \
|
||||
--accept-license \
|
||||
--no-kernel-module \
|
||||
--install-compat32-libs \
|
||||
--no-nouveau-check \
|
||||
--no-nvidia-modprobe \
|
||||
--no-rpms \
|
||||
--no-backup \
|
||||
--no-check-for-alternate-installs \
|
||||
--no-libglx-indirect \
|
||||
--no-install-libglvnd \
|
||||
> ${USER_HOME}/.cache/nvidia/last_install.log 2>&1
|
||||
}
|
||||
|
||||
if [[ -z ${nvidia_pci_address} ]]; then
|
||||
echo "**** No NVIDIA device found ****";
|
||||
else
|
||||
echo "**** Found NVIDIA device '${nvidia_gpu_name}' ****";
|
||||
install_driver
|
||||
fi
|
||||
|
||||
echo "DONE"
|
||||
57
overlay/scripts/90-configure_xorg.sh
Normal file
57
overlay/scripts/90-configure_xorg.sh
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
# Fech NVIDIA GPU device (if one exists)
|
||||
if [ "$NVIDIA_VISIBLE_DEVICES" == "all" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
elif [ -z "$NVIDIA_VISIBLE_DEVICES" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
else
|
||||
export gpu_select=$(nvidia-smi --format=csv --id=$(echo "$NVIDIA_VISIBLE_DEVICES" | cut -d ',' -f1) --query-gpu=uuid | sed -n 2p)
|
||||
if [ -z "$gpu_select" ]; then
|
||||
export gpu_select=$(nvidia-smi --format=csv --query-gpu=uuid 2> /dev/null | sed -n 2p)
|
||||
fi
|
||||
fi
|
||||
|
||||
export nvidia_gpu_hex_id=$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select}" 2> /dev/null | sed -n 2p)
|
||||
|
||||
# Fech current configuration (if modified in UI)
|
||||
if [ -f "${USER_HOME}/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml" ]; then
|
||||
new_display_sizew=$(cat ${USER_HOME}/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml | grep Resolution | head -n1 | grep -oP '(?<=value=").*?(?=")' | cut -d'x' -f1)
|
||||
new_display_sizeh=$(cat ${USER_HOME}/.config/xfce4/xfconf/xfce-perchannel-xml/displays.xml | grep Resolution | head -n1 | grep -oP '(?<=value=").*?(?=")' | cut -d'x' -f2)
|
||||
if [ "${new_display_sizew}x" != "x" ] && [ "${new_display_sizeh}x" != "x" ]; then
|
||||
export DISPLAY_SIZEW="${new_display_sizew}"
|
||||
export DISPLAY_SIZEH="${new_display_sizeh}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Configure a NVIDIA X11 config
|
||||
function configure_nvidia_x_server {
|
||||
# Configure x to be run by anyone
|
||||
if grep -Fxq "allowed_users=console" /etc/X11/Xwrapper.config; then
|
||||
echo "Configure Xwrapper.config"
|
||||
sed -i "s/allowed_users=console/allowed_users=anybody/" /etc/X11/Xwrapper.config
|
||||
fi
|
||||
|
||||
# Configure xorg for NVIDIA
|
||||
echo "Configuring X11 with GPU ID: '${gpu_select}'"
|
||||
nvidia_gpu_hex_id=$(nvidia-smi --format=csv --query-gpu=pci.bus_id --id="${gpu_select}" 2> /dev/null | sed -n 2p)
|
||||
IFS=":." ARR_ID=(${nvidia_gpu_hex_id})
|
||||
unset IFS
|
||||
bus_id=PCI:$((16#${ARR_ID[1]})):$((16#${ARR_ID[2]})):$((16#${ARR_ID[3]}))
|
||||
echo "Configuring X11 with PCI bus ID: '${bus_id}'"
|
||||
export MODELINE=$(cvt -r "${DISPLAY_SIZEW}" "${DISPLAY_SIZEH}" "${DISPLAY_REFRESH}" | sed -n 2p)
|
||||
echo "Writing X11 config with ${MODELINE}"
|
||||
nvidia-xconfig --virtual="${DISPLAY_SIZEW}x${DISPLAY_SIZEH}" --depth="${DISPLAY_CDEPTH}" --mode=$(echo "${MODELINE}" | awk '{print $2}' | tr -d '"') --allow-empty-initial-configuration --no-probe-all-gpus --busid="${bus_id}" --only-one-x-screen --connected-monitor="${DISPLAY_VIDEO_PORT}"
|
||||
sed -i '/Driver\s\+"nvidia"/a\ Option "ModeValidation" "NoMaxPClkCheck, NoEdidMaxPClkCheck, NoMaxSizeCheck, NoHorizSyncCheck, NoVertRefreshCheck, NoVirtualSizeCheck, NoExtendedGpuCapabilitiesCheck, NoTotalSizeCheck, NoDualLinkDVICheck, NoDisplayPortBandwidthCheck, AllowNon3DVisionModes, AllowNonHDMI3DModes, AllowNonEdidModes, NoEdidHDMI2Check, AllowDpInterlaced"' /etc/X11/xorg.conf
|
||||
sed -i '/Section\s\+"Monitor"/a\ '"${MODELINE}" /etc/X11/xorg.conf
|
||||
}
|
||||
|
||||
|
||||
if [[ -z ${nvidia_gpu_hex_id} ]]; then
|
||||
echo "**** Generate default xorg.conf ****";
|
||||
# TODO: Configure xorg.conf with no NVIDIA GPU
|
||||
else
|
||||
echo "**** Generate NVIDIA xorg.conf ****";
|
||||
configure_nvidia_x_server
|
||||
fi
|
||||
|
||||
echo "DONE"
|
||||
Reference in New Issue
Block a user