End of Life for Twilio Programmable Video - Upgrade to VideoSDKLearn More

How to Build Coturn WebRTC App?

Learn how to set up and configure Coturn for WebRTC applications. This guide covers installation, project structure, and key features to ensure reliable real-time communication. Perfect for developers using C/C++.

Introduction to Coturn Technology

What is Coturn?

Coturn is an open-source TURN (Traversal Using Relays around NAT) server implementation. It's a critical component in WebRTC (Web Real-Time Communication) technology, enabling reliable communication across network address translators (NAT) and firewalls. WebRTC applications use Coturn to facilitate real-time video, audio, and data exchange between users, regardless of their network environment.

Importance of TURN Servers in WebRTC

In WebRTC, peer-to-peer connections are the backbone of communication. However, establishing these direct connections can be challenging when users are behind NATs or firewalls. TURN servers like Coturn act as intermediaries, relaying traffic between peers when direct connections aren't possible. This ensures that the communication is smooth and uninterrupted, even in restrictive network environments.

Brief History of Coturn

Coturn originated as a merger of two projects: rfc5766-turn-server and restund. This merger combined the strengths of both projects to create a robust and efficient TURN server. Over the years, Coturn has evolved through community contributions, becoming a reliable and widely used solution in WebRTC implementations.
In summary, Coturn plays a vital role in enabling seamless real-time communication in WebRTC applications. Its ability to navigate complex network environments ensures that users can connect reliably, regardless of their network constraints. This introduction sets the stage for diving deeper into the technical setup and practical applications of Coturn in WebRTC.

Getting Started with the Code!

In this section, we will walk you through the process of setting up a Coturn server from scratch. We'll cover installation, project structure, and the architecture of your application, providing you with the foundational knowledge to get started with Coturn.

Create a New Coturn App

Setting Up the Development Environment

Before diving into the code, ensure you have a suitable development environment. You'll need a Unix-based system (Linux or macOS is recommended) and root or sudo privileges for installation. Ensure you have the following prerequisites installed:
  • GNU build system: Includes tools like make and gcc.
  • OpenSSL library: Used for secure communications.
  • Libevent library: For asynchronous event notification.
Install these dependencies using the package manager for your operating system. For example, on Ubuntu, you can run:


1sudo apt-get update
2sudo apt-get install build-essential libssl-dev libevent-dev

Install Coturn

Detailed Installation Guide for Coturn

[a] Download the Source Code

Clone the Coturn repository from GitHub:


1   git clone https://github.com/coturn/coturn.git
2   cd coturn

[b] Compile and Install

Run the following commands to compile and install Coturn:


1   ./configure
2   make
3   sudo make install
These commands will configure the build environment, compile the source code, and install Coturn on your system.

[c] Verify Installation

After installation, verify that Coturn is correctly installed by checking its version:


1   turnserver -V
This command should display the version of Coturn installed, confirming that the installation was successful.

Structure of the Project

Overview of Project Directories and Files

Once installed, Coturn's configuration files and executable binaries are located in specific directories. Here's a typical structure:
  • /usr/local/bin/turnserver: The main Coturn executable.
  • /etc/turnserver.conf: The default configuration file for Coturn.
  • /var/log/turnserver: Log files generated by Coturn.

Explanation of Configuration Files

The primary configuration file for Coturn is turnserver.conf. This file contains various settings that control how Coturn operates, including user authentication, network interfaces, and relay policies.

App Architecture


Key Architectural Components of a Coturn Server

Understanding the architecture of Coturn helps in configuring and optimizing it for your needs. Key components include:
  • TURN Server: Handles the actual relaying of media packets.
  • Authentication Module: Manages user access and authentication.
  • Relay Module: Manages the relaying of media packets between clients.

How Coturn Fits into a WebRTC Architecture

In a WebRTC application, Coturn acts as an intermediary server that relays media packets between peers. When peers cannot establish a direct peer-to-peer connection due to NAT or firewall restrictions, they connect to the Coturn server, which then relays the media packets between them. This ensures that communication is established seamlessly, even in challenging network conditions.
Now that you have a basic understanding of setting up Coturn and its architecture, you are ready to dive deeper into its configuration and integration with WebRTC. In the next sections, we will cover detailed configuration steps and provide code snippets to help you get started with your Coturn-enabled WebRTC application.

Step 1: Get Started with the Configuration File

Configuring Coturn is a crucial step in ensuring that your TURN server operates effectively and securely. In this section, we will guide you through the basics of setting up the turnserver.conf file, covering essential configuration parameters and user authentication.

Configuration File Basics

Creating and Editing the turnserver.conf File
The turnserver.conf file is the main configuration file for Coturn. You need to create or edit this file to customize the server settings. The default location for this file is /etc/turnserver.conf. If it doesn't exist, you can create it using a text editor:


1sudo nano /etc/turnserver.conf

Essential Configuration Parameters

[a] Listening Port

Define the port on which Coturn will listen for incoming requests. The default port for TURN is 3478, and for secure connections (TLS), it's 5349.


1   listening-port=3478
2   tls-listening-port=5349

[b] External IP

If your server has a public IP address different from the local IP, specify the external IP:


1   external-ip=<your-public-ip>

[c] Relay Configuration

Specify the range of ports that Coturn will use for relaying media:


1   min-port=49152
2   max-port=65535

[d] Fingerprint

Enabling fingerprinting is recommended for enhanced security:


1   fingerprint

Detailed Configuration

Setting Up User Authentication

[a] Static User Accounts

You can define static user accounts directly in the configuration file. This is useful for testing and small-scale deployments.


1   user=username:password
For example:


1   user=alice:securepassword

[b] Dynamic User Accounts

For larger deployments, you may want to use a more dynamic approach, such as using a REST API to fetch user credentials. To enable this, you need to specify the REST API endpoint:


1   use-auth-secret
2   static-auth-secret=your-auth-secret
Configure the REST API endpoint:


1   rest-api-sequence-allowed

Configuring Network Interfaces and Ports

[a] Listening Interfaces

Specify the network interfaces on which Coturn will listen for incoming connections:


1   listening-ip=<your-local-ip>

[b] Relay Interfaces

Define the interfaces used for relaying media packets:


1   relay-ip=<your-local-ip>
Example Configuration File
Here is an example of a basic turnserver.conf file:


1# Listening ports
5# External IP configuration
8# Relay configuration
12# Fingerprint for security
15# User authentication
20# Network interfaces
24# Log file

[c] Starting the Coturn Server

Once your configuration file is set up, you can start the Coturn server using the following command:


1sudo turnserver -c /etc/turnserver.conf
You can also enable Coturn to start on boot by configuring your system's service manager. For example, on systems using systemd, you can create a service file:


1sudo nano /etc/systemd/system/coturn.service
Add the following content to the service file:


2Description=Coturn TURN Server
6ExecStart=/usr/local/bin/turnserver -c /etc/turnserver.conf
Enable and start the service:


1sudo systemctl enable coturn
2sudo systemctl start coturn
In this part, we have covered the basics of creating and editing the turnserver.conf file, focusing on essential configuration parameters and user authentication. By following these steps, you should have a functional Coturn server ready to handle WebRTC traffic. In the next part, we will discuss how to wireframe all the components to ensure smooth integration with your WebRTC application.

Step 2: Wireframe All the Components

In this section, we will explore the key components of a Coturn-enabled WebRTC application and guide you through the process of setting up and wiring these components together. This step is crucial for ensuring that your application integrates seamlessly with the Coturn server to provide reliable real-time communication.

Component Overview

Explanation of Key Components in Coturn

TURN Server

The core of Coturn, responsible for relaying media packets between peers when direct connections are not possible due to NAT or firewall restrictions.

Authentication Module

Manages user authentication, ensuring that only authorized users can utilize the TURN server for relaying media.

Relay Module

Handles the actual relaying of media packets, ensuring that data is transmitted securely and efficiently between peers.

Logging and Monitoring

