From 7eec77875ee199eabad5c76eb7244860545d0590 Mon Sep 17 00:00:00 2001
From: Peter Gerwinski <peter.gerwinski@hs-bochum.de>
Date: Mon, 4 Jan 2021 17:34:38 +0100
Subject: [PATCH] configurable style for PULT buttons, communicate with
 CVH-Camera server via FIFOs rather than TCP/IP

---
 etc/pult/pult-1.conf                | 15 ++++++++--
 etc/pult/pult-2.conf                | 33 +++++++++++-----------
 etc/pult/pult-3.conf                | 35 ++++++++++++-----------
 etc/pult/pult-6.conf                | 14 ++-------
 lib/pult/cvh-camera.daemon          |  9 +++---
 lib/pult/cvh-camera.module          | 17 ++++++-----
 pult-install                        |  1 +
 sbin/cvh-camera                     | 15 +++++-----
 www/cgi-bin/pult.cgi                | 12 ++++----
 www/cvh-camera/camera-sender.html   | 44 ++++++++++++++++++-----------
 www/cvh-camera/camera-sender.js.in  | 26 ++++++++++++-----
 www/novnc/app/camera-receiver.js.in |  9 ++++--
 12 files changed, 131 insertions(+), 99 deletions(-)

diff --git a/etc/pult/pult-1.conf b/etc/pult/pult-1.conf
index 5736134..7f7f6ee 100644
--- a/etc/pult/pult-1.conf
+++ b/etc/pult/pult-1.conf
@@ -1,6 +1,17 @@
-bbb_url="https://bbb.cvh-server.de/b/pet-jxk-dch" 
+start_style="background-color: blue; color: white;"
+stop_style="background-color: red; color: black;"
+hide_style="margin-left: 2em; background-color: orange; color: black;"
+show_style="background-color: green; color: white;"
+min_style="background-color: yellow; color: black;"
+max_style="background-color: green; color: white;"
+
+#bbb_url="https://bbb.cvh-server.de/b/pet-jxk-dch" 
+bbb_url="https://bbb.cvh-server.de/b/pro-jmv-d5q-j9x"
 bbb_invitation="follow <a target="_blank" href=\"$bbb_url\">link</a> to $bbb_url"
+janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1001&pin=hsSS2020&slot=0&token=@INFO@"
+janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
 
 module vnc vnc port=5521 autostart nobuttons
 #module vnc-gast vnc invitation="connect to streaming.cvh-server.de:1"
-module bbb bbb-camera module_name="" url="$bbb_url" invitation="$bbb_invitation"
+#module bbb bbb-camera module_name="Camera" url="$bbb_url" invitation="$bbb_invitation"
+module janus cvh-camera module_name="Camera" browser="false" direct="true" slot="0" persistent_invitation="$janus_invitation"
diff --git a/etc/pult/pult-2.conf b/etc/pult/pult-2.conf
index f1498e4..c8cbbd0 100644
--- a/etc/pult/pult-2.conf
+++ b/etc/pult/pult-2.conf
@@ -1,20 +1,18 @@
-#start_text="starten"
-#stop_text="stoppen"
-#hide_text="verbergen"
-#show_text="zeigen"
-#min_text="minimieren"
-#max_text="maximieren"
-
 bbb_url="https://bbb.cvh-server.de/b/pet-jxk-dch" 
 bbb_invitation="follow <a target=\"_blank\" href=\"$bbb_url\">this link</a> to $bbb_url"
 jm_url="https://meet.cvh-server.de/VNC2" 
 jm_invitation="follow <a target=\"_blank\" href=\"$jm_url\">this link</a> to $jm_url"
