Created
March 31, 2020 10:25
-
-
Save mekya/1272449b72119745bc78333270e0c47c to your computer and use it in GitHub Desktop.
Canvas publish to Ant Media Server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%@ page language="java" contentType="text/html; charset=UTF-8" | |
pageEncoding="UTF-8"%> | |
<html> | |
<head> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta charset="UTF-8"> | |
<link rel="stylesheet" | |
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" | |
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" | |
crossorigin="anonymous"> | |
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> | |
<script src="js/webrtc_adaptor.js"></script> | |
<script | |
src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | |
<style> | |
video { | |
width: 100%; | |
max-width: 640px; | |
} | |
/* Space out content a bit */ | |
body { | |
padding-top: 20px; | |
padding-bottom: 20px; | |
} | |
/* Everything but the jumbotron gets side spacing for mobile first views */ | |
.header, .marketing, .footer { | |
padding-right: 15px; | |
padding-left: 15px; | |
} | |
/* Custom page header */ | |
.header { | |
padding-bottom: 20px; | |
border-bottom: 1px solid #e5e5e5; | |
} | |
/* Make the masthead heading the same height as the navigation */ | |
.header h3 { | |
margin-top: 0; | |
margin-bottom: 0; | |
line-height: 40px; | |
} | |
/* Custom page footer */ | |
.footer { | |
padding-top: 19px; | |
color: #777; | |
border-top: 1px solid #e5e5e5; | |
} | |
/* Customize container */ | |
@media ( min-width : 768px) { | |
.container { | |
max-width: 730px; | |
} | |
} | |
.container-narrow>hr { | |
margin: 30px 0; | |
} | |
/* Main marketing message and sign up button */ | |
.jumbotron { | |
text-align: center; | |
border-bottom: 1px solid #e5e5e5; | |
} | |
/* Responsive: Portrait tablets and up */ | |
@media screen and (min-width: 768px) { | |
/* Remove the padding we set earlier */ | |
.header, .marketing, .footer { | |
padding-right: 0; | |
padding-left: 0; | |
} | |
/* Space out the masthead */ | |
.header { | |
margin-bottom: 30px; | |
} | |
/* Remove the bottom border on the jumbotron for visual effect */ | |
.jumbotron { | |
border-bottom: 0; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header clearfix"> | |
<nav> | |
<ul class="nav navbar-pills pull-right"> | |
<li><a href="http://antmedia.io">Contact</a></li> | |
</ul> | |
</nav> | |
<h3 class="text-muted">WebRTC Publish</h3> | |
</div> | |
<div class="jumbotron"> | |
<canvas id="canvas" width="150" height="150"></canvas> | |
<p> | |
<video id="localVideo" autoplay muted controls playsinline></video> | |
</p> | |
<p> | |
<input type="text" class="form-control" value="stream1" | |
id="streamName" placeholder="Type stream name"> | |
<div class="form-check"> | |
<input class="form-check-input" checked="true" onchange="switchMode(event.target)" type="radio" value="" | |
id="camera_checkbox"> | |
<label class="form-check-label" for="camera_checkbox" style="font-weight:normal"> | |
Camera | |
</label> <br/> | |
<input class="form-check-input" disabled onchange="switchMode(event.target)" type="radio" value="" | |
id="screen_share_checkbox"> | |
<label class="form-check-label" for="screen_share_checkbox" style="font-weight:normal"> | |
Screen Share | |
</label> | |
<br/> | |
<input class="form-check-input" disabled onchange="switchMode(event.target)" type="radio" value="" | |
id="screen_share_with_camera_checkbox"> | |
<label class="form-check-label" for="screen_share_with_camera_checkbox" style="font-weight:normal"> | |
Screen Share with Camera | |
</label> | |
<br/> | |
<a id="browser_screen_share_doesnt_support" href="https://caniuse.com/#search=getDisplayMedia">Your browser doesn't support screen share. You can see supported browsers in this link </a> | |
</div> | |
</p> | |
<p> | |
<button onclick="startPublishing()" class="btn btn-info" disabled | |
id="start_publish_button">Start Publishing</button> | |
<button onclick="stopPublishing()" class="btn btn-info" disabled | |
id="stop_publish_button">Stop Publishing</button> | |
</p> | |
<span class="label label-success" id="broadcastingInfo" style="font-size:14px;display:none" | |
style="display: none">Publishing</span> | |
</div> | |
<footer class="footer"> | |
<p><a href="http://antmedia.io">Ant Media Server Enterprise Edition</a></p> | |
</footer> | |
</div> | |
</body> | |
<script> | |
var canvas = document.getElementById('canvas'); | |
function draw() { | |
if (canvas.getContext) { | |
var ctx = canvas.getContext('2d'); | |
ctx.fillStyle = 'rgb(200, 0, 0)'; | |
ctx.fillRect(10, 10, 50, 50); | |
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'; | |
ctx.fillRect(30, 30, 50, 50); | |
} | |
} | |
//update canvas for every 40ms | |
setInterval(function() { draw(); }, 40); | |
//capture stream from canvas | |
var localStream = canvas.captureStream(25); | |
//get audio with getUserMedia | |
navigator.mediaDevices.getUserMedia({video: false, audio:true}).then(function (audioStream) { | |
//add audio track to the localstream which is captured from canvas | |
localStream.addTrack(audioStream.getAudioTracks()[0]); | |
//initialize the webRTCAdaptor with the localStream created. | |
//initWebRTCAdaptor method is implemented below | |
initWebRTCAdaptor(localStream); | |
}); | |
var token = "<%= request.getParameter("token") %>"; | |
var camera_checkbox = document.getElementById("camera_checkbox"); | |
var screen_share_checkbox = document.getElementById("screen_share_checkbox"); | |
var screen_share_with_camera_checkbox = document.getElementById("screen_share_with_camera_checkbox"); | |
var start_publish_button = document.getElementById("start_publish_button"); | |
var stop_publish_button = document.getElementById("stop_publish_button"); | |
var install_extension_link = document.getElementById("install_chrome_extension_link"); | |
var streamNameBox = document.getElementById("streamName"); | |
var streamId; | |
function getUrlParameter(sParam) { | |
var sPageURL = decodeURIComponent(window.location.search.substring(1)), | |
sURLVariables = sPageURL.split('&'), | |
sParameterName, | |
i; | |
for (i = 0; i < sURLVariables.length; i++) { | |
sParameterName = sURLVariables[i].split('='); | |
if (sParameterName[0] === sParam) { | |
return sParameterName[1] === undefined ? true : sParameterName[1]; | |
} | |
} | |
}; | |
var name = getUrlParameter("name"); | |
if(name !== "undefined") | |
{ | |
streamNameBox.value = name; | |
} | |
// It should be true | |
var rtmpForward = getUrlParameter("rtmpForward"); | |
function startPublishing() { | |
streamId = streamNameBox.value; | |
webRTCAdaptor.publish(streamId, token); | |
} | |
function stopPublishing() { | |
webRTCAdaptor.stop(streamId); | |
} | |
function switchMode(chbx) { | |
if(camera_checkbox == chbx && camera_checkbox.checked == true){ | |
camera_checkbox.checked = true; | |
screen_share_checkbox.checked = false; | |
screen_share_with_camera_checkbox.checked = false; | |
webRTCAdaptor.switchVideoCapture(streamId); | |
} | |
else if(screen_share_checkbox == chbx && screen_share_checkbox.checked == true ){ | |
camera_checkbox.checked = false; | |
screen_share_checkbox.checked = true; | |
screen_share_with_camera_checkbox.checked = false; | |
webRTCAdaptor.switchDesktopCapture(streamId); | |
} | |
else if(screen_share_with_camera_checkbox == chbx && screen_share_with_camera_checkbox.checked == true){ | |
camera_checkbox.checked = false; | |
screen_share_checkbox.checked = false; | |
screen_share_with_camera_checkbox.checked = true; | |
webRTCAdaptor.switchDesktopCaptureWithCamera(streamId); | |
} | |
else { | |
chbx.checked = true; | |
} | |
} | |
function startAnimation() { | |
$("#broadcastingInfo").fadeIn(800, function () { | |
$("#broadcastingInfo").fadeOut(800, function () { | |
var state = webRTCAdaptor.signallingState(streamId); | |
if (state != null && state != "closed") { | |
var iceState = webRTCAdaptor.iceConnectionState(streamId); | |
if (iceState != null && iceState != "failed" && iceState != "disconnected") { | |
startAnimation(); | |
} | |
} | |
}); | |
}); | |
} | |
var pc_config = null; | |
var sdpConstraints = { | |
OfferToReceiveAudio : false, | |
OfferToReceiveVideo : false | |
}; | |
var mediaConstraints = { | |
video : true, | |
audio : true | |
}; | |
var appName = location.pathname.substring(0, location.pathname.lastIndexOf("/")+1); | |
var path = location.hostname + ":" + location.port + appName + "websocket?rtmpForward=" + rtmpForward; | |
var websocketURL = "ws://" + path; | |
if (location.protocol.startsWith("https")) { | |
websocketURL = "wss://" + path; | |
} | |
var webRTCAdaptor; | |
function initWebRTCAdaptor(stream) { | |
webRTCAdaptor = new WebRTCAdaptor({ | |
websocket_url : websocketURL, | |
mediaConstraints : mediaConstraints, | |
peerconnection_config : pc_config, | |
sdp_constraints : sdpConstraints, | |
localVideoId : "localVideo", | |
localStream: stream, | |
debug:true, | |
callback : function(info, obj) { | |
if (info == "initialized") { | |
console.log("initialized"); | |
start_publish_button.disabled = false; | |
stop_publish_button.disabled = true; | |
} else if (info == "publish_started") { | |
//stream is being published | |
console.log("publish started"); | |
start_publish_button.disabled = true; | |
stop_publish_button.disabled = false; | |
startAnimation(); | |
} else if (info == "publish_finished") { | |
//stream is being finished | |
console.log("publish finished"); | |
start_publish_button.disabled = false; | |
stop_publish_button.disabled = true; | |
} | |
else if (info == "browser_screen_share_supported") { | |
camera_checkbox.disabled = false; | |
screen_share_checkbox.disabled = false; | |
screen_share_with_camera_checkbox.disabled = false; | |
console.log("browser screen share supported"); | |
browser_screen_share_doesnt_support.style.display = "none"; | |
} | |
else if (info == "screen_share_stopped") { | |
camera_checkbox.checked = true; | |
screen_share_checkbox.checked = false; | |
screen_share_with_camera_checkbox.checked = false; | |
console.log("screen share stopped"); | |
} | |
else if (info == "closed") { | |
//console.log("Connection closed"); | |
if (typeof obj != "undefined") { | |
console.log("Connecton closed: " + JSON.stringify(obj)); | |
} | |
} | |
else if (info == "pong") { | |
//ping/pong message are sent to and received from server to make the connection alive all the time | |
//It's especially useful when load balancer or firewalls close the websocket connection due to inactivity | |
} | |
else if (info == "refreshConnection") { | |
startPublishing(); | |
} | |
else if (info == "ice_connection_state_changed") { | |
console.log("iceConnectionState Changed: ",JSON.stringify(obj)); | |
} | |
else if (info == "updated_stats") { | |
//obj is the PeerStats which has fields | |
//averageOutgoingBitrate - kbits/sec | |
//currentOutgoingBitrate - kbits/sec | |
console.log("Average outgoing bitrate " + obj.averageOutgoingBitrate + " kbits/sec" | |
+ " Current outgoing bitrate: " + obj.currentOutgoingBitrate + " kbits/sec"); | |
} | |
}, | |
callbackError : function(error, message) { | |
//some of the possible errors, NotFoundError, SecurityError,PermissionDeniedError | |
console.log("error callback: " + JSON.stringify(error)); | |
var errorMessage = JSON.stringify(error); | |
if (typeof message != "undefined") { | |
errorMessage = message; | |
} | |
var errorMessage = JSON.stringify(error); | |
if (error.indexOf("NotFoundError") != -1) { | |
errorMessage = "Camera or Mic are not found or not allowed in your device"; | |
} | |
else if (error.indexOf("NotReadableError") != -1 || error.indexOf("TrackStartError") != -1) { | |
errorMessage = "Camera or Mic is being used by some other process that does not let read the devices"; | |
} | |
else if(error.indexOf("OverconstrainedError") != -1 || error.indexOf("ConstraintNotSatisfiedError") != -1) { | |
errorMessage = "There is no device found that fits your video and audio constraints. You may change video and audio constraints" | |
} | |
else if (error.indexOf("NotAllowedError") != -1 || error.indexOf("PermissionDeniedError") != -1) { | |
errorMessage = "You are not allowed to access camera and mic."; | |
} | |
else if (error.indexOf("TypeError") != -1) { | |
errorMessage = "Video/Audio is required"; | |
} | |
else if (error.indexOf("ScreenSharePermissionDenied") != -1) { | |
errorMessage = "You are not allowed to access screen share"; | |
camera_checkbox.checked = true; | |
screen_share_checkbox.checked = false; | |
screen_share_with_camera_checkbox.checked = false; | |
} | |
else if (error.indexOf("WebSocketNotConnected") != -1) { | |
errorMessage = "WebSocket Connection is disconnected."; | |
} | |
alert(errorMessage); | |
} | |
}); | |
} | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is it working for you now?