RTCPeerConnection.ontrack never runs. Trying to create a meet app

17 views Asked by At

I am trying to create a meeting backend system just like google meet, i did the backend part but i was facing diffculties while setting up Video Calling feature using RTCPeerConnection. Everything else work accept ontrack (that's the main part I agree :) ).

I was expecting that after calling peerConnection.addTrack, peerConnection.ontrack should also get fired on other client. But it was not getting called.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
    <title>Spring Boot WebSocket Chat Application</title>
    <link rel="stylesheet" href="/css/main.css"/>
</head>
<body>
<noscript>
    <h2>Sorry! Your browser doesn't support Javascript</h2>
</noscript>

<div id="username-page">
    <div class="username-page-container">
        <h1 class="title">Type your username and room ID to enter the Chatroom</h1>
        <form id="usernameForm" name="usernameForm">
            <div class="form-group">
                <input type="text" id="name" placeholder="Username" autocomplete="off" class="form-control"/>
            </div>
            <div class="form-group">
                <input type="text" id="roomID" placeholder="Room ID" autocomplete="off" class="form-control"/>
            </div>
            <div class="form-group">
                <button type="submit" class="accent username-submit">Start Chatting</button>
            </div>
        </form>
    </div>
</div>

<div id="chat-page" class="hidden">
    <div class="chat-container">
        <div class="chat-header">
            <h2>Spring WebSocket Chat Demo - By Dhruv</h2>
        </div>
        <div id="video-container">
            <video id="localVideo" autoplay muted></video>
            <video id="remoteVideo" autoplay></video>
        </div>
        <button id="toggleVideo" class="accent">Start Video</button>
        <div class="connecting">
            Connecting...
        </div>
        <ul id="messageArea">
        </ul>
        <form id="messageForm" name="messageForm">
            <div class="form-group">
                <div class="input-group clearfix">
                    <input type="text" id="message" placeholder="Type a message..." autocomplete="off"
                           class="form-control"/>
                    <button type="submit" class="primary">Send</button>
                </div>
            </div>
        </form>
        <button id="leaveButton" class="accent">Leave Room</button>
    </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<script>
    'use strict';

    var usernamePage = document.querySelector('#username-page');
    var chatPage = document.querySelector('#chat-page');
    var usernameForm = document.querySelector('#usernameForm');
    var messageForm = document.querySelector('#messageForm');
    var messageInput = document.querySelector('#message');
    var messageArea = document.querySelector('#messageArea');
    var connectingElement = document.querySelector('.connecting');
    var leaveButton = document.querySelector('#leaveButton');


    var stompClient = null;
    var username = null;
    var roomId = null;

    // VIDEO CALL CODE START
    var localVideo = document.getElementById('localVideo');
    var remoteVideo = document.getElementById('remoteVideo');
    var conn = new WebSocket('ws://localhost:8080/ws_av');

    conn.onopen = function () {
        console.log("Connected to the signaling server");
        initialize();
    };

    conn.onmessage = function (msg) {
        console.log("Got message", msg);
        var content = JSON.parse(msg.data);
        var data = content.data;
        switch (content.event) {
            // when somebody wants to call us
            case "offer":
                handleOffer(data);
                break;
            case "answer":
                handleAnswer(data);
                break;
            // when a remote peer sends an ice candidate to us
            case "candidate":
                handleCandidate(data);
                break;
            default:
                break;
        }
    };

    function send(message) {
        conn.send(JSON.stringify(message));
    }

    var peerConnection;
    var dataChannel;

    function initialize() {

        var configuration = {
            iceServers: [
                { urls: "stun:stun.l.google.com:19302" }, // Google's public STUN server
                { urls: "stun:stun1.l.google.com:19302" }, // Additional Google's public STUN server
                { urls: "stun:stun2.l.google.com:19302" } // Additional Google's public STUN server
            ]
        }

        peerConnection = new RTCPeerConnection(configuration);

        // Setup ice handling
        peerConnection.onicecandidate = function (event) {
            if (event.candidate) {
                send({
                    event: "candidate",
                    data: event.candidate
                });
            }
        };

        // creating data channel
        dataChannel = peerConnection.createDataChannel("dataChannel", {
            reliable: true
        });

        dataChannel.onerror = function (error) {
            console.log("Error occured on datachannel:", error);
        };

        // when we receive a message from the other peer, printing it on the console
        dataChannel.onmessage = function (event) {
            console.log("message:", event.data);
        };

        dataChannel.onclose = function () {
            console.log("data channel is closed");
        };

        peerConnection.ondatachannel = function (event) {
            dataChannel = event.channel;
            console.log("Data channel is created!");
        };

        peerConnection.addEventListener(
            "track",
            (e) => {
                console.log("remote track added");
                remoteVideo.srcObject = e.streams[0];
            },
            false,
        );

    }

    var isVideoEnabled = false; // Track video state
    var localStream;
    async function startVideoStream() {
        if (isVideoEnabled) return; // Don't start if already enabled
        const constraints = {
            video: true, audio: true
        };
        localStream = await navigator.mediaDevices.getUserMedia(constraints);
        localVideo.srcObject = localStream;
        localStream.getTracks().forEach(track => (peerConnection.addTrack(track, localStream)));
        console.log("Track added");
        sendAvMessage("aklsdjflajsl;djfl;ajsdl;k");
    }

    function stopVideoStream() {
        if (!isVideoEnabled) return; // Don't stop if not enabled

        localVideo.srcObject.getTracks().forEach(track => track.stop());
        localVideo.srcObject = null;
        isVideoEnabled = false;
        toggleVideoButton.textContent = "Start Video";
    }

    // Get a reference to the button
    var toggleVideoButton = document.getElementById('toggleVideo');

    toggleVideoButton.addEventListener('click', function () {
        if (isVideoEnabled) {
            stopVideoStream();
        } else {
            startVideoStream();
        }
    });

    function createOffer() {
        peerConnection.createOffer(function (offer) {
            send({
                event: "offer",
                data: offer,
                offerToReceiveAudio: 1,
                offerToReceiveVideo: 1
            });
            peerConnection.setLocalDescription(offer);
        }, function (error) {
            alert("Error creating an offer");
        });
    }

    function handleOffer(offer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(offer));

        // create and send an answer to an offer
        peerConnection.createAnswer(function (answer) {
            peerConnection.setLocalDescription(answer);
            send({
                event: "answer",
                data: answer
            });
        }, function (error) {
            alert("Error creating an answer");
        });

    }

    function handleCandidate(candidate) {
        peerConnection.addIceCandidate(new RTCIceCandidate(candidate));
    }

    function handleAnswer(answer) {
        peerConnection.setRemoteDescription(new RTCSessionDescription(answer));
        console.log("connection established successfully!!");
    }

    function sendAvMessage(message) {
        dataChannel.send(message);
    }


    // VIDEO CALL CODE END


    function connect(event) {
        username = document.querySelector('#name').value.trim();
        roomId = document.querySelector('#roomID').value.trim(); // Fetch room ID entered by the user

        if (username && roomId) {
            usernamePage.classList.add('hidden');
            chatPage.classList.remove('hidden');

            var socket = new SockJS('/ws');
            stompClient = Stomp.over(socket);

            createOffer();

            stompClient.connect({}, onConnected, onError);
        }
        event.preventDefault();
    }

    function onConnected() {
        // Subscribe to the Room Topic
        stompClient.subscribe('/topic/room/' + roomId, onMessageReceived); // Use the dynamic room ID entered by the user

        // Tell your username to the server
        var joinMessage = {
            sender: username,
            signalType: 'JOIN',
            roomId: roomId // Use the dynamic room ID entered by the user
        };
        stompClient.send("/app/sendSignal", {}, JSON.stringify(joinMessage));

        connectingElement.classList.add('hidden');
    }

    function onError(error) {
        connectingElement.textContent = 'Could not connect to WebSocket server. Please refresh this page to try again!';
        connectingElement.style.color = 'red';
    }

    function sendMessage(event) {
        var messageContent = messageInput.value.trim();
        console.log(messageContent);
        if (messageContent && stompClient) {
            var chatMessage = {
                sender: username,
                signalType: 'CHAT',
                chatMessage: messageInput.value,
                roomId: roomId // Use the dynamic room ID entered by the user
            };
            stompClient.send("/app/sendSignal", {}, JSON.stringify(chatMessage));
            messageInput.value = '';
        }
        event.preventDefault();
    }

    function leaveRoom(event) {
        var leaveMessage = {
            sender: username,
            signalType: 'LEAVE',
            roomId: roomId // Use the dynamic room ID entered by the user
        };
        stompClient.send("/app/sendSignal", {}, JSON.stringify(leaveMessage));
        stompClient.disconnect();
        // Clear username and room ID and show username page
        username = null;
        roomId = null;
        usernamePage.classList.remove('hidden');
        chatPage.classList.add('hidden');
        event.preventDefault();
    }

    function onMessageReceived(payload) {
        var message = JSON.parse(payload.body);
        var messageElement = document.createElement('li');
        console.log("MESSAGE RECEIVED: ", message);
        if (message.signalType === 'JOIN') {
            messageElement.classList.add('event-message');
            message.chatMessage = message.sender + ' joined the meet!';
        } else if (message.signalType === 'LEAVE') {
            messageElement.classList.add('event-message');
            message.chatMessage = message.sender + ' left the meet!';
        } else {
            messageElement.classList.add('chat-message');
            var usernameElement = document.createElement('span');
            var usernameText = document.createTextNode(message.sender + ': ');
            usernameElement.appendChild(usernameText);
            messageElement.appendChild(usernameElement);
        }

        var textElement = document.createElement('span');
        var messageText = document.createTextNode(message.chatMessage);
        textElement.appendChild(messageText);
        messageElement.appendChild(textElement);

        messageArea.appendChild(messageElement);
        messageArea.scrollTop = messageArea.scrollHeight;
    }

    usernameForm.addEventListener('submit', connect, true);
    messageForm.addEventListener('submit', sendMessage, true);
    leaveButton.addEventListener('click', leaveRoom, true);
</script>
</body>
</html>
0

There are 0 answers