-janus_receiver_url="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1002"
-janus_receiver_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1005"
-janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1002"
-janus_sender_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1005"
-janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
-janus_invitation_redundant="follow <a target=\"_blank\" href=\"$janus_sender_url_redundant\">this link</a> to $janus_sender_url_redundant"
+#janus_receiver_url="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1002"
+#janus_receiver_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1005"
+#janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1002"
+janus_sender_url_1="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1002&pin=testcvh&slot=0&token=@INFO@"
+janus_sender_url_2="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1002&pin=testcvh&slot=1&token=@INFO@"
+janus_sender_url_3="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1002&pin=testcvh&slot=2&token=@INFO@"
+#janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
+#janus_invitation_redundant="follow <a target=\"_blank\" href=\"$janus_sender_url_redundant\">this link</a> to $janus_sender_url_redundant"
+janus_invitation_1="follow <a target=\"_blank\" href=\"$janus_sender_url_1\">this link</a> to $janus_sender_url_1"
+janus_invitation_2="follow <a target=\"_blank\" href=\"$janus_sender_url_2\">this link</a> to $janus_sender_url_2"
+janus_invitation_3="follow <a target=\"_blank\" href=\"$janus_sender_url_3\">this link</a> to $janus_sender_url_3"
 om_url="https://openmeetings.cvh-server.de:5443/openmeetings/#room/24"
 om_invitation="follow <a target=\"_blank\" href=\"$om_url\">this link</a> to $om_url"
 upload_sender_url="https://streaming.cvh-server.de/cgi-bin/pult-upload-2.cgi"
@@ -25,9 +23,12 @@ module vnc-gast vnc module_name="VNC Gast" invitation="connect to streaming.cvh-
 module bbb bbb-camera module_name="BBB-Kamera" url="$bbb_url" invitation="$bbb_invitation"
 module jm jm-camera module_name="JM-Kamera" url="$jm_url" invitation="$jm_invitation"
 camera_default_max_resolution="1024x768"
-module janus cvh-camera module_name="CVH-Kamera 2" url="$janus_receiver_url" persistent_invitation="$janus_invitation"
-module janus-r cvh-camera module_name="CVH-Kamera 5" camera_room="1005" url="$janus_receiver_url_redundant" persistent_invitation="$janus_invitation_redundant" min_geometry="480x360-0-360"
-module janus-d cvh-camera module_name="CVH-Kamera D" browser="false" direct="true" persistent_invitation="$janus_invitation"
+#module janus cvh-camera module_name="CVH-Kamera 6" url="$janus_receiver_url" persistent_invitation="$janus_invitation"
+#module janus-r cvh-camera module_name="CVH-Kamera 5" camera_room="1005" url="$janus_receiver_url_redundant" persistent_invitation="$janus_invitation_redundant" min_geometry="480x360-0-360"
+camera_default_max_resolution="1440x1080"
+module janus-1 cvh-camera module_name="CVH-Kamera 1" browser="false" direct="true" slot="0" persistent_invitation="$janus_invitation_1"
+module janus-2 cvh-camera module_name="CVH-Kamera 2" browser="false" direct="true" slot="1" persistent_invitation="$janus_invitation_2" min_geometry="480x360-0-360"
+module janus-3 cvh-camera module_name="CVH-Kamera 3" browser="false" direct="true" slot="2" persistent_invitation="$janus_invitation_3" min_geometry="480x360-0-720"
 module om om-board module_name="OM-Tafel" url="$om_url" persistent_invitation="$om_invitation"
 module bbbb bbb-board module_name="BBB-Tafel" url="$bbb_url" persistent_invitation="$bbb_invitation" min_geometry="1440x810+0+0"
 module upload upload module_name="Upload" persistent_invitation="$upload_invitation"
diff --git a/etc/pult/pult-3.conf b/etc/pult/pult-3.conf
index 7e98276..4617349 100644
--- a/etc/pult/pult-3.conf
+++ b/etc/pult/pult-3.conf
@@ -1,33 +1,34 @@
-#start_text="starten"
-#stop_text="stoppen"
-#hide_text="verbergen"
-#show_text="zeigen"
-#min_text="minimieren"
-#max_text="maximieren"
-
 bbb_url="https://bbb.cvh-server.de/b/pet-jxk-dch" 
 bbb_invitation="follow <a target=\"_blank\" href=\"$bbb_url\">this link</a> to $bbb_url"
 jm_url="https://meet.cvh-server.de/VNC3" 
 jm_invitation="follow <a target=\"_blank\" href=\"$jm_url\">this link</a> to $jm_url"
