Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Commit

Permalink
add network throttling option to gpac
Browse files Browse the repository at this point in the history
  • Loading branch information
DenizUgur committed Jul 17, 2022
1 parent 9c724dc commit d54700c
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 6 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,8 @@ COPY ./config/nginx.prod.conf /etc/nginx/nginx.conf
COPY --from=node-builder /server/gpac-dash /usr/local/bin/
COPY --from=node-builder /server/app/build /opt/server

# Copy network profiles
COPY ./simulator/config/profiles /opt/profiles

COPY ./scripts/entrypoint.sh /opt/entrypoint.sh
ENTRYPOINT [ "/opt/entrypoint.sh" ]
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ docker run -p 80:80 \ # web server will be accesible on port 80
-w "/home" \ # If you want to use your own video files
--name capsc-demo \ # Optional: If you want to name the container
ghcr.io/denizugur/capsc \ # Chanege it to `capsc` if you built the image yourself
<path to input file> # A file to stream. Must be relative to current working directory
<true or false> # Set to true if you want to display the visualizations over the video
--help # Shows the usage instructions for the demo
```

## Citation
Expand Down
38 changes: 35 additions & 3 deletions scripts/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
#!/bin/bash
INPUT_FILE=$1
VISUALIZATION=$2
POSITIONAL_ARGS=()

while [[ $# -gt 0 ]]; do
case $1 in
-i | --input)
INPUT_FILE="$2"
shift # past argument
shift # past value
;;
-n | --network-profile)
NETWORK_PROFILE="-use-network-profile $2"
shift # past argument
shift # past value
;;
-v | --visualization)
VISUALIZATION=YES
shift # past argument
;;
-h | --help)
echo "Usage: ./entrypoint.sh [-i | --input <input-file>] [-n | --network-profile <network-profile>] [-v | --visualization]"
exit 0
;;
-* | --*)
echo "Unknown option $1"
exit 1
;;
*)
POSITIONAL_ARGS+=("$1") # save positional arg
shift # past argument
;;
esac
done

set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters

if [ -z $INPUT_FILE ]; then
echo "No input file specified"
Expand All @@ -18,7 +50,7 @@ nginx

# Start GPAC
cd /opt
(gpac-dash -chunk-media-segments -cors &) >/dev/null 2>&1
(gpac-dash -chunk-media-segments -cors $NETWORK_PROFILE &) >/dev/null 2>&1

# Show banner
figlet "A-CAPSC Demonstration"
Expand Down
4 changes: 3 additions & 1 deletion scripts/gpac.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#!/bin/bash
BASE=$(dirname "$0")
export NODE_ENV=development

cd $BASE/../server
forever ./gpac-dash.js -chunk-media-segments -cors
forever ./gpac-dash.js -chunk-media-segments -cors $@
57 changes: 57 additions & 0 deletions server/gpac-dash.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ function usage() {
console.log("-segment-marker <4cc> marker for end of segment (default eods)");
console.log("-no-marker-write strip marker of the generated bitstream (default false)");
console.log("-cors add CORS header for all domains")
console.log("-use-network-profile specify the network profile to use (default: not used)");
console.log("-use-watch uses watch instead of watchFile (default: false)");
console.log("-quality-log-file name of a file in which the latest quality requested is logged (default: no log), experimental");
console.log("-incoming-log-file name of a file in which all requests are logged (default: no log)");
Expand All @@ -32,6 +33,7 @@ var port = 8000;
var quality_log_file = null;
var incoming_log_file = null;
var logLevel = 0;
var networkProfile = null;

/* Boolean controlling the sending of segments fragment-by-fragment as HTTP chunks,
requires MP4Box or DashCast to use -segment-marker eods */
Expand Down Expand Up @@ -91,9 +93,51 @@ function reportEvent(type, event, filename) {
reportMessage(logLevels.DEBUG_BASIC, type + " event (" + event + ") on " + filename + " (size " + file_size + ")");
}

let prevTime = null;
let sessionStartTime = null;
function throttleBandwidth(response, fileData) {
let presetOffset = 10;
let throttleOffset = 5;

if (sessionStartTime == null || prevTime + 30 * 1000 < getTime())
sessionStartTime = getTime();
prevTime = getTime();

let current_duration = getTime() - sessionStartTime;
current_duration /= 1000;

let networkProfile_i = parseInt(
(current_duration + presetOffset) % networkProfile.length
);
let targetRate =
(networkProfile[networkProfile_i].data.download * 8) / 1000;
targetRate *= 0.75;

let totalDuration = (getTime() - response.startTime) / 1000;
let size = (8 * fileData.total_sent) / 1000;
let targetDuration = size / targetRate;

let skipFlag =
totalDuration < 1 || size < 1000 || current_duration < throttleOffset;
if (totalDuration < targetDuration && !skipFlag) {
var diff = targetDuration - totalDuration;
var clamp = Math.min(diff, 0.2);
let targetTime = totalDuration + clamp;
while (true) {
totalDuration = (getTime() - response.startTime) / 1000;
if (totalDuration >= targetTime) {
break;
}
}
}
}

function sendAndUpdateBuffer(response, message, fileData, endpos, noWrite) {
var tmpBuffer;
fileData.total_sent += endpos;

if (networkProfile != null) throttleBandwidth(response, fileData);

reportMessage(sendMediaSegmentsFragmented ? logLevels.INFO : logLevels.DEBUG_BASIC,
"sendMediaSegmentsFragmented: " + sendMediaSegmentsFragmented + " File " + fileData.filename + ", sending " + message + " data from " + fileData.next_byte_to_send + " to " + (endpos - 1) + " in " + (getTime() - response.startTime) + " ms (total_sent: " + fileData.total_sent + ") at utc " + getTime());
tmpBuffer = fileData.buffer.slice(fileData.next_byte_to_send, endpos);
Expand Down Expand Up @@ -559,6 +603,19 @@ process.argv.splice(1).forEach(function (val, index, array) {
sendMediaSegmentsFragmented = true;
} else if (val === "-cors") {
allowCors = true;
} else if (val === "-use-network-profile") {
try {
const profilesPath =
process.env["NODE_ENV"] == "development"
? "../simulator/config/profiles"
: "/opt/profiles";
networkProfile = require(`${profilesPath}/${
array[index + 1]
}.json`);
} catch {
console.error("Network profile not found");
process.exit(-1);
}
} else if (val === "-use-watch") {
use_watchFile = false;
} else if (val === "-quality-log-file") {
Expand Down

0 comments on commit d54700c

Please sign in to comment.