From 353522e3cc48ae4c838cb6c6675ffa1bf3b1348e Mon Sep 17 00:00:00 2001 From: Lukas von Blarer Date: Thu, 4 Feb 2021 09:57:43 +0100 Subject: [PATCH] Add support for HLS video streams while still supporting other formats --- front/package.json | 2 ++ front/src/WebRtc/VideoManager.ts | 59 +++++++++++++++++--------------- front/yarn.lock | 20 ++++++++++- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/front/package.json b/front/package.json index e64c0816..2315fe43 100644 --- a/front/package.json +++ b/front/package.json @@ -34,12 +34,14 @@ "webpack-dev-server": "^3.11.2" }, "dependencies": { + "@types/hls.js": "^0.13.3", "@types/simple-peer": "^9.6.0", "@types/socket.io-client": "^1.4.32", "axios": "^0.21.1", "generic-type-guard": "^3.2.0", "google-protobuf": "^3.13.0", "phaser": "^3.54.0", + "hls.js": "^0.14.17", "phaser3-rex-plugins": "^1.1.42", "queue-typescript": "^1.0.1", "quill": "1.3.6", diff --git a/front/src/WebRtc/VideoManager.ts b/front/src/WebRtc/VideoManager.ts index b0f7425f..6df8ffdd 100644 --- a/front/src/WebRtc/VideoManager.ts +++ b/front/src/WebRtc/VideoManager.ts @@ -1,5 +1,6 @@ import {HtmlUtils} from "./HtmlUtils"; import {isUndefined} from "generic-type-guard"; +import Hls from "hls.js"; enum videoStates { closed = 0, @@ -32,10 +33,7 @@ class VideoManager { this.setVolume(1); } else { this.volume = parseFloat(storedVolume); - //HtmlUtils.getElementByIdOrFail('videoplayer_volume').value = storedVolume; } - - //HtmlUtils.getElementByIdOrFail('videoplayer_volume').value = '' + this.volume; } private close(): void { @@ -77,8 +75,6 @@ class VideoManager { public loadVideo(url: string): void { this.load(); - - /* Solution 1, remove whole video player */ this.videoPlayerDiv.innerHTML = ''; // necessary, if switching from one video context to another! (else both streams would play simultaneously) this.videoPlayerElem = document.createElement('video'); @@ -86,35 +82,22 @@ class VideoManager { this.videoPlayerElem.controls = true; this.videoPlayerElem.preload = 'none'; - const srcElem = document.createElement('source'); - srcElem.src = url; - - this.videoPlayerElem.append(srcElem); + if (url.includes('.m3u8')) { + this.loadHlsVideo(url); + } else { + this.videoPlayerElem.src = url; + } this.videoPlayerDiv.append(this.videoPlayerElem); this.changeVolume(); this.videoPlayerElem.play(); - /*const muteElem = HtmlUtils.getElementByIdOrFail('videoplayer_mute'); - muteElem.onclick = (ev: Event)=> { - this.muted = !this.muted; - this.changeVolume(); - - if (this.muted) { - HtmlUtils.getElementByIdOrFail('videoplayer_volume_icon_playing').classList.add('muted'); - } else { - HtmlUtils.getElementByIdOrFail('videoplayer_volume_icon_playing').classList.remove('muted'); - } + // @TODO: The videoPlayerElem variable is needed because of `this` being overridden in event handler. + const videoPlayerElem = this.videoPlayerElem; + videoPlayerElem.onplay = (e)=> { + this.jumpToEnd(videoPlayerElem); } - const volumeElem = HtmlUtils.getElementByIdOrFail('videoplayer_volume'); - volumeElem.oninput = (ev: Event)=> { - this.setVolume(parseFloat((ev.currentTarget).value)); - this.changeVolume(); - - (ev.currentTarget).blur(); - }*/ - const decreaseElem = HtmlUtils.getElementByIdOrFail('videoplayer_decrease_while_talking'); decreaseElem.oninput = (ev: Event)=> { this.decreaseWhileTalking = (ev.currentTarget).checked; @@ -130,6 +113,28 @@ class VideoManager { } } + public loadHlsVideo(url: string): void { + if (this.videoPlayerElem !== undefined) { + // First check for native browser HLS support + if (this.videoPlayerElem.canPlayType('application/vnd.apple.mpegurl')) { + this.videoPlayerElem.src = url; + // If no native HLS support, check if hls.js is supported + } else if (Hls.isSupported()) { + const hls = new Hls(); + hls.loadSource(url); + hls.attachMedia(this.videoPlayerElem); + } + } + } + + public jumpToEnd(videoPlayerElem: HTMLVideoElement): void { + const duration = videoPlayerElem.duration; + if (duration){ + videoPlayerElem.currentTime = duration; + videoPlayerElem.play(); + } + } + public unloadVideo(): void { try { const videoElem = HtmlUtils.getElementByIdOrFail('videoplayerelem'); diff --git a/front/yarn.lock b/front/yarn.lock index bbdf0e06..d618e47a 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -157,6 +157,11 @@ resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.2.tgz#70753e948cabeb416d71299dc35c3f562a10fb0f" integrity sha512-ubeqvw7sl6CdgeiIilsXB2jIFoD/D0F+/LIEp7xEBEXRNtDJcf05FRINybsJtL7GlkWOUVn6gJs2W9OF+xI6lg== +"@types/hls.js@^0.13.3": + version "0.13.3" + resolved "https://registry.yarnpkg.com/@types/hls.js/-/hls.js-0.13.3.tgz#eb982a866125745eadee468c989fc9e189f24019" + integrity sha512-Po8ZPCsAcPPuf5OODPEkb6cdWJ/w4BdX1veP7IIOc2WG0x1SW4GEQ1+FHKN1AMG2AePJfNUceJbh5PKtP92yRQ== + "@types/html-minifier-terser@^5.0.0": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50" @@ -2004,7 +2009,7 @@ eventemitter3@^3.1.2: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== -eventemitter3@^4.0.0, eventemitter3@^4.0.7: +eventemitter3@^4.0.0, eventemitter3@^4.0.3, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -2577,6 +2582,14 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hls.js@^0.14.17: + version "0.14.17" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.14.17.tgz#0127cff2ec2f994a54eb955fe669ef6153a8e317" + integrity sha512-25A7+m6qqp6UVkuzUQ//VVh2EEOPYlOBg32ypr34bcPO7liBMOkKFvbjbCBfiPAOTA/7BSx1Dujft3Th57WyFg== + dependencies: + eventemitter3 "^4.0.3" + url-toolkit "^2.1.6" + hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -5317,6 +5330,11 @@ url-parse@^1.4.3, url-parse@^1.5.1: querystringify "^2.1.1" requires-port "^1.0.0" +url-toolkit@^2.1.6: + version "2.2.1" + resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.2.1.tgz#89009ed3d62a3574de079532a7266c14d2cc1c4f" + integrity sha512-8+DzgrtDZYZGhHaAop5WGVghMdCfOLGbhcArsJD0qDll71FXa7EeKxi2hilPIscn2nwMz4PRjML32Sz4JTN0Xw== + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"