-janus_receiver_url="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1003"
-janus_receiver_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1005"
-janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1003"
-janus_sender_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1005"
-janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
-janus_invitation_redundant="follow <a target=\"_blank\" href=\"$janus_sender_url_redundant\">this link</a> to $janus_sender_url_redundant"
+#janus_receiver_url="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1003"
+#janus_receiver_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1005"
+#janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1003"
+janus_sender_url_1="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1003&pin=testcvh&slot=0&token=@INFO@"
+janus_sender_url_2="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1003&pin=testcvh&slot=1&token=@INFO@"
+janus_sender_url_3="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1003&pin=testcvh&slot=2&token=@INFO@"
+#janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
+#janus_invitation_redundant="follow <a target=\"_blank\" href=\"$janus_sender_url_redundant\">this link</a> to $janus_sender_url_redundant"
+janus_invitation_1="follow <a target=\"_blank\" href=\"$janus_sender_url_1\">this link</a> to $janus_sender_url_1"
+janus_invitation_2="follow <a target=\"_blank\" href=\"$janus_sender_url_2\">this link</a> to $janus_sender_url_2"
+janus_invitation_3="follow <a target=\"_blank\" href=\"$janus_sender_url_3\">this link</a> to $janus_sender_url_3"
 om_url="https://openmeetings.cvh-server.de:5443/openmeetings/#room/24"
 om_invitation="follow <a target=\"_blank\" href=\"$om_url\">this link</a> to $om_url"
 upload_sender_url="https://streaming.cvh-server.de/cgi-bin/pult-upload-3.cgi"
 upload_invitation="follow <a target="_blank" href=\"$upload_sender_url\">this link</a> to $upload_sender_url"
 
-module vnc vnc module_name="VNC" listen=22 invitation="connect through SSH tunnel to port 5523"
+module vnc vnc module_name="VNC" listen=23 invitation="connect through SSH tunnel to port 5523"
 module vnc-gast vnc module_name="VNC Gast" invitation="connect to streaming.cvh-server.de:3"
 module bbb bbb-camera module_name="BBB-Kamera" url="$bbb_url" invitation="$bbb_invitation"
 module jm jm-camera module_name="JM-Kamera" url="$jm_url" invitation="$jm_invitation"
 camera_default_max_resolution="1024x768"
-module janus cvh-camera module_name="CVH-Kamera 3" url="$janus_receiver_url" persistent_invitation="$janus_invitation"
-module janus-r cvh-camera module_name="CVH-Kamera 5" camera_room="1005" url="$janus_receiver_url_redundant" persistent_invitation="$janus_invitation_redundant" min_geometry="480x360-0-360"
-module janus-d cvh-camera module_name="CVH-Kamera D" browser="false" direct="true" persistent_invitation="$janus_invitation"
+#module janus cvh-camera module_name="CVH-Kamera 3" url="$janus_receiver_url" persistent_invitation="$janus_invitation"
+#module janus-r cvh-camera module_name="CVH-Kamera 5" camera_room="1005" url="$janus_receiver_url_redundant" persistent_invitation="$janus_invitation_redundant" min_geometry="480x360-0-360"
+camera_default_max_resolution="1440x1080"
+module janus-1 cvh-camera module_name="CVH-Kamera 1" browser="false" direct="true" slot="0" persistent_invitation="$janus_invitation_1"
+module janus-2 cvh-camera module_name="CVH-Kamera 2" browser="false" direct="true" slot="1" persistent_invitation="$janus_invitation_2" min_geometry="480x360-0-360"
+module janus-3 cvh-camera module_name="CVH-Kamera 3" browser="false" direct="true" slot="2" persistent_invitation="$janus_invitation_3" min_geometry="480x360-0-720"
 module om om-board module_name="OM-Tafel" url="$om_url" persistent_invitation="$om_invitation"
 module bbbb bbb-board module_name="BBB-Tafel" url="$bbb_url" persistent_invitation="$bbb_invitation" min_geometry="1440x810+0+0"
 module upload upload module_name="Upload" persistent_invitation="$upload_invitation"
