Skip to content

Instantly share code, notes, and snippets.

@mekya
Last active May 16, 2021 08:12
Show Gist options
  • Save mekya/5f7cb829cd1a4c2ed0ef593cfe963afc to your computer and use it in GitHub Desktop.
Save mekya/5f7cb829cd1a4c2ed0ef593cfe963afc to your computer and use it in GitHub Desktop.
Custom player - plays the rtmp or stream source if it's broadcasting and speed is high enough
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Ant Media Server WebRTC/HLS Player</title>
<!-- videojs includes -->
<link href="css/external/video-js.css" rel="stylesheet">
<script src="js/external/video.js"></script>
<script
src="js/external/videojs-http-streaming.js"></script>
<!-- end of video js includes -->
<script src="js/fetch.js"></script>
<script src="js/promise.min.js"></script>
<script src="js/external/adapter-latest.js"></script>
<script src="js/external/dash.all.min.js"></script>
<link href="css/player.css" rel="stylesheet">
</head>
<body>
<div id="video_info">
Stream will start playing automatically<br />when it is live
</div>
<!-- HLS Player -->
<div id="video_container">
<video id="video-player"
class="video-js vjs-default-skin vjs-big-play-centered"
controls preload="auto">
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading
to a web browser that <a
href="http://videojs.com/html5-video-support/" target="_blank">supports
HTML5 video</a>
</p>
</video>
</div>
<!-- WebRTC Player -->
<video id="remoteVideo" controls playsinline></video>
<div id="networkWarning">Your connection isn't fast enough to play this stream!</div>
<img id="play_button" src="images/play.png" onclick="playWebRTCVideo()"
style="position: absolute; top: 30px; left: 30px; display: none;" />
<script type="module">
/**
* This page accepts 4 arguments.
* 1. "id": the stream id to play.It is mandatory
* 2. "token": the token to play stream. It's mandatory if token security is enabled on server side.
* 3. "autoplay": To start playing automatically if streams is available. Optional. Default value is true
* 4. "mute": To start playing with mute if streams is available. Optional. Default value is true
* 5. "playOrder": the order which technologies is used in playing. Optional. Default value is "webrtc,hls".
* possible values are "hls,webrtc","webrtc","hls","vod","dash"
* 6. "playType": the order which play type is used in playing. Optional. Default value is "mp4,webm".
* possible values are "webm,mp4"","mp4","webm"
* 7. "targetLatency": To define target latency for the DASH player. Optional. Default value is 3.
*/
import {WebRTCAdaptor} from "./js/webrtc_adaptor.js"
import {getUrlParameter, isMobile, tryToPlay, tryToVODPlay} from "./js/fetch.stream.js"
//The play order, player tries to play according to this order, if it can not play then tries following format
var playOrder = getUrlParameter("playOrder");
if (playOrder == null) {
playOrder = ["webrtc", "hls"];
}
else {
playOrder = playOrder.split(',');
}
var streamId = getUrlParameter("id");
if (streamId == null) {
//check name variable for compatibility with older versions
streamId = getUrlParameter("name");
}
var playType = getUrlParameter("playType") ;
if (playType == null || playType=="mp4,webm"){
playType = ["mp4", "webm"];
}
else if(playType == "webm,mp4") {
playType=["webm", "mp4"];
}
else if(playType == "mp4"){
playType=["mp4"];
}
else if(playType == "webm"){
playType=["webm"];
}
var token = getUrlParameter("token");
var pAutoplay = getUrlParameter("autoplay");
var mute = getUrlParameter("mute");
var targetLatency = getUrlParameter("targetLatency");
var placeHolder = document.getElementById("video_info");
if(targetLatency == "null"){
targetLatency = 3;
}
var hlsExtension = "m3u8";
var dashExtension = "mpd";
var subscriberId = getUrlParameter("subscriberId");
var subscriberCode = getUrlParameter("subscriberCode");
var autoPlay = true;
if (pAutoplay == "false" || isMobile()) {
autoPlay = false;
}
if (mute == "true" || mute == null) {
mute = true;
}
else{
mute = false;
}
var webRTCAdaptor = null;
var streamsFolder = "streams";
function genericCallback(currentTech) {
placeHolder.innerHTML="Stream will start playing automatically<br/>when it is live";
setTimeout(function()
{
var index = playOrder.indexOf(currentTech);
if (index == -1 || index == (playOrder.length-1)) {
index = 0;
}
else {
index++;
}
var tech = playOrder[index];
if (tech == "webrtc")
{
// It means there is no HLS stream, so try to play WebRTC stream
if (webRTCAdaptor == null) {
initializeWebRTCPlayer(streamId, token, webrtcNoStreamCallback);
}
else {
webRTCAdaptor.getStreamInfo(streamId);
}
}
else if (tech == "hls")
{
tryToPlay(streamId, token, hlsExtension, subscriberId, subscriberCode, hlsNoStreamCallback);
}
else if (tech == "dash")
{
var dashFile = streamId + "/" + streamId;
tryToPlay(dashFile, token, dashExtension, subscriberId, subscriberCode, dashNoStreamCallback);
}
}, 3000);
}
function webrtcNoStreamCallback() {
/**
* If HLS is in the play order then try to play HLS, if not wait for WebRTC stream
* In some cases user may want to remove HLS from the order and force to play WebRTC only
* in these cases player only waits for WebRTC streams
*/
genericCallback("webrtc");
}
function hlsNoStreamCallback()
{
genericCallback("hls");
}
function vodNoStreamCallback()
{
placeHolder.innerHTML="Stream will start playing automatically<br/>when it is live";
setTimeout(function()
{
if(playOrder.includes("vod")){
tryToVODPlay(streamId, token, subscriberId, subscriberCode, vodNoStreamCallback, playType);
}
}, 3000);
}
function dashNoStreamCallback()
{
genericCallback("dash");
}
function setHLSElementsVisibility(show){
document.getElementById("video_container").style.display= show == true ? "block" : "none";
}
function hideWebRTCElements(){
setWebRTCElementsVisibility(false);
document.getElementById("play_button").style.display="none";
}
function setWebRTCElementsVisibility(show) {
document.getElementById("remoteVideo").style.display = show == true ? "block" : "none";
}
function setPlaceHolderVisibility(show) {
placeHolder.style.display = show == true ? "block" : "none";
}
function playWebRTCVideo() {
setWebRTCElementsVisibility(true);
if(mute){
document.getElementById("remoteVideo").muted=true;
}
else{
document.getElementById("remoteVideo").muted=false;
}
if(autoPlay){
document.getElementById("remoteVideo").play().then(function(value){
//autoplay started
document.getElementById("play_button").style.display="none";
}).catch(function(error) {
document.getElementById("play_button").style.display="block";
console.log("User interaction needed to start playing");
});
}
}
function initializePlayer(streamId, extension, token, subscriberId, subscriberCode) {
hideWebRTCElements();
startPlayer(streamId, extension, token, subscriberId, subscriberCode)
}
window.initializePlayer = initializePlayer
window.playWebRTCVideo = playWebRTCVideo
function startPlayer(streamId, extension, token, subscriberId, subscriberCode) {
var type;
var liveStream = false;
if (extension == "mp4") {
type = "video/mp4";
liveStream = false;
}
else if (extension == "webm") {
type = "video/webm";
liveStream = false;
}
else if(extension == "mov"){
type = "video/mp4";
alert("Browsers do not support to play mov format");
liveStream = false;
}
else if(extension == "avi"){
type = "video/mp4";
alert("Browsers do not support to play avi format");
liveStream = false;
}
else if (extension == "m3u8") {
type = "application/x-mpegURL";
liveStream = true;
}
else if (extension == "mpd") {
type = "application/dash+xml";
liveStream = true;
}
else {
console.log("Unknown extension: " + extension);
return;
}
var preview = streamId;
if (streamId.endsWith("_adaptive")) {
preview = streamId.substring(0, streamId.indexOf("_adaptive"));
}
// If it's not dash, play with videojs
if(extension != dashExtension){
var player = videojs('video-player', {
poster: "previews/"+preview+".png"
});
player.src({
src: "streams/" + streamId + "." + extension + "?token=" + token + "&subscriberId="+subscriberId +"&subscriberCode="+subscriberCode,
type: type,
withCredentials: true,
});
player.poster("previews/"+preview+".png");
if(mute){
player.muted(true);
}
else{
player.muted(false);
}
if (autoPlay) {
player.ready(function() {
player.play();
});
}
}else{
var player = dashjs.MediaPlayer().create();
player.updateSettings({'streaming': {'lowLatencyEnabled': true}});
player.updateSettings({
'streaming': {
'liveDelay': targetLatency,
'liveCatchUpMinDrift': 0.05,
'liveCatchUpPlaybackRate': 0.5,
"liveCatchupLatencyThreshold": 30,
}
});
player.initialize(document.querySelector("#video-player"), "streams/" + streamId + "." + extension + "?token=" + token, false);
if(mute){
player.setMute(true);
}
else{
player.setMute(false);
}
if (autoPlay && player.isReady()) {
player.play();
}
setInterval(function() {
console.log("live latency: " + player.getCurrentLiveLatency());
}, 2000);
}
//Check HLS player is finished. If finished page should be reload
if (typeof player.ready != "undefined" )
{
player.ready(function(){
var player = this;
player.on('ended', function() {
console.log("Playing has been finished");
hideWebRTCElements();
setHLSElementsVisibility(false);
setPlaceHolderVisibility(true);
tryToPlay(streamId, token, hlsExtension, subscriberId, subscriberCode, hlsNoStreamCallback);
});
});
}
else {
console.log("player ready is not available. List playing may not be continous");
}
setHLSElementsVisibility(true);
setWebRTCElementsVisibility(false);
setPlaceHolderVisibility(false);
}
function initializeWebRTCPlayer(streamId, token, subscriberId, subscriberCode, noStreamCallback) {
setHLSElementsVisibility(false);
var pc_config = {
'iceServers' : [ {
'urls' : 'stun:stun1.l.google.com:19302'
} ]
};
var sdpConstraints = {
OfferToReceiveAudio : true,
OfferToReceiveVideo : true
};
var mediaConstraints = {
video : false,
audio : false
};
var appName = location.pathname.substring(0, location.pathname.lastIndexOf("/")+1);
var path = location.hostname + ":" + location.port + appName + "websocket";
var websocketURL = "ws://" + path;
if (location.protocol.startsWith("https")) {
websocketURL = "wss://" + path;
}
//webRTCAdaptor is a global variable
webRTCAdaptor = new WebRTCAdaptor({
websocket_url : websocketURL,
mediaConstraints : mediaConstraints,
peerconnection_config : pc_config,
sdp_constraints : sdpConstraints,
remoteVideoId : "remoteVideo",
isPlayMode: true,
debug: true,
callback : function(info, description) {
if (info == "initialized") {
console.log("initialized");
webRTCAdaptor.getStreamInfo(streamId);
}
else if (info == "streamInformation") {
console.log("stream information");
webRTCAdaptor.play(streamId, token, subscriberId, subscriberCode);
}
else if (info == "play_started") {
//joined the stream
console.log("play started");
setPlaceHolderVisibility(false);
setHLSElementsVisibility(false);
playWebRTCVideo();
} else if (info == "play_finished") {
//leaved the stream
console.log("play finished");
setHLSElementsVisibility(false);
hideWebRTCElements();
setPlaceHolderVisibility(true);
//check that publish may start again
/*setTimeout(function(){
webRTCAdaptor.getStreamInfo(streamId);
}, 3000);
*/
}
else if (info == "closed") {
//console.log("Connection closed");
if (typeof description != "undefined") {
console.log("Connecton closed: " + JSON.stringify(description));
}
}
else if (info == "bitrateMeasurement") {
if(!document.getElementById("remoteVideo").paused){
document.getElementById("play_button").style.display="none";
}
console.debug(description);
if(description.audioBitrate + description.videoBitrate > description.targetBitrate)
{
document.getElementById("networkWarning").style.display = "block";
setTimeout(function() {
document.getElementById("networkWarning").style.display = "none";
}, 3000);
}
}
},
callbackError : function(error) {
//some of the possible errors, NotFoundError, SecurityError,PermissionDeniedError
console.log("error callback: " + JSON.stringify(error));
if (error == "no_stream_exist" ) {
if (typeof noStreamCallback != "undefined") {
noStreamCallback();
}
}
if (error == "notSetRemoteDescription" ) {
/*
* If getting codec incompatible or remote description error, it will redirect HLS player.
*/
tryToPlay(streamId, token, hlsExtension, subscriberId, subscriberCode, hlsNoStreamCallback);
}
}
});
}
if (streamId != "undefined")
{
if (streamId.startsWith(streamsFolder))
{
/*
* If streamId starts with streams, it's hls or mp4 file to be played
*/
var lastIndexOfDot = streamId.lastIndexOf(".")
var streamPath = streamId.substring(streamsFolder.length+1, lastIndexOfDot);
var extension = streamId.substring(lastIndexOfDot+1);
initializePlayer(streamPath, extension, token);
}
else {
/*
* Check that which one is in the first order
*/
/*
if (playOrder[0] == "webrtc" )
{
initializeWebRTCPlayer(streamId, token, subscriberId, subscriberCode, webrtcNoStreamCallback);
}
else if (playOrder[0] == "hls" )
{
tryToPlay(streamId, token, hlsExtension, subscriberId, subscriberCode, hlsNoStreamCallback);
}
else if (playOrder[0] == "vod" )
{
tryToVODPlay(streamId, token, subscriberId, subscriberCode, vodNoStreamCallback, playType);
}
else if (playOrder[0] == "dash" )
{
tryToPlay(streamId, token, dashExtension, subscriberId, subscriberCode, dashNoStreamCallback);
}
else {
alert("Unsupported play order requested. Supported formats are webrtc and hls. Use something like playOrder=webrtc,hls");
}
*/
}
}
else {
alert("No stream specified. Please add ?id={STREAM_ID} to the url");
}
setInterval(function() {
fetch("http://localhost:5080/WebRTCAppEE/rest/v2/broadcasts/" + streamId, {method: 'GET'})
.then(function(response) {
if (response.status == 200) {
return response.json();
}
return null;
}).then(function(stream){
if (stream != null) {
console.log(stream);
if (stream.status == "broadcasting" ) {
if (stream.speed > 0.9) {
//play webrtc if it's no playing
var display = document.getElementById("remoteVideo").style.display;
console.log("display of the stream: " + display);
if (display == "" || display == "none") {
initializeWebRTCPlayer(streamId, token, subscriberId, subscriberCode, webrtcNoStreamCallback);
}
}
else {
if (webRTCAdaptor != null) {
webRTCAdaptor.stop();
}
//show placeholder
setPlaceHolderVisibility(true);
}
}
else {
//stop and hide all players
if (webRTCAdaptor != null) {
webRTCAdaptor.stop();
}
//show placeholder
setPlaceHolderVisibility(true);
console.log("stream is offline");
}
}
else {
//stop and hide all players
if (webRTCAdaptor != null) {
webRTCAdaptor.stop();
}
//show placeholder
setPlaceHolderVisibility(true);
console.log("there is no stream with the stream id: " + streamId);
}
});
}, 5000);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment