Introduction to SimpleRealtime Server WebRTC
WebRTC (Web Real-Time Communication) is a powerful technology that enables real-time communication directly within web browsers, making it ideal for video conferencing, live streaming, and peer-to-peer data sharing applications. One of the robust solutions leveraging WebRTC is the SimpleRealtime Server (SRS), an open-source real-time video server.
What is SimpleRealtime Server WebRTC?
The SimpleRealtime Server, commonly referred to as SRS, is a high-performance, feature-rich real-time video server developed using C/C++. It supports various streaming protocols, including HTTP Live Streaming (HLS), Real-Time Messaging Protocol (RTMP), and WebRTC. This versatility makes SRS an excellent choice for developers looking to build scalable and efficient real-time communication applications.
SRS employs a publish (push) and subscribe (play) server model, allowing seamless integration with a wide range of broadcasting and playback scenarios. Whether you're looking to set up a live streaming service, build a video conferencing application, or create an interactive multimedia experience, SRS provides the necessary tools and functionalities.
Key features of SRS include:
- High Performance: Built with C/C++ for optimized performance and low latency.
- Protocol Support: Extensive support for HLS, RTMP, and WebRTC, catering to various streaming needs.
- Scalability: Designed to handle large-scale deployments with ease.
- Flexibility: Easily configurable and extensible to suit specific requirements.
With these capabilities, SRS stands out as a reliable and efficient solution for real-time video communication, empowering developers to create cutting-edge applications with minimal hassle. In the following sections, we'll delve deeper into setting up and configuring SRS, implementing key functionalities, and running your WebRTC application seamlessly.
Getting Started with the Code!
In this section, we will guide you through the initial steps to set up and start working with SimpleRealtime Server (SRS) for WebRTC applications. We'll cover everything from creating a new SRS project to understanding the structure and architecture of your application.
[a] Create a New SimpleRealtime Server WebRTC App
To get started with SRS, you'll first need to create a new project. Here's a step-by-step guide:
[b] Clone the SRS Repository
Begin by cloning the SRS repository from GitHub.
bash
1 git clone https://github.com/ossrs/srs.git
2 cd srs/trunk
[c] Install Dependencies
Make sure you have the necessary dependencies installed. SRS requires tools like Git, CMake, and GCC.
bash
1 sudo apt-get update
2 sudo apt-get install -y git cmake gcc g++
Install SRS
Now that you have the repository, the next step is to install SRS on your system.
[a] Build SRS
Navigate to the trunk directory and run the build script.
bash
1 ./configure
2 make
This command configures the build environment and compiles the SRS source code.
[b] Verify Installation
Once the build process is complete, you can verify the installation by checking the SRS version.
bash
1 ./objs/srs -v
Structure of the Project
Understanding the structure of your SRS project is crucial for effective development. Here's a breakdown of key directories and files:
- trunk: This is the main directory containing all source code and configuration files.
- conf: Contains configuration files for various SRS functionalities.
- objs: Directory where compiled binaries and objects are stored.
- src: Source code of the SRS server, including core functionalities and protocol handling.
- research: Contains experimental features and additional tools for testing and development.
App Architecture
The architecture of an SRS application is designed to be modular and scalable. Key components include:
Core Server
The core server handles the main operations, including session management, data processing, and communication protocols.
Modules
SRS supports various modules for different streaming protocols like RTMP, HLS, and WebRTC. Each module is responsible for handling its specific protocol.
Configuration Files
These files define the settings and parameters for the server and its modules, allowing for customizable and flexible setups.
By following these steps, you will have a functional SRS installation ready for development. The next sections will dive deeper into configuring SRS, implementing essential features, and building a complete WebRTC application.
With the basics covered, you're now prepared to start configuring and coding your SRS WebRTC application. Let's move on to setting up the initial configuration and building out your application's wireframe in the next steps.
Step 1: Get Started with Configuration
Configuring SimpleRealtime Server (SRS) for WebRTC is a critical step to ensure your application runs smoothly. In this section, we'll walk you through the initial configuration process, including key configuration files and parameters necessary for setting up WebRTC with SRS.
[a] Configuring SRS for WebRTC
The first step in configuring SRS is to modify the main configuration file to support WebRTC. The primary configuration file for SRS is
srs.conf
, located in the conf
directory. Here’s a step-by-step guide:[b] Locate the Configuration File
Navigate to the
conf
directory within your SRS installation.bash
1 cd /path/to/srs/trunk/conf
[c] Open the Configuration File
Use a text editor to open
srs.conf
.bash
1 nano srs.conf
[d] Configure WebRTC
Add the following configuration to enable WebRTC in SRS:
1 listen 1935;
2 max_connections 1000;
3 daemon off;
4 srs_log_tank console;
5 srs_log_level trace;
6 http_server {
7 enabled on;
8 listen 8080;
9 dir ./objs/nginx/html;
10 }
11 rtc_server {
12 enabled on;
13 listen 8000;
14 candidate $CANDIDATE;
15 auto_play on;
16 }
17 vhost __defaultVhost__ {
18 rtc {
19 enabled on;
20 }
21 }
[e] Save and Exit
After making these changes, save the file and exit the text editor.
Important Configuration Parameters
- listen: The port number that SRS will listen on for incoming connections. The default is
1935
, commonly used for RTMP. - max_connections: Sets the maximum number of simultaneous connections that SRS will handle.
- http_server: Enables the HTTP server component, necessary for serving WebRTC and other HTTP-based services.
- listen: The port number for the HTTP server.
- dir: The directory from which static files will be served.
- rtc_server: Enables the RTC (Real-Time Communication) server, which handles WebRTC connections.
- listen: The port number for the RTC server.
- candidate: The public IP address or domain name of your server, used for establishing WebRTC connections.
- auto_play: Automatically plays the stream for the clients.
Additional Considerations
Firewall Configuration
Ensure that your server's firewall allows traffic on the ports you've configured (1935 for RTMP, 8000 for RTC, and 8080 for HTTP).
Public IP Address
If your server is behind a NAT or firewall, configure the
candidate
parameter with your public IP address or domain name to ensure WebRTC connections can be established from external clients.By following these configuration steps, you’ve set up your SRS server to handle WebRTC connections. This foundational setup is essential for building and deploying a WebRTC application using SRS.
In the next part, we will move on to wireframing all the components of your application, providing a blueprint for the user interface and user experience. This will set the stage for implementing specific features and functionalities in subsequent steps.
Step 2: Wireframe All the Components
Wireframing your application is an essential step in the development process. It helps you visualize the structure and layout of your app, ensuring that all necessary components are included and correctly positioned. In this section, we’ll create a basic wireframe for our SimpleRealtime Server (SRS) WebRTC application and implement the initial HTML structure.
Creating a Basic Wireframe
The basic components of our SRS WebRTC application will include:
- Join Screen: A screen where users can enter a room ID and join a video conference.
- Control Panel: Controls for muting audio, disabling video, and leaving the call.
- Participant View: A view to display all participants in the video conference.
Here is the HTML structure to wireframe these components
HTML
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>SRS WebRTC App</title>
7 <style>
8 body {
9 font-family: Arial, sans-serif;
10 display: flex;
11 flex-direction: column;
12 align-items: center;
13 justify-content: center;
14 height: 100vh;
15 margin: 0;
16 background-color: #f4f4f4;
17 }
18 .container {
19 width: 80%;
20 max-width: 800px;
21 background: white;
22 padding: 20px;
23 border-radius: 10px;
24 box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
25 }
26 .join-screen, .control-panel, .participant-view {
27 display: none;
28 }
29 .join-screen.active, .control-panel.active, .participant-view.active {
30 display: block;
31 }
32 .join-screen input {
33 width: calc(100% - 22px);
34 padding: 10px;
35 margin-bottom: 10px;
36 border: 1px solid #ccc;
37 border-radius: 5px;
38 }
39 .join-screen button {
40 padding: 10px 20px;
41 border: none;
42 background-color: #007bff;
43 color: white;
44 border-radius: 5px;
45 cursor: pointer;
46 }
47 .control-panel {
48 margin-top: 20px;
49 }
50 .control-panel button {
51 padding: 10px;
52 border: none;
53 background-color: #007bff;
54 color: white;
55 border-radius: 5px;
56 cursor: pointer;
57 margin-right: 10px;
58 }
59 .participant-view {
60 margin-top: 20px;
61 display: flex;
62 flex-wrap: wrap;
63 }
64 .participant-view video {
65 width: 100%;
66 max-width: 200px;
67 margin: 10px;
68 border-radius: 10px;
69 background-color: #000;
70 }
71 </style>
72</head>
73<body>
74 <div class="container">
75 <div class="join-screen active">
76 <h2>Join a Room</h2>
77 <input type="text" id="room-id" placeholder="Enter Room ID">
78 <button onclick="joinRoom()">Join</button>
79 </div>
80 <div class="control-panel">
81 <button onclick="toggleAudio()">Mute/Unmute Audio</button>
82 <button onclick="toggleVideo()">Disable/Enable Video</button>
83 <button onclick="leaveRoom()">Leave Room</button>
84 </div>
85 <div class="participant-view">
86 <!-- Participant videos will be added here dynamically -->
87 </div>
88 </div>
89
90 <script>
91 function joinRoom() {
92 document.querySelector('.join-screen').classList.remove('active');
93 document.querySelector('.control-panel').classList.add('active');
94 document.querySelector('.participant-view').classList.add('active');
95 // Initialize WebRTC connection and join the specified room
96 }
97
98 function toggleAudio() {
99 // Toggle audio stream
100 }
101
102 function toggleVideo() {
103 // Toggle video stream
104 }
105
106 function leaveRoom() {
107 document.querySelector('.join-screen').classList.add('active');
108 document.querySelector('.control-panel').classList.remove('active');
109 document.querySelector('.participant-view').classList.remove('active');
110 // Leave the WebRTC room and clean up streams
111 }
112 </script>
113</body>
114</html>
Explanation of the Wireframe Components
Join Screen
- Contains an input field for the user to enter a room ID and a button to join the room.
- This section is initially visible (
.join-screen.active
).
Control Panel
- Contains buttons to mute/unmute audio, disable/enable video, and leave the room.
- This section is initially hidden and becomes visible after joining a room (
.control-panel.active
).
Participant View
- A flexible container to display video streams of participants in the room.
- This section is initially hidden and becomes visible after joining a room (
.participant-view.active
).
This wireframe sets up the basic layout and user interface for your WebRTC application. In the next parts, we will implement the functionalities for each of these components, starting with the join screen and then moving on to adding controls and handling participant views. By the end of these steps, you will have a fully functional WebRTC application using SRS.
Step 3: Implement Join Screen
The join screen is the first interface users will interact with when they access your SimpleRealtime Server (SRS) WebRTC application. It allows users to enter a room ID and join a video conference. In this section, we will implement the JavaScript functionality needed to make the join screen operational.
Building the Join Screen
We already have the HTML structure for the join screen. Now, we need to add the JavaScript code to handle user input and establish a WebRTC connection using SRS.
Here’s the step-by-step implementation:
HTML Structure
Ensure your HTML join screen structure is in place as shown in the previous part.
JavaScript for Join Screen
Add the following JavaScript code within the
<script>
tags at the bottom of your HTML file.HTML
1<script>
2 // Function to join a room
3 async function joinRoom() {
4 const roomId = document.getElementById('room-id').value.trim();
5 if (!roomId) {
6 alert('Please enter a room ID.');
7 return;
8 }
9
10 document.querySelector('.join-screen').classList.remove('active');
11 document.querySelector('.control-panel').classList.add('active');
12 document.querySelector('.participant-view').classList.add('active');
13
14 try {
15 // Initialize WebRTC connection
16 await initializeWebRTC(roomId);
17 } catch (error) {
18 console.error('Failed to join room:', error);
19 alert('Failed to join room. Please try again.');
20 document.querySelector('.join-screen').classList.add('active');
21 document.querySelector('.control-panel').classList.remove('active');
22 document.querySelector('.participant-view').classList.remove('active');
23 }
24 }
25
26 // Function to initialize WebRTC connection
27 async function initializeWebRTC(roomId) {
28 const configuration = {
29 iceServers: [
30 { urls: 'stun:stun.l.google.com:19302' }
31 ]
32 };
33 const peerConnection = new RTCPeerConnection(configuration);
34
35 // Handle ICE candidates
36 peerConnection.onicecandidate = event => {
37 if (event.candidate) {
38 sendMessage('candidate', roomId, event.candidate);
39 }
40 };
41
42 // Handle remote stream
43 peerConnection.ontrack = event => {
44 const remoteVideo = document.createElement('video');
45 remoteVideo.srcObject = event.streams[0];
46 remoteVideo.autoplay = true;
47 remoteVideo.playsInline = true;
48 document.querySelector('.participant-view').appendChild(remoteVideo);
49 };
50
51 // Get user media
52 const localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
53 localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
54
55 // Create offer
56 const offer = await peerConnection.createOffer();
57 await peerConnection.setLocalDescription(offer);
58
59 // Send offer to the server
60 sendMessage('offer', roomId, offer);
61
62 // Listen for answer from the server
63 socket.on('answer', async (message) => {
64 if (message.roomId === roomId) {
65 const remoteDesc = new RTCSessionDescription(message.sdp);
66 await peerConnection.setRemoteDescription(remoteDesc);
67 }
68 });
69
70 // Listen for candidate from the server
71 socket.on('candidate', async (message) => {
72 if (message.roomId === roomId) {
73 const candidate = new RTCIceCandidate(message.candidate);
74 await peerConnection.addIceCandidate(candidate);
75 }
76 });
77 }
78
79 // Function to send messages to the server
80 function sendMessage(type, roomId, data) {
81 const message = { type, roomId, data };
82 socket.emit(type, message);
83 }
84
85 // Initialize socket.io client
86 const socket = io.connect('http://localhost:8080');
87</script>
Explanation of the Code
Join Room Function
- Retrieves the room ID entered by the user.
- Shows and hides the appropriate screen sections.
- Calls
initializeWebRTC
to set up the WebRTC connection.
Initialize WebRTC Function
- Configures ICE servers for peer-to-peer connection.
- Sets up event handlers for ICE candidates and remote streams.
- Retrieves the user's media (audio and video) and adds it to the peer connection.
- Creates an SDP offer and sends it to the server.
- Listens for SDP answer and ICE candidates from the server.
Send Message Function
- Sends signaling messages (offer, answer, candidate) to the server using Socket.IO.
Socket.IO Initialization
- Establishes a connection to the server using Socket.IO for signaling.
By following these steps, you will have implemented the join screen functionality, enabling users to enter a room ID and join a video conference. In the next part, we will implement controls for managing the media streams and other interactive features in your application.
Step 4: Implement Controls
Implementing controls for your SimpleRealtime Server (SRS) WebRTC application is essential for providing users with the ability to manage their audio and video streams. In this section, we’ll add functionality to the control panel, allowing users to mute/unmute audio, disable/enable video, and leave the room.
Adding Controls to the Application
We already have the HTML buttons for the control panel in place. Now, we need to add the JavaScript functionality to handle these controls.
HTML Structure
Ensure your control panel buttons are in place as shown in the previous parts.
JavaScript for Controls
Add the following JavaScript code within the
<script>
tags at the bottom of your HTML file.HTML
1<script>
2 let localStream;
3 let peerConnection;
4
5 // Function to join a room
6 async function joinRoom() {
7 const roomId = document.getElementById('room-id').value.trim();
8 if (!roomId) {
9 alert('Please enter a room ID.');
10 return;
11 }
12
13 document.querySelector('.join-screen').classList.remove('active');
14 document.querySelector('.control-panel').classList.add('active');
15 document.querySelector('.participant-view').classList.add('active');
16
17 try {
18 // Initialize WebRTC connection
19 await initializeWebRTC(roomId);
20 } catch (error) {
21 console.error('Failed to join room:', error);
22 alert('Failed to join room. Please try again.');
23 document.querySelector('.join-screen').classList.add('active');
24 document.querySelector('.control-panel').classList.remove('active');
25 document.querySelector('.participant-view').classList.remove('active');
26 }
27 }
28
29 // Function to initialize WebRTC connection
30 async function initializeWebRTC(roomId) {
31 const configuration = {
32 iceServers: [
33 { urls: 'stun:stun.l.google.com:19302' }
34 ]
35 };
36 peerConnection = new RTCPeerConnection(configuration);
37
38 // Handle ICE candidates
39 peerConnection.onicecandidate = event => {
40 if (event.candidate) {
41 sendMessage('candidate', roomId, event.candidate);
42 }
43 };
44
45 // Handle remote stream
46 peerConnection.ontrack = event => {
47 const remoteVideo = document.createElement('video');
48 remoteVideo.srcObject = event.streams[0];
49 remoteVideo.autoplay = true;
50 remoteVideo.playsInline = true;
51 document.querySelector('.participant-view').appendChild(remoteVideo);
52 };
53
54 // Get user media
55 localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
56 localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
57
58 // Create offer
59 const offer = await peerConnection.createOffer();
60 await peerConnection.setLocalDescription(offer);
61
62 // Send offer to the server
63 sendMessage('offer', roomId, offer);
64
65 // Listen for answer from the server
66 socket.on('answer', async (message) => {
67 if (message.roomId === roomId) {
68 const remoteDesc = new RTCSessionDescription(message.sdp);
69 await peerConnection.setRemoteDescription(remoteDesc);
70 }
71 });
72
73 // Listen for candidate from the server
74 socket.on('candidate', async (message) => {
75 if (message.roomId === roomId) {
76 const candidate = new RTCIceCandidate(message.candidate);
77 await peerConnection.addIceCandidate(candidate);
78 }
79 });
80 }
81
82 // Function to send messages to the server
83 function sendMessage(type, roomId, data) {
84 const message = { type, roomId, data };
85 socket.emit(type, message);
86 }
87
88 // Function to toggle audio
89 function toggleAudio() {
90 const audioTracks = localStream.getAudioTracks();
91 if (audioTracks.length === 0) {
92 console.log('No audio track found');
93 return;
94 }
95
96 for (const track of audioTracks) {
97 track.enabled = !track.enabled;
98 }
99 }
100
101 // Function to toggle video
102 function toggleVideo() {
103 const videoTracks = localStream.getVideoTracks();
104 if (videoTracks.length === 0) {
105 console.log('No video track found');
106 return;
107 }
108
109 for (const track of videoTracks) {
110 track.enabled = !track.enabled;
111 }
112 }
113
114 // Function to leave the room
115 function leaveRoom() {
116 document.querySelector('.join-screen').classList.add('active');
117 document.querySelector('.control-panel').classList.remove('active');
118 document.querySelector('.participant-view').classList.remove('active');
119
120 // Close the peer connection and stop local tracks
121 if (peerConnection) {
122 peerConnection.close();
123 peerConnection = null;
124 }
125
126 if (localStream) {
127 localStream.getTracks().forEach(track => track.stop());
128 localStream = null;
129 }
130
131 // Clean up participant view
132 document.querySelector('.participant-view').innerHTML = '';
133
134 // Notify server about leaving the room
135 sendMessage('leave', roomId, {});
136 }
137
138 // Initialize socket.io client
139 const socket = io.connect('http://localhost:8080');
140</script>
Explanation of the Code
Toggle Audio Function
- Retrieves all audio tracks from the local media stream.
- Toggles the
enabled
property of each audio track to mute/unmute the audio.
Toggle Video Function
- Retrieves all video tracks from the local media stream.
- Toggles the
enabled
property of each video track to disable/enable the video.
Leave Room Function
- Hides the control panel and participant view, showing the join screen again.
- Closes the peer connection and stops all local media tracks.
- Clears the participant view and notifies the server that the user has left the room.
Socket.IO Initialization
- Establishes a connection to the server using Socket.IO for signaling.
By implementing these controls, users can now manage their audio and video streams and leave the room when needed. In the next part, we will implement the participant view, allowing the display and management of multiple video streams in the application. This will complete the core functionality of your SRS WebRTC application.
Step 5: Implement Participant View
The participant view is a crucial component of any video conferencing application. It displays the video streams of all participants in the room. In this section, we will implement the JavaScript code to manage and display multiple video streams in the participant view.
Developing the Participant View
We have already set up the HTML structure for the participant view in previous parts. Now, we'll enhance our JavaScript to handle multiple participants effectively.
HTML Structure
Ensure your participant view container is in place as shown in the previous parts.
JavaScript for Managing Participants
Add the following JavaScript code within the
<script>
tags at the bottom of your HTML file.1<script>
2 let localStream;
3 let peerConnection;
4 const participants = {}; // Object to store participants
5
6 // Function to join a room
7 async function joinRoom() {
8 const roomId = document.getElementById('room-id').value.trim();
9 if (!roomId) {
10 alert('Please enter a room ID.');
11 return;
12 }
13
14 document.querySelector('.join-screen').classList.remove('active');
15 document.querySelector('.control-panel').classList.add('active');
16 document.querySelector('.participant-view').classList.add('active');
17
18 try {
19 // Initialize WebRTC connection
20 await initializeWebRTC(roomId);
21 } catch (error) {
22 console.error('Failed to join room:', error);
23 alert('Failed to join room. Please try again.');
24 document.querySelector('.join-screen').classList.add('active');
25 document.querySelector('.control-panel').classList.remove('active');
26 document.querySelector('.participant-view').classList.remove('active');
27 }
28 }
29
30 // Function to initialize WebRTC connection
31 async function initializeWebRTC(roomId) {
32 const configuration = {
33 iceServers: [
34 { urls: 'stun:stun.l.google.com:19302' }
35 ]
36 };
37 peerConnection = new RTCPeerConnection(configuration);
38
39 // Handle ICE candidates
40 peerConnection.onicecandidate = event => {
41 if (event.candidate) {
42 sendMessage('candidate', roomId, event.candidate);
43 }
44 };
45
46 // Handle remote stream
47 peerConnection.ontrack = event => {
48 const remoteStream = event.streams[0];
49 addParticipantStream(event.streams[0], event.streams[0].id);
50 };
51
52 // Get user media
53 localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
54 localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
55 addParticipantStream(localStream, 'local');
56
57 // Create offer
58 const offer = await peerConnection.createOffer();
59 await peerConnection.setLocalDescription(offer);
60
61 // Send offer to the server
62 sendMessage('offer', roomId, offer);
63
64 // Listen for answer from the server
65 socket.on('answer', async (message) => {
66 if (message.roomId === roomId) {
67 const remoteDesc = new RTCSessionDescription(message.sdp);
68 await peerConnection.setRemoteDescription(remoteDesc);
69 }
70 });
71
72 // Listen for candidate from the server
73 socket.on('candidate', async (message) => {
74 if (message.roomId === roomId) {
75 const candidate = new RTCIceCandidate(message.candidate);
76 await peerConnection.addIceCandidate(candidate);
77 }
78 });
79
80 // Listen for new participants
81 socket.on('new-participant', (message) => {
82 if (message.roomId === roomId) {
83 // Handle new participant joining
84 // This could involve setting up a new peer connection
85 }
86 });
87
88 // Listen for participant leaving
89 socket.on('participant-left', (message) => {
90 if (message.roomId === roomId && participants[message.participantId]) {
91 removeParticipantStream(message.participantId);
92 }
93 });
94 }
95
96 // Function to send messages to the server
97 function sendMessage(type, roomId, data) {
98 const message = { type, roomId, data };
99 socket.emit(type, message);
100 }
101
102 // Function to add participant's stream to the view
103 function addParticipantStream(stream, participantId) {
104 const participantVideo = document.createElement('video');
105 participantVideo.srcObject = stream;
106 participantVideo.autoplay = true;
107 participantVideo.playsInline = true;
108 participantVideo.id = participantId;
109 participantVideo.classList.add('participant-video');
110 document.querySelector('.participant-view').appendChild(participantVideo);
111 participants[participantId] = participantVideo;
112 }
113
114 // Function to remove participant's stream from the view
115 function removeParticipantStream(participantId) {
116 const participantVideo = document.getElementById(participantId);
117 if (participantVideo) {
118 participantVideo.srcObject.getTracks().forEach(track => track.stop());
119 participantVideo.remove();
120 delete participants[participantId];
121 }
122 }
123
124 // Function to toggle audio
125 function toggleAudio() {
126 const audioTracks = localStream.getAudioTracks();
127 if (audioTracks.length === 0) {
128 console.log('No audio track found');
129 return;
130 }
131
132 for (const track of audioTracks) {
133 track.enabled = !track.enabled;
134 }
135 }
136
137 // Function to toggle video
138 function toggleVideo() {
139 const videoTracks = localStream.getVideoTracks();
140 if (videoTracks.length === 0) {
141 console.log('No video track found');
142 return;
143 }
144
145 for (const track of videoTracks) {
146 track.enabled = !track.enabled;
147 }
148 }
149
150 // Function to leave the room
151 function leaveRoom() {
152 document.querySelector('.join-screen').classList.add('active');
153 document.querySelector('.control-panel').classList.remove('active');
154 document.querySelector('.participant-view').classList.remove('active');
155
156 // Close the peer connection and stop local tracks
157 if (peerConnection) {
158 peerConnection.close();
159 peerConnection = null;
160 }
161
162 if (localStream) {
163 localStream.getTracks().forEach(track => track.stop());
164 localStream = null;
165 }
166
167 // Clean up participant view
168 Object.keys(participants).forEach(participantId => removeParticipantStream(participantId));
169
170 // Notify server about leaving the room
171 sendMessage('leave', roomId, {});
172 }
173
174 // Initialize socket.io client
175 const socket = io.connect('http://localhost:8080');
176</script>
Explanation of the Code
Participants Object
- An object to store the video elements of participants, keyed by participant ID.
Add Participant Stream Function
- Creates a video element for the participant's stream.
- Sets the video element's
srcObject
to the participant's media stream. - Adds the video element to the participant view and stores it in the
participants
object.
Remove Participant Stream Function
- Retrieves the video element of the participant using their ID.
- Stops all tracks of the participant's media stream and removes the video element from the DOM.
- Deletes the participant's entry from the
participants
object.
Socket Event Listeners
new-participant
: Handles new participants joining the room. You may need to set up new peer connections for each participant.participant-left
: Removes the video element of a participant who has left the room.
By implementing these features, your SRS WebRTC application will now be able to display and manage multiple participant video streams. This completes the core functionality needed for a basic video conferencing application. In the final part, we will cover running your code and provide a conclusion along with a comprehensive FAQ section.
Step 6: Run Your Code Now
With all the core functionalities implemented, it's time to run your SimpleRealtime Server (SRS) WebRTC application. This final part will guide you through the steps to test your application and ensure everything is working as expected.
Running the Application
[a] Start the SRS Server
Navigate to your SRS directory and start the server.
1 cd /path/to/srs/trunk
2 ./objs/srs -c conf/srs.conf
[b] Start Your Web Server
If you're serving your HTML file through a local web server, ensure it is running. You can use a simple server like
http-server
or serve through a more advanced setup.1 http-server -p 8080
If you're using a different method to serve your HTML files, ensure it's correctly configured.
[c] Open Your Application in a Browser
- Open your web browser and navigate to the local address where your HTML file is being served, such as
http://localhost:8080
.
[d] Test the Application
- Enter a room ID in the join screen and click "Join".
- Test the audio and video controls by muting/unmuting and enabling/disabling video.
- Join the same room from another browser or device to ensure participant views are correctly displayed and managed.
- Use the "Leave Room" button to verify that leaving the room works as expected and cleans up resources.
Conclusion
In this tutorial, we've walked through the process of setting up a SimpleRealtime Server (SRS) WebRTC application from scratch. We've covered configuring the server, building the HTML structure, implementing the join screen, adding controls, and managing participant views. By following these steps, you've created a basic yet functional video conferencing application.
Want to level-up your learning? Subscribe now
Subscribe to our newsletter for more tech based insights
FAQ