diff --git a/etc/pult/pult-6.conf b/etc/pult/pult-6.conf
index ca37bd5..44511c1 100644
--- a/etc/pult/pult-6.conf
+++ b/etc/pult/pult-6.conf
@@ -1,10 +1,3 @@
-#start_text="starten"
-#stop_text="stoppen"
-#hide_text="verbergen"
-#show_text="zeigen"
-#min_text="minimieren"
-#max_text="maximieren"
-
 bbb_url="https://bbb.cvh-server.de/b/pet-jxk-dch" 
 bbb_invitation="follow <a target=\"_blank\" href=\"$bbb_url\">this link</a> to $bbb_url"
 jm_url="https://meet.cvh-server.de/VNC6" 
@@ -12,10 +5,9 @@ jm_invitation="follow <a target=\"_blank\" href=\"$jm_url\">this link</a> to $jm
 #janus_receiver_url="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1006"
 #janus_receiver_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-receiver.html?room=1005"
 #janus_sender_url="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006"
-#janus_sender_url_redundant="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1005"
-janus_sender_url_1="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&slot=0&token=@INFO@"
-janus_sender_url_2="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&slot=1&token=@INFO@"
-janus_sender_url_3="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&slot=2&token=@INFO@"
+janus_sender_url_1="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&pin=testcvh&slot=0&token=@INFO@"
+janus_sender_url_2="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&pin=testcvh&slot=1&token=@INFO@"
+janus_sender_url_3="https://streaming.cvh-server.de/cvh-camera/camera-sender.html?room=1006&pin=testcvh&slot=2&token=@INFO@"
 #janus_invitation="follow <a target=\"_blank\" href=\"$janus_sender_url\">this link</a> to $janus_sender_url"
 #janus_invitation_redundant="follow <a target=\"_blank\" href=\"$janus_sender_url_redundant\">this link</a> to $janus_sender_url_redundant"
 janus_invitation_1="follow <a target=\"_blank\" href=\"$janus_sender_url_1\">this link</a> to $janus_sender_url_1"
diff --git a/lib/pult/cvh-camera.daemon b/lib/pult/cvh-camera.daemon
index 2543fc8..e88fdd4 100755
--- a/lib/pult/cvh-camera.daemon
+++ b/lib/pult/cvh-camera.daemon
@@ -5,7 +5,6 @@ debug=true
 module_name="$1"
 channel="$2"
 camera_room="$((1000 + channel))"
-camera_server_port="$((5010 + channel))"
 browser=true
 direct=false
 
@@ -15,6 +14,9 @@ direct=false
 pid_file="$run_directory/$module_name-$channel.pid"
 $debug && echo "$0[$channel]: pid_file = $pid_file" 1>&2
 
+input_fifo="$run_directory/cvh-camera-$channel.input"
+$debug && echo "$0[$channel]: input_fifo = $input_fifo" 1>&2
+
 module ()
 {
   m="$1"
@@ -35,9 +37,6 @@ module ()
         "direct="*)
           direct="$(echo $opt | sed -e 's/^direct=//')"
           ;;
-        "camera_server_port="*)
-          camera_server_port="$(echo $opt | sed -e 's/^camera_server_port=//')"
-          ;;
         "slot="*)
           slot="$(echo $opt | sed -e 's/^slot=//')"
           ;;
@@ -65,7 +64,7 @@ trap cleanup exit;
 if $direct; then
   token="$(dd if=/dev/urandom bs=1 count=32 2>/dev/null | shasum | cut -d " " -f 1)"
   $debug && echo "$0[$channel]: sending command to camera server: activate_slot" 1>&2
-  echo "activate_slot $slot $token" | nc -q 0 localhost "$camera_server_port"
+  echo "activate_slot $slot $token" > "$input_fifo"
 else
   token=""
 fi
diff --git a/lib/pult/cvh-camera.module b/lib/pult/cvh-camera.module
index c08e003..70b4b74 100755
--- a/lib/pult/cvh-camera.module
+++ b/lib/pult/cvh-camera.module
@@ -7,7 +7,6 @@ channel="$PULT_CHANNEL"
 $debug && echo "$0[$channel]: $module_name $@" 1>&2
 
 camera_room="$((1000 + channel))"
-camera_server_port="$((5010 + channel))"
 
 . "/usr/local/etc/pult/pult.conf"
 
@@ -27,9 +26,6 @@ module ()
         "direct="*)
           direct="$(echo $opt | sed -e 's/^direct=//')"
           ;;
