WebSocket Using WebRTC easy to implement peer to peer video calling. But how to implement group video calling using WebRTC and WebSocket in Spring Boot.?
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import com.call.event.ConnectionHandler;
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ConnectionHandler(), "/call").setAllowedOrigins("*");
}
}
ConnectionHandler Here Socket Handler.We handle all user session and socket and payoads.
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
System.out.println("Got signal - " + message.getPayload());
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
@Component
public class ConnectionHandler extends TextWebSocketHandler {
List<WebSocketSession>sessions = new CopyOnWriteArrayList<>();
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
System.out.println("Got signal - " + message.getPayload());
for (WebSocketSession webSocketSession : sessions) {
if (webSocketSession.isOpen() && !session.getId().equals(webSocketSession.getId())) {
webSocketSession.sendMessage(message);
}
}
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
System.out.println("-----------------------------------------------------------------------------");
System.out.println("Connection opened!");
System.out.println("-----------------------------------------------------------------------------");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("-----------------------------------------------------------------------------");
System.out.println("Connection Closed!");
System.out.println("-----------------------------------------------------------------------------");
sessions.add(session);
}
}
WebRTC code Here WebRTC code for Peer to Peer connection. We using webRTC for getUserMedia and DataChanells.
let peerConnection=null;
let localVideo;
let localStream;
let videoTrack;
let audioTrack;
let stream;
let signal;
var signalingWebsocket = new WebSocket("ws://localhost:8080/call");
signalingWebsocket.onmessage = function(msg) {
console.log("Got message", msg.data);
signal = JSON.parse(msg.data);
switch (signal.type) {
case "offer":
handleOffer(signal);
break;
case "answer":
handleAnswer(signal);
break;
// In local network, ICE candidates might not be generated.
case "candidate":
handleCandidate(signal);
break;
default:
break;
}
};
signalingWebsocket.onopen = init();
function sendSignal(signal) {
if (signalingWebsocket.readyState == 1) {
signalingWebsocket.send(JSON.stringify(signal));
}
};
/*
* Initialize
*/
function init() {
console.log("Connected to signaling endpoint. Now initializing.");
preparePeerConnection();
displayLocalStream(true);
};
/*
* Prepare RTCPeerConnection & setup event handlers.
*/
function preparePeerConnection() {
// Using free public google STUN server.
const configuration = {
iceServers: [{
urls: 'stun:stun.l.google.com:19302'
}]
};
// Prepare peer connection object
peerConnection = new webkitRTCPeerConnection(configuration, {optional: [{RtpDataChannels: true}]});
peerConnection.onnegotiationneeded = async () => {
console.log('onnegotiationneeded');
sendOfferSignal();
};
peerConnection.onicecandidate = function(event) {
if (event.candidate) {
sendSignal(event);
}
};
peerConnection.addEventListener('track', displayRemoteStream);
};
async function displayLocalStream(firstTime) {
console.log('Requesting local stream');
localVideo = document.getElementById('localVideo');
try {
stream = await navigator.mediaDevices.getUserMedia({
video: {
width: 500,
height: 300
},
audio: false
});
console.log('Received local stream');
localVideo.srcObject = stream;
localStream = stream;
videoAudioTrackInfo(localStream);
console.log(stream);
// For first time, add local stream to peer connection.
if (firstTime) {
setTimeout(
function() {
addLocalStreamToPeerConnection(localStream);
}, 2000);
}
// Send offer signal to signaling server endpoint.
sendOfferSignal();
} catch (e) {
alert(`getUserMedia() error: ${e.name}`);
throw e;
}
console.log('Start complete');
}
function videoAudioTrackInfo(localStream) {
videoTrack = localStream.getVideoTracks();
audioTrack = localStream.getAudioTracks();
if (videoTrack.length > 0) {
console.log(`Using video device: ${videoTrack[0].label}`);
}
if (audioTrack.length > 0) {
console.log(`Using audio device: ${audioTrack[0].label}`);
}
}
async function addLocalStreamToPeerConnection(localStream) {
console.log('Starting addLocalStreamToPeerConnection');
localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
console.log('localStream tracks added');
};
function sendOfferSignal() {
peerConnection.createOffer(function(offer) {
sendSignal(offer);
peerConnection.setLocalDescription(offer);
}, function(error) {
alert("Error creating an offer");
});
};
function handleOffer(offer) {
peerConnection.setRemoteDescription(new RTCSessionDescription(offer));
peerConnection.createAnswer(function(answer) {
peerConnection.setLocalDescription(answer);
sendSignal(answer);
}, function(error) {
alert("Error creating an answer");
});
};
function handleAnswer(answer) {
peerConnection.setRemoteDescription(new RTCSessionDescription(answer));
console.log("connection established successfully!!");
};
function handleCandidate(candidate) {
alert("handleCandidate");
peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
};
function displayRemoteStream(e) {
console.log('displayRemoteStream');
const remoteVideo = document.getElementById('remoteVideo');
if (remoteVideo.srcObject !== e.streams[0]) {
remoteVideo.srcObject = e.streams[0];
console.log('pc2 received remote stream');
}
};
function leaveMeeting() {
let cnf=confirm("Are you sure for leave meeting!")
if(cnf==true){
console.log('Ending call');
peerConnection.close();
signalingWebsocket.close();
window.location.href = '/';
}else{
console.log('you are in meeting....');
}
};