Coturn provides logging and monitoring capabilities to track server performance and troubleshoot issues.

Interaction Between Components

Understanding how these components interact is essential for configuring your Coturn server effectively. Here's a high-level overview of the interaction:
Client Initiation: A WebRTC client initiates a connection and attempts to establish a peer-to-peer connection.
NAT Traversal: If the peer-to-peer connection fails due to NAT or firewall, the client connects to the Coturn server.
Authentication: The client provides authentication credentials to the Coturn server.
Relaying: Upon successful authentication, the Coturn server relays media packets between the clients, facilitating the communication.

Setting Up Components

Wiring the Components Together
To wire all the components together, follow these steps:

[a] WebRTC Client Configuration

Ensure your WebRTC client is configured to use the Coturn server as a TURN server. This is typically done in the JavaScript code that sets up the WebRTC peer connection.


1   const iceServers = [
2       {
3           urls: 'turn:your-coturn-server-ip:3478',
4           username: 'alice',
5           credential: 'securepassword'
6       }
7   ];
9   const peerConnection = new RTCPeerConnection({ iceServers });

[b] Server Configuration

Ensure that your Coturn server is configured correctly as per the configuration file discussed in the previous section. Double-check the following parameters:
  • Listening port
  • External IP
  • User authentication settings
  • Network interfaces

[c] Client-Server Communication

When a WebRTC client initiates a connection, it will include the TURN server in its ICE (Interactive Connectivity Establishment) candidates. The client will first attempt a direct connection, and if that fails, it will fallback to using the TURN server for relaying the media.

[d] Testing the Setup

To verify that everything is working correctly, use a WebRTC test application like

Trickle ICE

. Input your Coturn server details and check if the candidates are gathered successfully.

Example Configuration for Different Use Cases

[a] Single Server Setup

For a simple application, you might have a single Coturn server handling all the relay traffic. Ensure the configuration file (turnserver.conf) is set up with the basic settings discussed earlier.

[b] Multiple Server Setup

For larger applications, you might deploy multiple Coturn servers to handle the load. In this case, use a load balancer to distribute traffic among the servers. Each server will have a similar configuration file, with adjustments for the specific server's IP addresses and ports.

[c] Secure Connections

If security is a concern (which it should be), configure Coturn to use TLS/DTLS for secure communications. Ensure that you have valid SSL certificates and configure the tls-listening-port in your turnserver.conf file.


1   tls-listening-port=5349
2   cert=/path/to/your/certificate.pem
3   pkey=/path/to/your/privatekey.pem
In this part, we have discussed the essential components of a Coturn-enabled WebRTC application and how to wire these components together. By ensuring that your WebRTC client is correctly configured to use the Coturn server and that your server settings are optimized, you can facilitate seamless and reliable real-time communication. In the next part, we will cover the implementation of the join screen, providing a more interactive and user-friendly interface for your application.

Step 3: Implement Join Screen

The join screen is the first interaction point for users in a WebRTC application. It's crucial to design and implement it effectively to ensure a seamless user experience. In this section, we will guide you through the steps to implement a join screen that integrates with Coturn for reliable communication.

Join Screen Overview

Role of the Join Screen in a WebRTC Application

The join screen serves several key functions:
  • User Identification: It collects user information such as name and room ID.
  • Session Initialization: It sets up the necessary parameters for the WebRTC session.
  • User Feedback: It provides feedback to the user about the connection status.
By properly implementing the join screen, you can ensure that users have a smooth start to their WebRTC session, paving the way for a reliable communication experience.

Implementation Steps

[a] HTML Structure for the Join Screen

Start by creating a simple HTML structure for the join screen. This will include input fields for the user to enter their name and room ID, and a button to join the session.


1<!DOCTYPE html>
2<html lang="en">
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Join WebRTC Session</title>
7    <style>
8        body { font-family: Arial, sans-serif; }
9        .join-container { max-width: 300px; margin: 50px auto; text-align: center; }
10        input { width: 100%; padding: 10px; margin: 10px 0; }
11        button { padding: 10px 20px; }
12    </style>
15    <div class="join-container">
16        <h1>Join Session</h1>
17        <input type="text" id="username" placeholder="Enter your name" required>
18        <input type="text" id="room-id" placeholder="Enter room ID" required>
19        <button id="join-btn">Join</button>
20    </div>
21    <script src="join.js"></script>