-        "camera_server_port="*)
-          camera_server_port="$(echo $opt | sed -e 's/^camera_server_port=//')"
-          ;;
         "slot="*)
           slot="$(echo $opt | sed -e 's/^slot=//')"
           ;;
@@ -39,11 +35,14 @@ module ()
 }
 
 . "/usr/local/etc/pult/pult-$channel.conf"
-$debug && echo "$0[$channel]: camera_room = $camera_room, camera_server_port = $camera_server_port" 1>&2
+$debug && echo "$0[$channel]: camera_room = $camera_room" 1>&2
 
 pid_file="$run_directory/$module_name-$channel.pid"
 $debug && echo "$0[$channel]: pid_file = $pid_file" 1>&2
 
+input_fifo="$run_directory/cvh-camera-$channel.input"
+$debug && echo "$0[$channel]: input_fifo = $input_fifo" 1>&2
+
 cmd="$1"
 case "$cmd" in
   start)
@@ -53,7 +52,7 @@ case "$cmd" in
   stop)
     if $direct; then
       $debug && echo "$0[$channel]: sending command to camera server: deactivate_slot" 1>&2
-      echo "deactivate_slot $slot" | nc -q 0 localhost "$camera_server_port"
+      echo "deactivate_slot $slot" > "$input_fifo"
     fi
     if [ -f "$pid_file" ]; then
       pid=$(cat "$pid_file")
@@ -72,13 +71,13 @@ case "$cmd" in
     if $direct; then
       if [ "$2" = "hidden" ]; then
         $debug && echo "$0[$channel]: sending command to camera server: hide $slot" 1>&2
-        echo "hide $slot" | nc -q 0 localhost "$camera_server_port"
+        echo "hide $slot" > "$input_fifo"
       else
         $debug && echo "$0[$channel]: sending command to camera server: show $slot" 1>&2
-        echo "show $slot" | nc -q 0 localhost "$camera_server_port"
+        echo "show $slot" > "$input_fifo"
         sleep 0.1
         $debug && echo "$0[$channel]: sending command to camera server: set_geometry_relative_to_canvas $slot lt $4 $5 $2 $3 $6" 1>&2
-        echo "set_geometry_relative_to_canvas $slot lt $4 $5 $2 $3 $6" | nc -q 0 localhost "$camera_server_port"
+        echo "set_geometry_relative_to_canvas $slot lt $4 $5 $2 $3 $6" > "$input_fifo"
       fi
     fi
     ;;
