DEV Community

Cover image for Calling a door phone from a web browser
Pedro Sanders for Fonoster Inc

Posted on • Edited on

Calling a door phone from a web browser

Calling a door phone from a web browser

In this tutorial, I will take you through the steps of building a VoIP network that will allow you to make calls from a web browser out to a door phone. This setup would be helpful for access control for commercial buildings, monitoring and security, calls for assistance in hospitals, and more.

We will use SIP.js as the client, Routr as the signaling server, and RTPEngine to proxy RTP traffic.

GitHub logo fonoster / routr

⚡ The future of programmable SIP servers.

Requirements

Before you start this tutorial, you will need the following:

  • Docker Engine installed on your computer or the cloud
  • NodeJS 18+ (Use nvm if possible)
  • Routr command-line tool (Install with npm install -g @routr/ctl)
  • A door phone such as Fanvil i20S

Running Routr and RTPEngine with Docker Compose

This tutorial will use Routr for signaling and RTPEngine to proxy RTP traffic.

The simplest way to run both services is using Docker Compose.

To run the services with Docker Compose, first, create a folder named voipnet and, in it, a file named compose.yaml with the following content:

Filename: voipnet/compose.yml

version: "3"

services:
  routr:
    image: fonoster/routr-one:latest
    environment:
      EXTERNAL_ADDRS: ${DOCKER_HOST_ADDRESS}
      RTPENGINE_HOST: rtpengine
    ports:
      - 51908:51908
      - 5062:5062
      - 5060:5060
    volumes:
      # Ensures the data survives container restarts
      - shared:/var/lib/postgresql/data

  # RTPEngine requires network mode "host" to work properly. However, this option doesn't work on 
  # Windows and MacOs. For development, we are opening a few ports to the host machine. 
  # For production, you must use the network_mode: host which works on Linux.
  rtpengine:
    image: fonoster/rtpengine:latest
    # Uncomment the following line for production
    # network_mode: host
    environment:
      # Set DOCKER_HOST_ADDRESS to an IP address that is reachable to the SIP clients
      PUBLIC_IP: ${DOCKER_HOST_ADDRESS}
      PORT_MIN: 10000
      PORT_MAX: 10100
      LOG_LEVEL: 6
    ports:
      - 22222:22222/udp
      - 10000-10100:10000-10100/udp

volumes:
  shared:
Enter fullscreen mode Exit fullscreen mode

Notice how we included the environment variables EXTERNAL_ADDRS and PUBLIC_IP in the previous file, whose value must be set to an IP that all parties can reach to avoid wrong signaling and audio issues.

Also noteworthy is that the port 51908 was opened for administration, 5060 for TCP signaling, and 5062 for signaling with SIP.js

Next, save the file and run the following command:

# NOTE: Be sure to update the IP address
DOCKER_HOST_ADDRESS=192.168.1.7 docker compose up
Enter fullscreen mode Exit fullscreen mode

The previous command will pull Routr and RTPEngine from Docker Hub and start the containers. You could also add the -d option to run the service in the background.

Configuring a Domain and a set of Agents

You will use Routr's command-line tool to issue commands to the server and build the VoIP network.

The network will have a Domain, sip.local, an Agent named "Door Phone," and an Agent named "Admin."

To build the VoIP network, first create a new Domain with:

rctl domains create --insecure
Enter fullscreen mode Exit fullscreen mode

Notice the --insecure flag, which is required since we don't have a TLS certificate.

The output of your command will look similar to the output below:

Press ^C at any time to quit.
 ›   Warning: Egress rules unavailable due to 0 configured numbers.
? Friendly Name Local Domain
? SIP URI sip.local
? IP Access Control List None
? Ready? Yes
Creating Domain Local Domain... 3b20410a-3c80-4f66-b7b3-58f65ff65352
Enter fullscreen mode Exit fullscreen mode

Next, create two sets of credentials—one for the administrator and one for the door phone.

To create a set of credentials, issue the following command:

rctl credentials create --insecure
Enter fullscreen mode Exit fullscreen mode

You must do this twice, one for the Door Phone and one for Admin. Please set the Door Phone username to doorphone1 and the Admin to admin

Your output will be similar to this:

This utility will help you create a new set of Credentials.
Press ^C at any time to quit.
? Friendly Name Door Phone #1 - Credentials
? Username doorphone1
? Password [hidden]
? Ready? Yes
Creating Credentials Door Phone - Credentials... 5fbc7367-a59d-4555-9fc4-a15ff29c24c8
Enter fullscreen mode Exit fullscreen mode

Finally, create Agents to represent the Door Phone and the Admin using the following command:

rctl agents create --insecure
Enter fullscreen mode Exit fullscreen mode

Follow the prompt and ensure that the username matches that of the credentials.

Your output will look similar to this:

This utility will help you create a new Agent.
Press ^C at any time to quit.
? Friendly Name Door Phone #1
? Select a Domain sip.local
? Username doorphone1
? Credentials Name Door Phone #1 - Credentials
? Max Contacts 1
? Privacy None
? Enabled? Yes
? Ready? Yes
Creating Agent Door Phone #1... 662a379d-66f1-4e6e-9df5-5126f1dcb930
Enter fullscreen mode Exit fullscreen mode

Be sure to repeat the process for the Admin.

You might use the get subcommand for any previously created resources to verify your settings. For example, to get a list of Agents, you might run this:

rctl agents get --insecure
Enter fullscreen mode Exit fullscreen mode

Configuring the door phone

The configuration on your door phone will depend on the make and model. However, generally speaking, it should have the following parameters:

  • Username
  • Password
  • Domain
  • Proxy/Server

For a Fanvil iS20, the configuration will be like this:

Video feed from a Fanvil unit

Building a barebones tool for calling

To create the SIP Agent, we will use the SimpleAgent implementation SIP.js, which is perfect for testing.

For a bare-bone SIP Agent, copy the following code in a file named index.html:

Filename voipnet/index.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta charset="utf-8" />
  <title>Video Feed</title>
  <style>
    h1 { font-family: 'Courier New', Courier, monospace; }
  </style>
</head>

<body>
  <h1>Door Phone Video Feed</h1>
  <div style="border: 1px solid black;  width: 300px; height: 300px;">
    <video id="remoteVideo" autoplay muted style="background-color: black; height: 100%"></video>
  </div>

  <br />

  <button id="callButton">Call Door Phone</button>
  <button id="hangupButton">Hangup</button>

  <audio style="display: none" id="remoteAudio" controls>
    <p>Your browser doesn't support HTML5 audio.</p>
  </audio>
  <script type="module">
    import { Web } from "https://unpkg.com/sip.js@0.21.2/lib/index.js";

    document.addEventListener('DOMContentLoaded', () => {
      const remoteVideo = document.getElementById('remoteVideo');
      const callButton = document.getElementById('callButton');
      const hangupButton = document.getElementById('hangupButton');
      const remoteAudio = document.getElementById('remoteAudio');

      const config = {
        server: "ws://localhost:5062",
        aor:  "sip:admin@sip.local",
        doorPhoneAor: "sip:doorphone1@sip.local"
      }

      const options = {
        aor: config.aor,
        media: {
          constraints: { audio: true, video: true },
          remote: {
            audio: remoteAudio,
            video: remoteVideo
          }
        },
        userAgentOptions: {
          authorizationUsername: "admin",
          authorizationPassword: "1234",
        }
      };

      const simpleUser = new Web.SimpleUser(config.server, options);

      callButton.addEventListener('click', async() => {
        await simpleUser.connect();
        simpleUser.call(config.doorPhoneAor);
      });

      hangupButton.addEventListener('click', () => {
        simpleUser.hangup();
      });
    });
  </script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

Then, lunch the SIP Agent with:

npx http-server .
Enter fullscreen mode Exit fullscreen mode

Calling the door phone from the web browser

Now that created a SIP agent using SIP.js, we only need to register the door phone to Routr and press the "Call Door Phone" button in the web browser.

If you have issues calling the door phone, please inspect the browser's console for errors.

The SIP agent should connect to the door phone, and you should see a video feed.

Example of the output:

Video feed from a Fanvil unit

What's next?

Please comment if you find this tutorial helpful and check out the following relevant tutorials:

Top comments (2)

Collapse
 
prawee profile image
Prawee Wongsa

great job

Collapse
 
psanders profile image
Pedro Sanders

Thanks for the support, @prawee. You rock!