LePhenix47 / Lahouiti_Younes_P13_21062024

This repo contains the code for the a Proof of Concept (PoC) for the "Your car your way" app for the support page using WebSockets for the chat and WebRTC for the videoconference
MIT License
1 stars 0 forks source link

P13: Your car your way WebSockets and WebRTC Proof of Concept (PoC)

Your Car Your Way logo

Description

This Proof of Concept (PoC) demonstrates the feasibility of real-time communication through an online chat and video-conference service, leveraging WebSockets and WebRTC technologies. The PoC aims to validate our proposal by showcasing a seamless exchange between users and customer service representatives, ensuring a robust and interactive user experience.

Why WebSockets & WebRTC?

WebSockets enable persistent, bidirectional communication between the client and server, allowing for instant message delivery and low-latency interactions. WebRTC facilitates peer-to-peer connections for audio, video, and data sharing, ensuring high-quality real-time communication without the need for intermediary servers. By developing this PoC, we aim to reassure stakeholders of the viability and effectiveness of our proposed online chat functionality.

Table of contents

Tech stack for the PoC

Front-End

HTML5 logo

SASS logo

TypeScript logo

Angular logo

Back-End

NodeJS logo

ExpressJS logo

Socket.io logo

Pre-requisites

Node.js

Install Node.js LTS to install dependencies and run both the Front-End and Back-End servers.

Configuration

Node.js

The project requires Node.js version 20.11.0

You can install Node.js also using the node version manager (nvm), after clicking on the latest release and installing the nvm-setup.exe file, you can upgrade or downgrade node version using the nvm commands

Here's the steps:

  1. Check the list of node versions installed:

    nvm ls
    
    # Output example:
    # * 16.15.0 (Currently using 64-bit executable)
  2. Install the node version to upgrade/downgrade to:

      nvm install 20.11.0
  3. Use the freshly installed version:

      nvm ls
      # 20.11.0
      # * 16.13.1 (Currently using 64-bit executable)
    
      nvm use 20.11.0
      # Now using node v20.11.0 (64-bit)

In case it doesn't work:

Go to the nodejs/ folder and slightly rename it, then re-execute nvm use 20.11.0

Installation procedure

Cloning the project: To clone this repository from GitHub, run the following command: git clone https://github.com/LePhenix47/Lahouiti_Younes_P13_21062024 .

Front-End

  1. Install the dependencies:

To start the Angular Front-End project, follow these steps:

cd front
npm install
  1. Starting the server
npm run dev-https

Note: This project is compatible with other JS runtimes such as Bun. If you use one, you can simply run bun dev-https to start the server.

This command will compile the Angular application and start a development server in HTTPS (WebRTC requires a secure context to function correctly). You can then access the application in your browser at https://localhost:4200.

Back-End

  1. Install the dependencies and configure .env file:

To start the NodeJS Back-End project, follow these steps:

cd back
npm install
# Any random address is accepted
LOCAL_IP=
  1. Starting the server
npm start

# If you use the Bun JS runtime you can also use `bun start`

Note: This project is also compatible with alternative JS runtimes like Bun, in which case you can start the server with bun start.

This command will start the NodeJS development server. You can then access the API with: https://localhost:3000.

Features and Limitations

Features

This PoC includes the following features:

Limitations

The PoC has some known limitations:

WebRTC glossary

Understanding the key terms and components in WebRTC is crucial for working with this PoC:

πŸ—ΊοΈ NAT
Network Address Translation (NAT):
NAT is a method used to remap one IP address space into another. It allows multiple devices on a local area network (LAN) to share a single public IP address. This enables private IP addresses (used within the LAN) to be translated into a public IP address, facilitating access to the internet while also providing a level of security by hiding internal network addresses.
πŸ”„ STUN
Session Traversal Utilities for NAT (STUN):
STUN is used to discover the public IP address and port assigned to a device behind a NAT. This information is crucial for ICE candidates to establish a peer-to-peer connection, allowing devices to communicate directly over the internet.
πŸ”„ TURN
Traversal Using Relays around NAT (TURN):
TURN is employed when a direct peer-to-peer connection fails, often due to firewalls or restrictive NAT configurations. It relays media traffic through a server to ensure connectivity between peers, acting as a backup when direct communication is not possible.
❄️ ICE
Interactive Connectivity Establishment (ICE):
ICE is a framework designed to establish peer-to-peer connections by gathering multiple connection candidates (possible network paths) and testing their reachability. These candidates provide information such as IP addresses and ports, representing different network interfaces (e.g., local network, public IP). ICE works in conjunction with STUN servers to discover the public IP address of a peer, and TURN servers to relay data if direct connections fail. The framework resolves issues like Network Address Translation (NAT) traversal, dynamic IP addressing, and VPN usage, ensuring a reliable and efficient connection for media or data exchange between peers.
πŸ“œ SDP
Session Description Protocol (SDP):
SDP is a format used to describe multimedia communication sessions. It provides essential information about the media types, codecs, and connection details required for peers to establish a communication session.
πŸŽ₯ Audio-video P2P
Audio-video Peer-to-Peer (P2P):
P2P communication allows two devices to connect directly to each other for streaming audio and video, bypassing the need for a central server. This enhances performance by reducing latency and improving bandwidth utilization.
πŸ“‘ TCP
Transmission Control Protocol (TCP):
TCP is a protocol that ensures reliable data transmission and cares about data integrity. It establishes a connection and guarantees that packets are delivered in the correct order, are aligned, and are error-free. This makes TCP suitable for applications where data accuracy is essential, such as HTTP and WebSockets.
πŸ“‘ UDP
User Datagram Protocol (UDP):
UDP is a protocol for data transmission that prioritizes speed and low latency, making it ideal for real-time communications like audio and video streams, where quick delivery is prioritized over reliability. It does not guarantee packet order or integrity, allowing some packets to be lost or arrive out of sequence. Although, this enables continuous session flow despite network issues, ensuring that the most recent packets are processed to maintain synchronization, especially in unstable Wi-Fi environments.
πŸ”— Websockets
Websockets:
A protocol that enables two-way communication between a client and a server over a single, long-lived connection. This allows for real-time data exchange and is particularly useful in applications requiring frequent updates, such as chat applications or live notifications.
πŸ“ž Signaling path
Signaling Path:
The signaling path refers to the process of establishing, maintaining, and terminating a connection between peers. It involves the exchange of messages that help peers discover each other, negotiate connection parameters, and handle disconnections. It can be an HTTP request or a WebSockets one
πŸ–₯️ Signaling server
Signaling Server:
A signaling server facilitates the establishment of connections between peers by exchanging signaling messages, which include offers, answers, and ICE candidates. While both HTTP and WebSockets can be used for signaling, WebSockets are preferred due to their support for real-time communication and lower latency.

WebRTC Peer-to-Peer Connection Setup

This document outlines the process of setting up a peer-to-peer connection using WebRTC. The flow includes steps for both the sender and the receiver of the connection.

Get User Media (G.U.M.)

Use getUserMedia() to access the user's camera and microphone, and getDisplayMedia() to access the user's screen.

const ls1 = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); // User's webcam and microphone
const ls2 = await navigator.mediaDevices.getDisplayMedia({ video: true, audio: false  }); // User's screen

Create Peer Connection

Create an RTCPeerConnection object.

const pc = new RTCPeerConnection(stunTurnConfig);

Add Local Tracks to the Connection

Add local media tracks to the peer connection.

ls1.getTracks().forEach(track => pc.addTrack(track));
ls2.getTracks().forEach(track => pc.addTrack(track));

Add Event Listeners to Peer Connection

Listen for various events on the peer connection.

pc.onicecandidate = (event) => { /* Handle ICE candidates */ };
pc.ontrack = (event) => { /* Handle remote track */ };
pc.onnegotiationneeded = (event) => { /* Handle negotiation */ };
pc.onsignalingstatechange = (event) => { /* Debug signaling state */ };

ICE Candidate Event

When an ICE candidate is found, send it to the other peer via the signaling server.

socket.emit("ice-candidate", event.candidate);

ICE Candidate WebSocket Response

When receiving an ICE candidate from the signaling server, add it to the peer connection.

socket.on("ice-candidate", (candidate) => pc.addIceCandidate(candidate));

Sender (offerer)

User Wants to Initiate Call

Create an offer, set the local description, and send the offer via the signaling server.

const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
socket.emit("offer", offer);

Set Remote Description (Answer)

When receiving an answer, set the remote description.

socket.on("answer", async (answer) => {
    await pc.setRemoteDescription(answer);
});

Receiver (answerer)

Set Remote Description (Offer)

When receiving an offer, set the remote description.

socket.on("offer", async (offer) => {
    await pc.setRemoteDescription(offer);
    const answer = await pc.createAnswer();
    await pc.setLocalDescription(answer);
    socket.emit("answer", answer);
});

Create Answer and Set Local Description

Create an answer, set the local description, and send the answer via the signaling server.

On Track Event

When a remote media track is added, handle it by creating a new MediaStream and adding the track to it.

pc.ontrack = (event) => {
    const remoteStream = new MediaStream();
    event.streams[0].getTracks().forEach(track => remoteStream.addTrack(track));
    remoteVideoElement.srcObject = remoteStream;
};