diff --git a/pult-install b/pult-install
index a585b46..e1fc6db 100755
--- a/pult-install
+++ b/pult-install
@@ -73,6 +73,7 @@ $install -o root -g root -m 644 www/cvh-camera/* "$www_directory/cvh-camera/"
 $install -o root -g root -m 644 www/novnc/vnc.html "$novnc_directory/"
 $install -o root -g root -m 644 www/novnc/core/*.js "$novnc_directory/core/"
 $install -o root -g root -m 644 www/novnc/app/*.js "$novnc_directory/app/"
+$install -o root -g root -m 644 www/novnc/app/*.js.in "$novnc_directory/app/"
 $install -o root -g root -m 644 www/novnc/app/styles/*.css "$novnc_directory/app/styles/"
 $install -o root -g root -m 644 etc/systemd/system/* /etc/systemd/system/
 
diff --git a/sbin/cvh-camera b/sbin/cvh-camera
index a6e2651..70bb148 100755
--- a/sbin/cvh-camera
+++ b/sbin/cvh-camera
@@ -3,14 +3,15 @@
 channel="$1"
 
 server_port="$((5000 + channel))"
-pult_port="$((5010 + channel))"
+pult_fifo="/usr/local/var/run/pult/cvh-camera-$channel.input"
+
+if [ -p "$pult_fifo" ]; then
+  cat "$pult_fifo" > /dev/null
+else
+  mkfifo "$pult_fifo"
+fi
 
 export NODE_PATH="/usr/lib/node_modules"
 export PORT="$server_port"
 
-(
-  echo "hide"
-  while true; do
-    nc.openbsd -l "$pult_port"
-  done
-) | node /usr/local/sbin/cvh-camera-server.js
+tail -F "$pult_fifo" | node /usr/local/sbin/cvh-camera-server.js
diff --git a/www/cgi-bin/pult.cgi b/www/cgi-bin/pult.cgi
index b9654e2..0ce8c6c 100755
--- a/www/cgi-bin/pult.cgi
+++ b/www/cgi-bin/pult.cgi
@@ -77,9 +77,9 @@ module ()
     esac
     echo -e "      <tr>"
     echo -e "        <td><div class=\"module_name\"><div class=\"$module_class\">$module_name</div></div></td>"
-    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"start\"><button class=\"channel\" type=\"submit\">$start_text</button></form></td>"
-    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"stop\"><button class=\"channel\" type=\"submit\">$stop_text</button></form></td>"
-    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"hide\"><button class=\"channel\" type=\"submit\">$hide_text</button></form></td>"
+    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"start\"><button class=\"channel\" type=\"submit\" style=\"$start_style\">$start_text</button></form></td>"
+    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"stop\"><button class=\"channel\" type=\"submit\" style=\"$stop_style\">$stop_text</button></form></td>"
+    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"hide\"><button class=\"channel\" type=\"submit\" style=\"$hide_style\">$hide_text</button></form></td>"
     local min=false
     local defaults=$(invoke_module "$m" "$d" "defaults")
     for opt in $defaults "$@"; do
@@ -87,7 +87,7 @@ module ()
         "min="*)
           eval "$opt"
           if "$min"; then
-            echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"min\"><button class=\"channel\" type=\"submit\">$min_text</button></form></td>"
+            echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"min\"><button class=\"channel\" type=\"submit\" style=\"$min_style\">$min_text</button></form></td>"
           fi
           ;;
         "invitation="*)
@@ -107,10 +107,12 @@ module ()
       esac
     done
     local max_or_show_text="$show_text"
+    local max_or_show_style="$show_style"
     if "$min"; then
       max_or_show_text="$max_text"
+      max_or_show_style="$max_style"
     fi
-    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"max\"><button class=\"channel\" type=\"submit\">$max_or_show_text</button></form></td>"
+    echo -e "        <td><form action=\"pult-$channel.cgi\" method=\"post\"><input type=\"hidden\" name=\"$m\" value=\"max\"><button class=\"channel\" type=\"submit\" style=\"$max_or_show_style\">$max_or_show_text</button></form></td>"
     echo -e "      </tr>"
   fi
 }
diff --git a/www/cvh-camera/camera-sender.html b/www/cvh-camera/camera-sender.html
index 76f7c07..5a9bb3d 100644
--- a/www/cvh-camera/camera-sender.html
+++ b/www/cvh-camera/camera-sender.html
@@ -9,26 +9,36 @@
     </head>
     <body>
         <h3 id="room-indicator"></h3>
+<!--
         <div>
             Leave the pin empty if the rooms has none set.
         </div>
-        <select id="res-select">
-            <option value="lowres">320x240</option>
-            <option value="lowres-16:9">320x180</option>
-            <option value="stdres">640x480</option>
-            <option value="stdres-16:9">640x360</option>
-            <option value="hires-4:3">960x720</option>
-            <option value="hires-16:9">1280x720</option>
-        </select>
-        <input type="password" id="pin-input" placeholder="Room pin" />
-        <button id="start" disabled>Start</button>
-        <button id="stop" disabled>Stop</button>
-        <form id="bandwidth-form">
-            <label>A bandwidth cap can be set here. 0 or negative means no cap.</label>
-            <br />
-            <input type="text" id="bandwidth-input" placeholder="New bitrate [in kbit/s]" />
-            <input type="submit" id="bandwidth-submit" value="Change" disabled />
-        </form>
+-->
+        <p>
+            <select id="res-select">
+                <option value="lowres">320x240</option>
+                <option value="lowres-16:9">320x180</option>
+                <option value="stdres" selected>640x480</option>
+                <option value="stdres-16:9">640x360</option>
+                <option value="hires-4:3">960x720</option>
+                <option value="hires-16:9">1280x720</option>
+            </select>
+<!--
+            <input type="password" id="pin-input" placeholder="Room pin" />
+-->
+            <button id="start" disabled>Start</button>
+            <button id="stop" disabled>Stop</button>
+        </p>
+
+        <p>
+            <form id="bandwidth-form">
+                <label>While the camera is running, a bandwidth cap can be set here. 0 or negative means no cap.</label>
+                <br />
+                <input type="text" id="bandwidth-input" placeholder="New bitrate [in kbit/s]" />
+                <input type="submit" id="bandwidth-submit" value="Change" disabled />
+            </form>
+        </p>
+
         <div id="preview-container"></div>
     </body>
 </html>
diff --git a/www/cvh-camera/camera-sender.js.in b/www/cvh-camera/camera-sender.js.in
index 4dbe7df..61f7df1 100644
--- a/www/cvh-camera/camera-sender.js.in
+++ b/www/cvh-camera/camera-sender.js.in
@@ -14,14 +14,16 @@ document.addEventListener('DOMContentLoaded', function() {
     var transmitting = false;
     var room = 1006;
     var slot = 0;
+    var pin = '';
     var token = '';
     var feedId = null;
 
     parseRoomFromURL();
     parseSlotFromURL();
+    parsePinFromURL();
     parseTokenFromURL();
 
-    roomIndicator.innerText = `VNC ${room - 1000} (Room ${room}) - Slot ${slot} - Token: ${token || '*none*'}`;
+    roomIndicator.innerText = `Channel ${room - 1000}, Camera ${slot + 1}`;
 
     const socketNumber = room + 4000;
     const socket = io('https://' + window.location.hostname, {
@@ -48,9 +50,11 @@ document.addEventListener('DOMContentLoaded', function() {
             transmitting = true;
 
             var bandwidthForm = document.getElementById('bandwidth-form');
-            var bandwidthSubmit = document.getElementById('bandwidth-submit');
-            bandwidthForm.onsubmit = handleBandwidthFormSubmit;
-            bandwidthSubmit.removeAttribute('disabled', '');
+            if (bandwidthForm) {
+                var bandwidthSubmit = document.getElementById('bandwidth-submit');
+                bandwidthForm.onsubmit = handleBandwidthFormSubmit;
+                bandwidthSubmit.removeAttribute('disabled', '');
+            }
             stopButton.removeAttribute('disabled');
             stopButton.onclick = function() {
                 janus.destroy();
@@ -102,13 +106,11 @@ document.addEventListener('DOMContentLoaded', function() {
 
                             startButton.onclick = function() {
                                 var resSelect = document.getElementById('res-select');
-                                var pinInput = document.getElementById('pin-input');
                                 startButton.setAttribute('disabled', '');
                                 resSelect.setAttribute('disabled', '');
                                 sendResolution = resSelect.value;
                                 Janus.log('sendResolution:', sendResolution);
-                                shareCamera(pinInput.value);
-                                pinInput.value = '';
+                                shareCamera(pin);
                             };
                             startButton.removeAttribute('disabled');
                         },
@@ -249,6 +251,16 @@ document.addEventListener('DOMContentLoaded', function() {
         }
     }
 
+    function parsePinFromURL() {
+        var urlParams = new URLSearchParams(window.location.search);
+        var pinParam = urlParams.get('pin');
+        if (pinParam != null) {
+            pin = pinParam;
+        } else {
+            console.log('Got no valid pin in URL search params');
+        }
+    }
+
     function parseTokenFromURL() {
         var urlParams = new URLSearchParams(window.location.search);
         var tokenParam = urlParams.get('token');
diff --git a/www/novnc/app/camera-receiver.js.in b/www/novnc/app/camera-receiver.js.in
index 1371bb1..d83275f 100644
--- a/www/novnc/app/camera-receiver.js.in
+++ b/www/novnc/app/camera-receiver.js.in
@@ -122,9 +122,12 @@ document.addEventListener('DOMContentLoaded', function() {
         delete videoGeometryParams[slot];
         delete source[slot];
         var video = document.getElementById('camera-feed-' + slot);
-        video.remove();
-        janusPluginHandles[slot].detach();
-        delete janusPluginHandles[slot];
+        if (video)
+            video.remove();
+        if (janusPluginHandles[slot]) {
+            janusPluginHandles[slot].detach();
+            delete janusPluginHandles[slot];
+        }
     }
 
     function newRemoteFeed(slot, feedId, initialState) {
-- 
GitLab