<!DOCTYPE>
<!--Solving idea thymeleaf expression templates reporting red wavy lines-->
<!--suppress ALL -->
<html xmlns:th="">
<head>
<meta charset="UTF-8">
<title>WebRTC + WebSocket</title>
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
<style>
html,body{
margin: 0;
padding: 0;
}
#main{
position: absolute;
width: 370px;
height: 550px;
}
#localVideo{
position: absolute;
background: #757474;
top: 10px;
right: 10px;
width: 100px;
height: 150px;
z-index: 2;
}
#remoteVideo{
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background: #222;
}
#buttons{
z-index: 3;
bottom: 20px;
left: 90px;
position: absolute;
}
#toUser{
border: 1px solid #ccc;
padding: 7px 0px;
border-radius: 5px;
padding-left: 5px;
margin-bottom: 5px;
}
#toUser:focus{
border-color: #66afe9;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)
}
#call{
width: 70px;
height: 35px;
background-color: #00BB00;
border: none;
margin-right: 25px;
color: white;
border-radius: 5px;
}
#hangup{
width:70px;
height:35px;
background-color:#FF5151;
border:none;
color:white;
border-radius: 5px;
}
</style>
</head>
<body>
<div id="main">
<video id="remoteVideo" playsinline autoplay></video>
<video id="localVideo" playsinline autoplay muted></video>
<div id="buttons">
<input id="toUser" placeholder= "Enter online friend account"/><br/>
<button id="call">video call</button>
<button id="hangup">hang up (a phone)</button>
</div>
</div>
</body>
<!-- may be invoked or not-->
<!--<script th:src="@{/js/}"></script>-->
<script type="text/javascript" th:inline="javascript">
let username = "fanly";
let localVideo = ('localVideo');
let remoteVideo = ('remoteVideo');
let websocket = null;
let peer = null;
WebSocketInit();
ButtonFunInit();
/* WebSocket */
function WebSocketInit(){
//Determine whether the current browser supports WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://127.0.0.1:961/device/chat?name="+username);
} else {
alert("WebSocket is not supported by the current browser!");
}
//Callback methods for connection errors
= function (e) {
alert("An error occurred in the WebSocket connection!");
};
//Callback method for connection closure
= function () {
("WebSocket connection closure");
};
//Callback method for successful connection establishment
= function () {
("WebSocket connection successful");
};
//The callback method that receives the message
= async function (event) {
let { type, fromUser, msg, sdp, iceCandidate } = ((/\n/g,"\\n").replace(/\r/g,"\\r"));
(type);
if (type === 'hangup') {
(msg);
('hangup').click();
return;
}
if (type === 'call_start') {
let msg = "0"
if(confirm(fromUser + "Initiate a video call, sure to answer?")==true){
('toUser').value = fromUser;
WebRTCInit();
msg = "1"
}
(({
type:"call_back",
toUser:fromUser,
fromUser:username,
msg:msg
}));
return;
}
if (type === 'call_back') {
if(msg === "1"){
(('toUser').value + "Agree to video calls");
//Create local videos and send offers
let stream = await ({ video: true, audio: true })
= stream;
().forEach(track => {
(track, stream);
});
let offer = await ();
await (offer);
let newOffer = offer;
newOffer["fromUser"] = username;
newOffer["toUser"] = ('toUser').value;
((newOffer));
}else if(msg === "0"){
alert(('toUser').value + "Rejection of video calls");
('hangup').click();
}else{
alert(msg);
('hangup').click();
}
return;
}
if (type === 'offer') {
let stream = await ({ video: true, audio: true });
= stream;
().forEach(track => {
(track, stream);
});
await (new RTCSessionDescription({ type, sdp }));
let answer = await ();
let newAnswer = answer;
newAnswer["fromUser"] = username;
newAnswer["toUser"] = ('toUser').value;
((newAnswer));
await (answer);
return;
}
if (type === 'answer') {
(new RTCSessionDescription({ type, sdp }));
return;
}
if (type === '_ice') {
(iceCandidate);
return;
}
}
}
/* WebRTC */
function WebRTCInit(){
peer = new RTCPeerConnection();
//ice
= function (e) {
if () {
(({
type: '_ice',
toUser:('toUser').value,
fromUser:username,
iceCandidate:
}));
}
};
//track
= function (e) {
if (e && ) {
= [0];
}
};
}
/* pushbutton event*/
function ButtonFunInit(){
//video call
('call').onclick = function (e){
('toUser'). = 'hidden';
let toUser = ('toUser').value;
if(!toUser){
alert("Please specify your friend's account before initiating a video call!");
return;
}
if(peer == null){
WebRTCInit();
}
(({
type:"call_start",
fromUser:username,
toUser:toUser,
}));
}
//hang up (a phone)
('hangup').onclick = function (e){
('toUser'). = 'unset';
if(){
const videoTracks = ();
(videoTrack => {
();
(videoTrack);
});
}
if(){
const videoTracks = ();
(videoTrack => {
();
(videoTrack);
});
//Hang up and notify the other party at the same time
(({
type:"hangup",
fromUser:username,
toUser:('toUser').value,
}));
}
if(peer){
= null;
= null;
= null;
= null;
= null;
= null;
= null;
= null;
();
peer = null;
}
= null;
= null;
}
}
</script>
</html>