From 5f7c947268a76a6eaa1c4e1d4b3152a8dbf4cff3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Simon=20D=C3=B6ring?= <simon.doering@stud.hs-bochum.de>
Date: Sat, 6 Feb 2021 16:56:11 +0100
Subject: [PATCH] Add bitrate limiting by controller to frontend

---
 camera-server/src/janus/handlers.ts           | 13 ++++---
 .../src/socket-io/handlers/sender-handlers.ts | 16 ++++++++-
 sender/camera-sender.css                      | 18 ++++++++++
 sender/camera-sender.html                     |  5 +--
 sender/camera-sender.js                       | 34 +++++++++++++------
 5 files changed, 68 insertions(+), 18 deletions(-)

diff --git a/camera-server/src/janus/handlers.ts b/camera-server/src/janus/handlers.ts
index 0cbc889..0000fd6 100644
--- a/camera-server/src/janus/handlers.ts
+++ b/camera-server/src/janus/handlers.ts
@@ -7,9 +7,12 @@ export const setBitrate = async (
 ): Promise<boolean> => {
     const currentSlotState = cameraSlotState[slot];
     if (!currentSlotState.feedActive) {
-        console.log(`Tried to set bitrate for inactive slot ${slot}`);
+        console.log(
+            `Error: Tried to set bitrate of feed on slot ${slot} which has no active feed`
+        );
         return false;
     }
+    console.log(`Setting bitrate of feed on slot ${slot} to ${newBitrate}`);
     try {
         const response = await janusAPI.configureVideoroomBitrate(
             currentSlotState.sessionId!,
@@ -17,15 +20,17 @@ export const setBitrate = async (
             newBitrate
         );
         if (response.data?.janus === 'ack') {
-            console.log('Set new bitrate for slot ' + slot);
+            console.log(`Successfully set new bitrate of feed on slot ${slot}`);
             return true;
         } else {
-            console.log(`Error: Could not set new bitrate for slot ${slot}`);
+            console.log(
+                `Error: Could not set new bitrate of feed on slot ${slot}`
+            );
             return false;
         }
     } catch (err) {
         console.log(
-            `Error: An unknown error occurred while setting the bitrate of slot ${slot}:`,
+            `Error: An unknown error occurred while setting the bitrate of the feed on slot ${slot}:`,
             err
         );
         return false;
diff --git a/camera-server/src/socket-io/handlers/sender-handlers.ts b/camera-server/src/socket-io/handlers/sender-handlers.ts
index 691b1a4..0426a6b 100644
--- a/camera-server/src/socket-io/handlers/sender-handlers.ts
+++ b/camera-server/src/socket-io/handlers/sender-handlers.ts
@@ -38,6 +38,7 @@ const handleSetFeedId = (
 ) => {
     let success = true;
     let message = '';
+    let controllerBitrateLimit = null;
 
     try {
         const slot = socket.cameraSlot;
@@ -138,6 +139,7 @@ const handleSetFeedId = (
 
         console.log('Setting feed id of slot ' + slot + ' to ' + feedId);
         message = 'Successfully set feed id - you are now using this slot';
+        controllerBitrateLimit = currentSlotState.controllerBitrateLimit;
 
         currentSlotState.feedActive = true;
         currentSlotState.feedId = feedId;
@@ -161,7 +163,15 @@ const handleSetFeedId = (
         }
     }
 
-    fn({ success, message });
+    const response: {
+        success: boolean;
+        message: string;
+        controllerBitrateLimit?: number;
+    } = { success, message };
+    if (controllerBitrateLimit != null) {
+        response.controllerBitrateLimit = controllerBitrateLimit;
+    }
+    fn(response);
 };
 
 const handleChangeName = (
@@ -275,6 +285,10 @@ const handleSetBitrateLimit = async (
             bitrateLimit = 0;
         }
 
+        console.log(
+            `Setting user bitrate limit of slot ${slot} to ${bitrateLimit}`
+        );
+
         const prevBitrate = currentSlotState.getCurrentBitrate();
         currentSlotState.userBitrateLimit = bitrateLimit;
         const newBitrate = currentSlotState.getCurrentBitrate();
diff --git a/sender/camera-sender.css b/sender/camera-sender.css
index 04653ed..57635a6 100644
--- a/sender/camera-sender.css
+++ b/sender/camera-sender.css
@@ -177,12 +177,30 @@ body {
 
 .bandwidth-form__input {
     flex: 2 0 50px;
+    padding: 4px;
     min-width: 0;
+    border: 2px solid transparent;
+    border-radius: 4px;
     margin-right: 4px;
+    outline: none;
+    box-shadow: none;
+}
+
+.bandwidth-form__input:focus {
+    border-color: var(--light-blue-3);
 }
 
 .bandwidth-form__button {
     flex: 1 0 0;
+    padding: 4px;
+    border-radius: 4px;
+    outline: none;
+    border: none;
+    background: var(--light-blue-2);
+}
+
+.bandwidth-form__button:hover {
+    background: var(--light-blue-3);
 }
 
 .main__controls {
diff --git a/sender/camera-sender.html b/sender/camera-sender.html
index 54f4af9..0a25bf5 100644
--- a/sender/camera-sender.html
+++ b/sender/camera-sender.html
@@ -58,10 +58,11 @@
             <section id="options-container" class="main__options hidden">
                 <button id="options-toggle" class="options__toggle">Advanced options</button>
                 <div id="options" class="options__body hidden">
+                    <p class="options__hint">Controller bitrate limit: <span id="controller-bitrate-limit">128</span> kbit/s</p>
+                    <p class="options__hint">Your bitrate limit (0 means no limit): <span id="user-bitrate-limit">0</span> kbit/s</p>
                     <form id="bandwidth-form">
-                        <p class="options__hint">While the camera is running, a bandwidth cap can be set here. 0 or negative means no cap.</p>
                         <div class="bandwidth-form__control">
-                            <input type="text" placeholder="Bitrate [in kbit/s]" id="bandwidth-input" class="bandwidth-form__input" />
+                            <input type="number" min="0" required placeholder="Bitrate [in kbit/s]" id="bandwidth-input" class="bandwidth-form__input" />
                             <button type="submit" id="bandwidth-submit" class="bandwidth-form__button" disabled>Change</button>
                         </div>
                     </form>
diff --git a/sender/camera-sender.js b/sender/camera-sender.js
index 00bd473..91c9e07 100644
--- a/sender/camera-sender.js
+++ b/sender/camera-sender.js
@@ -74,6 +74,9 @@ document.addEventListener('DOMContentLoaded', function() {
             }
         });
         socket.on('disconnect', handleUnexpectedSocketDisconnect);
+        socket.on('new_controller_bitrate_limit', function(data) {
+            setControllerBitrateLimit(Math.floor(data.bitrateLimit / 1000));
+        });
     };
 
     function handleSenderInitResponse(data) {
@@ -105,6 +108,7 @@ document.addEventListener('DOMContentLoaded', function() {
 
             showVideo();
             showOptions();
+            setControllerBitrateLimit(Math.floor(data.controllerBitrateLimit / 1000));
             if (customNameAllowed) {
                 var nameForm = document.getElementById('name-form');
                 nameForm.onsubmit = function(event) {
@@ -221,18 +225,18 @@ document.addEventListener('DOMContentLoaded', function() {
     function handleBandwidthFormSubmit(event) {
         event.preventDefault();
         var bandwidthInput = document.getElementById('bandwidth-input');
-        var bitrateStr = bandwidthInput.value.trim();
-        if (bitrateStr !== '' && !isNaN(bitrateStr) ) {
-            var bitrate = parseInt(bitrateStr) * 1000;
-            if (bitrate < 0) {
-                bandwidth = 0;
-                Janus.log('Negative bitrate input set to 0 (unlimited)');
+        var bitrateLimit = parseInt(bandwidthInput.value);
+        bandwidthInput.value = '';
+        socket.emit(
+            'set_bitrate_limit',
+            { bitrateLimit: 1000 * bitrateLimit },
+            function(data) {
+                console.log('set_bitrate_limit response', data);
+                if (data.success) {
+                    setUserBitrateLimit(bitrateLimit);
+                }
             }
-            videoroomHandle.send({ message: { request: 'configure', bitrate }});
-            bandwidthInput.value = '';
-        } else {
-            alert('Invalid value for bitrate');
-        }
+        );
     }
 
     function handleMessage(msg, jsep) {
@@ -286,6 +290,14 @@ document.addEventListener('DOMContentLoaded', function() {
         }
     }
 
+    function setUserBitrateLimit(bitrateLimit) {
+        document.getElementById('user-bitrate-limit').innerText = bitrateLimit;
+    }
+
+    function setControllerBitrateLimit(bitrateLimit) {
+        document.getElementById('controller-bitrate-limit').innerText = bitrateLimit;
+    }
+
     function cleanup() {
         hideVideo();
         hideOptions();
-- 
GitLab