[b] JavaScript for Handling User Input and Starting WebRTC Session

Next, create a JavaScript file (join.js) to handle the user input and initiate the WebRTC session. This script will capture the user's name and room ID, configure the ICE servers to use Coturn, and initialize the peer connection.


1document.getElementById('join-btn').addEventListener('click', async () => {
2    const username = document.getElementById('username').value;
3    const roomId = document.getElementById('room-id').value;
5    if (!username || !roomId) {
6        alert('Please enter your name and room ID.');
7        return;
8    }
10    // Configuration for Coturn server
11    const iceServers = [
12        {
13            urls: 'turn:your-coturn-server-ip:3478',
14            username: 'alice',
15            credential: 'securepassword'
16        }
17    ];
19    // Initialize the WebRTC connection
20    const configuration = { iceServers };
21    const peerConnection = new RTCPeerConnection(configuration);
23    // Handle ICE candidate events
24    peerConnection.onicecandidate = event => {
25        if (event.candidate) {
26            console.log('New ICE candidate:', event.candidate);
27            // Send the candidate to the remote peer via your signaling server
28        }
29    };
31    // Add media tracks (audio/video) from the user's device
32    try {
33        const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
34        stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
36        // Display the local video stream
37        const videoElement = document.createElement('video');
38        videoElement.srcObject = stream;
39        videoElement.autoplay = true;
40        document.body.appendChild(videoElement);
42        // Join the session (implement signaling logic here)
43        joinSession(peerConnection, username, roomId);
44    } catch (error) {
45        console.error('Error accessing media devices.', error);
46    }
49async function joinSession(peerConnection, username, roomId) {
50    // Implement signaling server connection and room join logic here
51    // This typically involves exchanging SDP offers/answers and ICE candidates

[c] Integrating Coturn with the Join Screen

Configure ICE Servers: Ensure that the iceServers array in the JavaScript code includes the Coturn server details.
Signaling Server Integration: The joinSession function should connect to your signaling server and handle the exchange of SDP (Session Description Protocol) offers and answers, as well as ICE candidates.
Example signaling code (using WebSocket or any other signaling protocol):


1     const signalingServerUrl = 'wss://your-signaling-server';
2     const signalingSocket = new WebSocket(signalingServerUrl);
4     signalingSocket.onopen = () => {
5         console.log('Connected to the signaling server');
6         signalingSocket.send(JSON.stringify({
7             type: 'join',
8             username,
9             roomId
10         }));
11     };
13     signalingSocket.onmessage = async message => {
14         const data = JSON.parse(message.data);
16         switch (data.type) {
17             case 'offer':
18                 await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
19                 const answer = await peerConnection.createAnswer();
20                 await peerConnection.setLocalDescription(answer);
21                 signalingSocket.send(JSON.stringify({ type: 'answer', answer }));
22                 break;
24             case 'answer':
25                 await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
26                 break;
28             case 'candidate':
29                 await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
30                 break;
31         }
32     };
34     signalingSocket.onerror = error => {
35         console.error('Signaling server error:', error);
36     };
In this part, we've implemented a basic join screen for a WebRTC application. We've set up the HTML structure, added JavaScript to handle user input, configured the ICE servers to use Coturn, and integrated a signaling mechanism. This foundation allows users to join a WebRTC session reliably, leveraging Coturn for NAT traversal and relaying media. In the next part, we will focus on implementing controls to enhance user interaction and functionality within the application.

Step 4: Implement Controls

In this section, we will implement controls to enhance the user experience in your WebRTC application. These controls will include features such as mute/unmute, video on/off, and screen sharing. Adding these controls ensures that users have the necessary tools to manage their communication effectively.

Controls Overview

Types of Controls Needed in a WebRTC App
  1. Mute/Unmute Audio:
    • Allows users to mute or unmute their microphone during a call.
  2. Video On/Off:
    • Lets users turn their camera on or off.
  3. Screen Sharing:
    • Enables users to share their screen with other participants.
By implementing these controls, you provide users with greater flexibility and control over their communication experience.


Adding Mute/Unmute Audio Control

[a] HTML Button for Mute/Unmute

Add a button to your HTML file for toggling the microphone:


1   <button id="mute-btn">Mute</button>

[b] JavaScript for Mute/Unmute

Update your join.js file to handle the mute/unmute functionality:


1   const muteButton = document.getElementById('mute-btn');
2   let isMuted = false;
4   muteButton.addEventListener('click', () => {
5       const audioTracks = stream.getAudioTracks();
6       audioTracks.forEach(track => track.enabled = !track.enabled);
7       isMuted = !isMuted;
8       muteButton.textContent = isMuted ? 'Unmute' : 'Mute';
9   });

Adding Video On/Off Control

[a] HTML Button for Video On/Off

Add a button to your HTML file for toggling the camera:


1   <button id="video-btn">Turn Off Video</button>

[b] JavaScript for Video On/Off

Update your join.js file to handle the video on/off functionality:


1   const videoButton = document.getElementById('video-btn');
2   let isVideoOn = true;
4   videoButton.addEventListener('click', () => {
5       const videoTracks = stream.getVideoTracks();
6       videoTracks.forEach(track => track.enabled = !track.enabled);
7       isVideoOn = !isVideoOn;
8       videoButton.textContent = isVideoOn ? 'Turn Off Video' : 'Turn On Video';
9   });

Adding Screen Sharing Control

[a] HTML Button for Screen Sharing

Add a button to your HTML file for initiating screen sharing:


1   <button id="share-screen-btn">Share Screen</button>

[b] JavaScript for Screen Sharing

Update your join.js file to handle screen sharing:


1   const shareScreenButton = document.getElementById('share-screen-btn');
3   shareScreenButton.addEventListener('click', async () => {
4       try {
5           const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
6           const screenTrack = screenStream.getVideoTracks()[0];
8           // Replace video track with screen track
9           const sender = peerConnection.getSenders().find(s => s.track.kind === 'video');
10           sender.replaceTrack(screenTrack);
12           // Update UI
13           shareScreenButton.textContent = 'Stop Sharing';
14           screenTrack.onended = () => {
15               // Revert to webcam video
16               sender.replaceTrack(stream.getVideoTracks()[0]);
17               shareScreenButton.textContent = 'Share Screen';
18           };
19       } catch (error) {
20           console.error('Error sharing screen:', error);
21       }
22   });
In this part, we have implemented essential controls for a WebRTC application: mute/unmute audio, video on/off, and screen sharing. These controls provide users with the flexibility to manage their communication settings, enhancing the overall user experience. With these features in place, users can effectively control their audio and video streams and share their screens seamlessly. In the next part, we will focus on implementing the participant view, allowing users to see and interact with other participants in the session.

Get Free 10,000 Minutes Every Months

No credit card required to start.

Step 5: Implement Participant View

In this section, we will focus on implementing the participant view for your WebRTC application. The participant view allows users to see and interact with other participants in the session. This step is crucial for creating a fully interactive and engaging real-time communication experience.

Participant View Overview

Importance of Participant View in WebRTC
The participant view is essential because it:
  • Displays Video Streams: Shows the video feeds of all participants.
  • Indicates Connection Status: Provides visual cues about the connection status of each participant.
  • Enables Interaction: Allows users to interact with each other's video streams (e.g., pinning, full-screen).
A well-implemented participant view enhances the user experience by making the communication more immersive and interactive.

HTML Structure for Participant View

First, update your HTML file to include a container for the participant videos.


1<!DOCTYPE html>
2<html lang="en">
4    <meta charset="UTF-8">
5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6    <title>Join WebRTC Session</title>
7    <style>
8        body { font-family: Arial, sans-serif; }
9        .join-container { max-width: 300px; margin: 50px auto; text-align: center; }
10        input { width: 100%; padding: 10px; margin: 10px 0; }
11        button { padding: 10px 20px; margin: 10px 5px; }
12        #participants { display: flex; flex-wrap: wrap; }
13        .participant { margin: 10px; }
14        video { width: 200px; height: auto; }
15    </style>
18    <div class="join-container">
19        <h1>Join Session</h1>
20        <input type="text" id="username" placeholder="Enter your name" required>
21        <input type="text" id="room-id" placeholder="Enter room ID" required>
22        <button id="join-btn">Join</button>
23        <button id="mute-btn">Mute</button>
24        <button id="video-btn">Turn Off Video</button>
25        <button id="share-screen-btn">Share Screen</button>
26    </div>
27    <div id="participants"></div>
28    <script src="join.js"></script>

JavaScript for Handling Participant Video Streams

Next, update your join.js file to manage the video streams of participants.

[a] Handling Local Video Stream

Ensure the local video stream is displayed correctly when the user joins the session.


1   const participantsContainer = document.getElementById('participants');
3   document.getElementById('join-btn').addEventListener('click', async () => {
4       const username = document.getElementById('username').value;
5       const roomId = document.getElementById('room-id').value;
7       if (!username || !roomId) {
8           alert('Please enter your name and room ID.');
9           return;
10       }
12       // Configuration for Coturn server
13       const iceServers = [
14           {
15               urls: 'turn:your-coturn-server-ip:3478',
16               username: 'alice',
17               credential: 'securepassword'
18           }
19       ];
21       // Initialize the WebRTC connection
22       const configuration = { iceServers };
23       const peerConnection = new RTCPeerConnection(configuration);
25       // Handle ICE candidate events
26       peerConnection.onicecandidate = event => {
27           if (event.candidate) {
28               console.log('New ICE candidate:', event.candidate);
29               // Send the candidate to the remote peer via your signaling server
30           }
31       };
33       // Add media tracks (audio/video) from the user's device
34       try {
35           const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
36           stream.getTracks().forEach(track => peerConnection.addTrack(track, stream));
38           // Display the local video stream
39           const videoElement = document.createElement('video');
40           videoElement.srcObject = stream;
41           videoElement.autoplay = true;
42           videoElement.muted = true;  // Mute local video to avoid echo
43           videoElement.className = 'participant';
44           participantsContainer.appendChild(videoElement);
46           // Join the session (implement signaling logic here)
47           joinSession(peerConnection, username, roomId);
48       } catch (error) {
49           console.error('Error accessing media devices.', error);
50       }
51   });
53   async function joinSession(peerConnection, username, roomId) {
54       // Implement signaling server connection and room join logic here
55       // This typically involves exchanging SDP offers/answers and ICE candidates
56   }

[b] Handling Remote Video Streams

Update the joinSession function to handle incoming remote video streams.


1   async function joinSession(peerConnection, username, roomId) {
2       const signalingServerUrl = 'wss://your-signaling-server';
3       const signalingSocket = new WebSocket(signalingServerUrl);
5       signalingSocket.onopen = () => {
6           console.log('Connected to the signaling server');
7           signalingSocket.send(JSON.stringify({
8               type: 'join',
9               username,
10               roomId
11           }));
12       };
14       signalingSocket.onmessage = async message => {
15           const data = JSON.parse(message.data);
17           switch (data.type) {
18               case 'offer':
19                   await peerConnection.setRemoteDescription(new RTCSessionDescription(data.offer));
20                   const answer = await peerConnection.createAnswer();
21                   await peerConnection.setLocalDescription(answer);
22                   signalingSocket.send(JSON.stringify({ type: 'answer', answer }));
23                   break;
25               case 'answer':
26                   await peerConnection.setRemoteDescription(new RTCSessionDescription(data.answer));
27                   break;
29               case 'candidate':
30                   await peerConnection.addIceCandidate(new RTCIceCandidate(data.candidate));
31                   break;
32           }
33       };
35       peerConnection.ontrack = event => {
36           const [stream] = event.streams;
37           const videoElement = document.createElement('video');
38           videoElement.srcObject = stream;
39           videoElement.autoplay = true;
40           videoElement.className = 'participant';
41           participantsContainer.appendChild(videoElement);
42       };
44       signalingSocket.onerror = error => {
45           console.error('Signaling server error:', error);
46       };
47   }
In this part, we've implemented the participant view for a WebRTC application. By adding the HTML structure and JavaScript logic to handle local and remote video streams, we enable users to see and interact with each other in real-time. This functionality is crucial for creating a fully interactive and engaging communication experience. In the next part, we will focus on running and testing your complete WebRTC application to ensure everything works as expected.

Step 6: Run Your Code Now

In this section, we'll walk you through the steps to run and test your complete WebRTC application. We'll ensure that everything is set up correctly and provide tips for debugging common issues. This will help you verify that your Coturn-enabled WebRTC application is functioning as expected.

Running the Code

Steps to Compile and Run Your Coturn Setup

[a] Start the Coturn Server

Ensure your Coturn server is configured and start it using the command:


1   sudo turnserver -c /etc/turnserver.conf
If you've set up Coturn to run as a service, use the following commands to start and enable the service:


1   sudo systemctl start coturn
2   sudo systemctl enable coturn

[b] Run Your WebRTC Application

Ensure your signaling server is running. If you're using a WebSocket server, start it with:


1   node signaling-server.js
Open your WebRTC application's HTML file in a web browser. This can typically be done by simply opening the index.html file or running a local server using Python or any other HTTP server tool:


1   python -m http.server 8000
Navigate to http://localhost:8000 in your browser to access the application.
Verifying the Setup and Initial Tests

[a] Join a Session

Open the application in two different browser windows or tabs, or on two different devices. Enter a username and room ID in each window and click the "Join" button. Ensure both users can see and interact with each other.

[b] Test Audio and Video

Verify that the audio and video streams are working correctly. Test the mute/unmute and video on/off controls to ensure they function as expected.

[c] Test Screen Sharing

Click the "Share Screen" button and ensure that the screen sharing works properly. Verify that the screen sharing can be stopped and the video feed returns to the webcam.


Common Issues and How to Troubleshoot Them

No Audio/Video

  • Check Permissions: Ensure that your browser has permission to access the microphone and camera.
  • Console Errors: Look for any errors in the browser console. These can provide clues about what might be wrong.
  • Network Issues: Ensure that the Coturn server is reachable from both peers. Verify network configurations and firewall settings.

ICE Connection Failed

  • Check Coturn Configuration: Ensure that the turnserver.conf file is correctly configured, including the listening-port, tls-listening-port, and external-ip settings.
  • Check ICE Servers Configuration: Verify that the ICE servers in your WebRTC application are correctly set to use the Coturn server.
  • Network Restrictions: Ensure that there are no network restrictions blocking the TURN server ports.

Screen Sharing Issues

  • Browser Support: Ensure that your browser supports the getDisplayMedia API for screen sharing.
  • Permissions: Ensure that your browser has permission to capture the screen.
  • Replace Track: Verify that the screen sharing track is correctly replacing the video track in the peer connection.

Tips for Maintaining a Stable Setup

Monitor Server Performance

Regularly monitor the performance of your Coturn server using log files and performance metrics. This helps in identifying and addressing any bottlenecks or issues.

Keep Software Updated

Ensure that both Coturn and your WebRTC application dependencies are up to date with the latest security patches and features.

Regular Testing

Continuously test your application, especially after making changes to the code or configuration. Regular testing helps in catching issues early and ensuring a smooth user experience.


Congratulations! You have successfully set up a Coturn-enabled WebRTC application. By following the steps outlined in this article, you've created a robust real-time communication platform that can handle various network environments. Your application now supports essential features such as audio/video streaming, screen sharing, and user controls, providing a comprehensive communication experience.

Want to level-up your learning? Subscribe now

Subscribe to our newsletter for more tech based insights