diff --git a/novnc/app/camera-receiver.js b/novnc/app/camera-receiver.js
index e86026c04385f9ffc2c4fe15d830f60f1589af16..eb7405f7b60d1faea4c5d0624b937b15d1b15e73 100644
--- a/novnc/app/camera-receiver.js
+++ b/novnc/app/camera-receiver.js
@@ -7,7 +7,6 @@ document.addEventListener('DOMContentLoaded', function() {
     var opaqueId = 'camera-receiver-' + Janus.randomString(12);
 
     var room = 1000;
-    var source = {};
 
     var passwordButton = document.getElementById('noVNC_password_button');
     var passwordInput = document.getElementById('noVNC_password_input');
@@ -49,6 +48,7 @@ document.addEventListener('DOMContentLoaded', function() {
     //     h: 0,
     //     z: 0
     // }
+    var source = {};
 
     var videoPrescale = 1;
     parseVideoPrescaleFromURL();
@@ -138,37 +138,52 @@ document.addEventListener('DOMContentLoaded', function() {
         source[slot] = feedId;
         var cameraElementId = 'camera-feed-' + slot;
 
-        var video = document.getElementById(cameraElementId);
-        if (video == null) {
+        var videoEl = document.getElementById(cameraElementId);
+        if (videoEl == null) {
             var videoContainer = document.createElement('div');
             videoContainer.setAttribute('id', cameraElementId + '-container');
             videoContainer.classList.add('camera-feed-container');
 
-            video = document.createElement('video');
-            video.setAttribute('id', cameraElementId);
-            video.setAttribute('muted', '');
-            video.setAttribute('autoplay', '');
-            video.setAttribute('playsinline', '');
+            videoEl = document.createElement('video');
+            videoEl.setAttribute('id', cameraElementId);
+            videoEl.setAttribute('muted', '');
+            videoEl.setAttribute('autoplay', '');
+            videoEl.setAttribute('playsinline', '');
             // Necessary for autoplay without user interaction
-            video.oncanplaythrough = function() {
-                video.muted = true;
-                video.play();
+            videoEl.oncanplaythrough = function() {
+                videoEl.muted = true;
+                videoEl.play();
             }
-            video.classList.add('camera-feed');
+            videoEl.classList.add('camera-feed');
 
             document.body.appendChild(videoContainer);
-            videoContainer.appendChild(video);
+            videoContainer.appendChild(videoEl);
         }
 
-        var remoteFeedHandle = null;
-        
+        attachSubscriber(slot, feedId);
+
+        handleCommand(slot, initialState.geometry.command, initialState.geometry.params);
+        handleCommand(slot, initialState.visibility.command, initialState.visibility.params);
+        if (initialState.annotation) {
+            setAnnotation(slot, initialState.annotation);
+        }
+    }
+
+    function reconnectRemoteFeed(slot) {
+        if (janusPluginHandles[slot] != null) {
+            janusPluginHandles[slot].detach();
+        }
+        var feedId = source[slot];
+        attachSubscriber(slot, feedId);
+    }
+
+    function attachSubscriber(slot, feedId) {
         janus.attach({
             plugin: 'janus.plugin.videoroom',
             opaqueId,
             success: function(pluginHandle) {
-                remoteFeedHandle = pluginHandle;
                 janusPluginHandles[slot] = pluginHandle;
-                Janus.log('Plugin attached (subscriber slot ' + slot + ')! (' + remoteFeedHandle.getPlugin() + ', id=' + remoteFeedHandle.getId() + ')');
+                Janus.log('Plugin attached (subscriber slot ' + slot + ')! (' + pluginHandle.getPlugin() + ', id=' + pluginHandle.getId() + ')');
                 var listen = {
                     request: 'join',
                     room,
@@ -176,7 +191,7 @@ document.addEventListener('DOMContentLoaded', function() {
                     feed: feedId,
                     pin
                 };
-                remoteFeedHandle.send({ message: listen });
+                pluginHandle.send({ message: listen });
             },
             error: function(error) {
                 var formattedError = JSON.stringify(error, null, 2);
@@ -185,18 +200,23 @@ document.addEventListener('DOMContentLoaded', function() {
             },
             onmessage: handleMessageSubscriber.bind(null, slot),
             onremotestream: function(stream) {
-                Janus.attachMediaStream(video, stream);
+                var cameraEl = document.getElementById('camera-feed-' + slot);
+                Janus.attachMediaStream(cameraEl, stream);
+            },
+            iceState: function handleIceState(state) {
+                if (state === 'failed') {
+                    console.warn(`iceState of slot ${slot} changed to failed`);
+                    console.log('Trying to reconnect');
+                    reconnectRemoteFeed(slot);
+                    console.log('%cICE failed - bitte Screenshot vom Verlauf dieser Konsole machen und an Professor Gerwinski oder Simon Döring (simon.doering@stud.hs-bochum.de) schicken. Bitte auch schauen, ob noch/wieder alle Kamera-Bilder zu sehen sind, ohne die Seite neu zu laden!', 'font-size: 20px; background: #f55');
+                } else {
+                    console.log(`iceState of slot ${slot} changed to: ${state}`);
+                }
             },
             oncleanup: function() {
                 Janus.log('Got a cleanup notification');
             }
         });
-
-        handleCommand(slot, initialState.geometry.command, initialState.geometry.params);
-        handleCommand(slot, initialState.visibility.command, initialState.visibility.params);
-        if (initialState.annotation) {
-            setAnnotation(slot, initialState.annotation);
-        }
     }
 
     function handleMessageSubscriber(slot, msg, jsep) {
@@ -231,6 +251,20 @@ document.addEventListener('DOMContentLoaded', function() {
         }
     }
 
+    // TEST START
+    var testContainer = document.createElement('div');
+    testContainer.setAttribute('style', 'position: fixed; bottom: 0; right: 0;');
+    [0, 1, 2, 3].forEach(function(slot) {
+        var testButton = document.createElement('button');
+        testButton.innerText = 'Reconnect slot ' + slot;
+        testButton.onclick = function() {
+            reconnectRemoteFeed(slot);
+        };
+        testContainer.appendChild(testButton);
+    });
+    document.body.appendChild(testContainer);
+    // TEST END
+
     function parseRoomFromURL() {
         var urlParams = new URLSearchParams(window.location.search);
         var roomParam = urlParams.get('room');