On Negotiation Needed Event

When negotiation is needed, handle it appropriately (e.g., create and send a new offer if necessary).

Frontend (FE)

Backend (BE)

Initiating Peer

Outgoing Events:

  1. Send SDP offer:

    socket.emit('offer', {
     type: 'offer',
     sdp: peerConnection.localDescription
    });
  2. Send ICE candidates:

    peerConnection.onicecandidate = (event) => {
     if (event.candidate) {
       socket.emit('ice-candidate', {
         candidate: event.candidate
       });
     }
    };

Incoming Events:

  1. Receive SDP answer:

    socket.on('answer', async (message) => {
     await peerConnection.setRemoteDescription(new RTCSessionDescription(message));
    });
  2. Receive ICE candidates:

    socket.on('ice-candidate', async (message) => {
     try {
       await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
     } catch (e) {
       console.error('Error adding received ice candidate', e);
     }
    });
Receiving Peer

Outgoing Events:

  1. Send SDP answer:

    socket.emit('answer', {
     type: 'answer',
     sdp: peerConnection.localDescription
    });
  2. Send ICE candidates:

    peerConnection.onicecandidate = (event) => {
     if (event.candidate) {
       socket.emit('ice-candidate', {
         candidate: event.candidate
       });
     }
    };

Incoming Events:

  1. Receive SDP offer:

    socket.on('offer', async (message) => {
     await peerConnection.setRemoteDescription(new RTCSessionDescription(message));
     const answer = await peerConnection.createAnswer();
    
     // Emit the answer, see "Send SDP answer"
    });
  2. Receive ICE candidates:

    socket.on('ice-candidate', async (message) => {
     try {
       await peerConnection.addIceCandidate(new RTCIceCandidate(message.candidate));
     } catch (e) {
       console.error('Error adding received ice candidate', e);
     }
    });

Miscellaneous

πŸ’» WebRTC flow chart WebRTC flow chart [View discussion here](https://github.com/LePhenix47/Lahouiti_Younes_P13_21062024/discussions/12)
πŸ› οΈ Back-End Stack Explanation ### Why Node.js was chosen for the Back-End instead of Java with Spring Boot 1. **Outdated and Complex Libraries**: Using Spring Boot's WebSocket dependencies through Spring Initializer would require [StompJS](https://github.com/stomp-js/stompjs) and [SockJS](https://github.com/sockjs/sockjs-client). While the lack of updates since 2021 makes these libraries difficult to work with on the Back-End, the real annoyance lies in the Front-End. Integrating these libraries on the Front-End is complex and cumbersome. Additionally, this stack does not support sending binary data, and its features are limited compared to modern libraries like [Socket.io](https://github.com/socketio/socket.io). 2. **Socket.io with Spring Boot**: While there is a [Socket.io](https://github.com/socketio/socket.io) implementation for Spring Boot ([Netty-Socket.io](https://github.com/mrniko/netty-socketio)), it comes with a major drawback: the library has had no documentation at all, and that since 2012. This forces reliance on third-party articles and YouTube tutorials, which often lead to configuration issues. Despite attempting to configure it myself, I encountered persistent problems. Given these challenges, Node.js was chosen for WebSocket implementation due to its robust ecosystem and active support.
πŸ” Debugging WebRTC Connections To effectively debug WebRTC connections, instead of relying on manual console logs, you can use the built-in debugging tool available at: chrome://webrtc-internals/. This tool provides detailed insights into the WebRTC connection, including ICE candidates, connection state, and media stream statistics, helping you diagnose issues more efficiently.

Conclusion

This Proof of Concept (PoC) for "Your Car Your Way" successfully demonstrates the capabilities of WebSockets and WebRTC for real-time communication in an online chat and video-conference environment. Through the seamless integration of these technologies, we've showcased the potential to deliver an interactive, high-quality user experience that meets the expectations of modern digital communication.

The PoC validates the feasibility of implementing such technologies in a production environment, offering insights into both the advantages and challenges encountered during development. While the PoC highlights the robustness of WebSockets for instant messaging and WebRTC for video conferencing, it also sheds light on areas that require further refinement, such as connection feedback, memory management, and room handling.

By using Node.js for the Back-End and Angular for the Front-End, we were able to create a responsive and scalable architecture that aligns with current industry standards. The choice of these technologies also provided flexibility and ease of development, making this PoC not only a demonstration of the proposed solution but also a foundation for future enhancements.

In conclusion, this PoC serves as a strong foundation for the next stages of development, offering stakeholders a clear vision of the technical viability and user experience that can be expected in the final implementation. With further iteration and optimization, this approach has the potential to revolutionize how customers and service representatives interact in real-time, delivering a more personalized and efficient service experience.