Skip to main content

· 4 min read
Pedro Sanders

Last year, when I started assembling Team Fonoster, I published a post on Reddit that sparked a great conversation and placed Fonoster on Github's trending list even though we didn't have much to show.

As a result, I had the opportunity to interview dozens of CTOs from companies worldwide and speak with several investors who were interested in the idea of an open-source stack of Programmable Telecommunications.

In the interviews, I found we need an innovative approach to a cloud-based stack for Programmable Telecommunications.

Why we needed CPaaS in the first place?

Building an application that takes advantage of the existing Telecom network has always been a difficult task compared with, for example, building a web-based application.

This is difficult because it involves a particular set of skills that is challenging to find and can get really costly.

Let's face it, no one wants to read through dozens of RFCs to program a phone call.

So, when the API era arrived along with UCaaS and CPaaS providers, it was a no-brainer to use one of those providers to deploy a solution within weeks instead of spending months only to get a simple use-case.

So what's wrong with traditional CPaaS?

There is nothing wrong with traditional CPaaS. In fact, in most cases, using a CPaaS is a great option to deploy a Telecommunications solution.

However, even though the concept of using a CPaaS to go to market quickly is fantastic, it comes at a high price for some use-cases. After all, if something goes wrong, you will have no other option but to migrate to another CPaaS or build your own solution and start again on square zero.

Some companies complain about the high prices for using a CPaaS. A startup CTO once told me, “It almost feels that we are paying for a lot of features we don't need.” This is because, with a traditional CPaaS, you start on a pay-as-you-go model, but costs can quickly get out of control.

Other companies find themselves limited by their providers' features because with traditional CPaaS you have no option but to use what they have available. There is no chance for customization. And even though that's not a problem for most companies, it is a deal-breaker for technology companies.

Then you have use-cases, especially in the healthcare industry, that can't benefit from using a traditional CPaaS due to privacy concerns and local regulations.

In which of those categories does your company fall?

How can we make this better?

The primary innovation of Fonoster lies in researching and developing the means for creating a highly portable, cloud-based Programmable Telecommunications stack.

This Programmable Telecommunications stack will allow businesses to call an API to dial, answer a call, establish a video session, send SMS, etc. There won't be any concern about what servers and networks are doing with that information in the background.

Our overall approach to building Fonoster is to use existing open-source solutions that are best in their class when possible and build our own when necessary. We then integrate this individual open-source software into a cohesive set of APIs that resembles a traditional CPaaS.

For example, to start a simple Voice Application one could write a Javascript code like the one below:

const { VoiceServer } = require("@fonoster/voice");

const serverConfig = {
pathToFiles: `${process.cwd()}/sounds`,
};

new VoiceServer(serverConfig).listen(
async (req, res) => {
console.log(req);
await res.answer();
await res.play(`sound:${req.selfEndpoint}/sounds/hello-world.sln16`);
await res.hangup();
}
);

Or to make a call to the telephone network, you could use the SDK and write a simple script like this:

const Fonoster = require("@fonoster/sdk");
const callManager = new Fonoster.CallManager();

callManager.call({
from: "9842753574",
to: "17853178070",
webhook: "https://5a2d2ea5d84d.ngrok.io"
})
.then(console.log)
.catch(console.error);

Want to create a reminders application? No problem, in few easy steps, you can create and deploy a Cloud Function that will run based on a given Cron schedule.

First, initialize your Cloud Function with:

fonoster funcs:init

Then, edit the handler with the following code:

const Fonoster = require("@fonoster/sdk");
const callManager = new Fonoster.CallManager();

// 🚀 Let's get started
// Use fonoster funcs:deploy to send to the cloud functions
module.exports = async(request, response) => {
await callManager.call({
from: "9842753589",
to: "17853178070",
webhook: "https://5a2d2ea5d84d.ngrok.io"
})
return response.succeed("OK");
};

Finally, deploy to the Cloud Functions subsystem with a Cron string.

fonoster funcs:deploy --schedule "*/5 * * * *"

You get the idea.

The Cloud Functions capability if offered by the integration with OpenFaaS (by Alex Ellis)

What's next?

Be sure to check The essentials of building Voice Applications with Fonoster to overview the Programmable Voice features available on Project Fonoster.

Star the project on Github and contact us via:

· 3 min read
Pedro Sanders

At Fonoster Inc, we want to help companies and individuals that wish to adopt Fonoster as their Programmable Telecommunications solution. To help archive this goal, our team uses Cloud-Init for cloud instance initialization.

You can deploy Fonoster to all major public cloud providers, private cloud infrastructure, and bare-metal installations with Cloud-Init.

In this tutorial, we will also use Multipass.

Multipass is a Canonical project that offers a lightweight VM manager for Linux, Windows, and macOS. With Multipass, you can deploy Fonoster on Ubuntu in a local environment in a single command. This deployment method is by far the fastest way to get started with Fonoster.

Requirements

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

  • Multipass
  • NodeJS 14+ (Use nvm if possible)
  • Fonoster command-line tool (install with npm install -g @fonoster/ctl)

Deploying to Multipass

This method will not automatically enable TLS for you

Deploy Fonoster to Multipass with the following steps. First, download the cloud-config.txt file into a local directory with:

curl https://raw.githubusercontent.com/fonoster/fonoster/main/operator/cloud-config.txt -o cloud-config.txt

Since we are running locally, we have to modify the cloud-config to discover the private ipv4 instead of the public ipv4.

First, update cloud-config with:

sed -i.bak -e "s#publicv4#privatev4#g" "cloud-config.txt"

Then, from the same directory, fire up Multipass.

multipass launch --name fonoster --disk 8G --cpus 2 --mem 4G --cloud-init cloud-config.txt

You might see a timed out waiting for initialization to complete, especially in a slow Internet connection. Don't worry. The process will continue in the background.

You can access your VM and continue following the installation process with:

multipass shell fonoster
tail -f /var/log/cloud-init-output.log

Once you see "Cloud init is done!" the process is complete. If everything goes well, you will be able to log in to your Fonoster deployment. To authenticate for the first time to your deployment, first get your admin credentials with:

cat /opt/fonoster/config/admin_credentials

Your output will look like the one below.

{
"accessKeyId": "admin",
"accessKeySecret": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Next, from the host machine, obtain your VM's IP with:

multipass info fonoster

Look for the entry starting with IPv4.

Name:           fonoster
State: Running
IPv4: 192.168.64.39
172.17.0.1
172.24.0.1
...

With the accessKeyId, accessKeySecret, and your VM's IP address, you can now login using the command-line tool or access your server with the SDK.

What's next?

For more deployment options, be sure to check the operator's section of Fonoster's documentation.

Star the project on Github and contact us via:

· 7 min read
Pedro Sanders

The purpose of this tutorial is to show the basics of Fonoster. Here you will find how to create a Voice Application, add a Number, and then use that Number to originate a call. Please follow the guide in sequence, as each step builds on the last one.

Requirements

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

  • A set of credentials from here 👈
  • An account for access to a SIP Service Provider (For US and Canada, we recommend voip.ms)
  • NodeJS 14+ (Use nvm if possible)
  • Fonoster command-line tool install with npm install -g @fonoster/ctl
  • Ngrok install with npm install -g ngrok

You can login to the server with:

fonoster auth:login

And your output will be similar to:

Access your Fonoster infrastructure
Press ^C at any time to quit.
? api endpoint api.fonoster.io
? access key id psanders
? access key token *************************...
? ready? Yes
Accessing endpoint api.fonoster.io... Done

Then, set the default Project:

# Get the PROJECT_ID of the project using the 'projects:list' command 
fonoster projects:use ${PROJECT_ID}

Creating a basic Voice Application

A Voice Application is a server that takes control of the flow of a call.

A Voice Application can use any combination of the following verbs:

  • Answer - Accepts the call
  • Hangup - Closes the call
  • Play - It takes an URL or file and streams the sound back to the calling part
  • Say - It takes a text, synthesizes the text into audio, and streams the result
  • Gather - It waits for DTMF events and returns back the result
  • SGather - It listen for a stream DTMF events and returns back the result
  • Record - It records the voice of the calling party and saves the audio on the Storage sub-system
  • Mute - It tells the channel to stop sending media, thus effectively muting the channel
  • Unmute - It tells the channel to allow media flow

To create a Voice Application perform the following steps.

First, clone the NodeJS example template as follows:

git clone https://github.com/fonoster/nodejs-voiceapp

Next, install the dependencies:

cd nodejs-voiceapp
npm install

Finally, launch the Voice Application with:

npm start

Your output will look like this:

info: initializing voice server
info: starting voice server on @ 0.0.0.0, port=3000

Your app will live at http://127.0.0.1:3000. Be sure to leave the server up!

Using Ngrok to publish your Voice Application

Now that we have our Voice Application up and running, we need to make it available on the Internet——the fastest way to enable public access by using Ngrok.

For example, with ngrok, you can publish a web server with a single command.

On a new console, run Ngrok with the following command:

ngrok http 3000

The output will look like this:

ngrok_output

Leave this service running, and save the Forwarding URL for use in the next step.

Building a SIP Network

A SIP Network has all the building blocks needed to establish communication between two SIP endpoints (i.e., softphone, webphone, cellphone, the PSTN, etc.) We want to configure a Number and route the calls to our Voice Application on this guide.

Let's start by creating a SIP Service Provider.

Adding a SIP Service Provider

A SIP Service Provider is an organization that will terminate your calls to the phone network (or PSTN).

You will need the username, password, and host you obtained from your SIP Service Provider for this section.

Create a new provider with:

fonoster providers:create

The output will look similar to this:

This utility will help you create a new Provider
Press ^C at any time to quit.
? friendly name VOIPMS
? username 215706
? secret [hidden]
? host newyork1.voip.ms
? transport tcp
? expire 300
? ready? Yes
Creating provider YourServiceProvider... Done

Adding a SIP Number

A Number, often referred to as DID/DOD, is a number managed by your SIP Service provider.

If your Provider doesn't accept E164, you can append the --ignore-e164-validation

fonoster numbers:create --ignore-e164-validation

Here is an example of the output:

This utility will help you create a new Number
Press ^C at any time to quit.
? number in E.164 format (e.g. +16471234567) 9842753574
? service provider VOIPMS
? aor link (leave empty)
? webhook https://5a2d2ea5d84d.ngrok.io # Replace with the value you obtained from Ngrok
? ready? Yes
Creating number +17853178071... KyjgGEkasj

Be sure to replace the information with what was given to you by your Provider.

Creating a SIP Domain

A SIP Domain is a space within the SIP Network where SIP entities live (usually SIP Agents). To create a SIP Domain, you can use the command-line tool or the SDK.

In this step, you need to select the Number you just created as your Egreess Number. Also, make sure to use an "unclaimed" uri or you will receive this error: "› Error: This Domain already exists."

Create a new Domain with:

fonoster domains:create

Your output will look similar to this:

This utility will help you create a new Domain
Press ^C at any time to quit.
? friendly name Acme Corp
? domain uri (e.g acme.com) sip.acme.com
? egress number none
? egress rule .*
? ready? Yes
Creating domain Acme Corp... Jny9B_qaIh

In the demo server, you don't need to own the Domain. Any available URI is fair game!

Using the API to make a call

To make a call, you need install the SDK.

Install the SDK, from within the voiceapp, with:

npm install --save @fonoster/sdk 

Next, create the script call.js with the following code:

// This will load the SDK and reuse your Fonoster credentials
const Fonoster = require("@fonoster/sdk");
const callManager = new Fonoster.CallManager();

// Few notes:
// 1. Update the from to look exactly as the Number you added
// 2. Use an active phone or mobile
// 3. Replace the webhook with the one from your Ngrok
callManager.call({
from: "9842753574",
to: "17853178070",
webhook: "https://5a2d2ea5d84d.ngrok.io",
ignoreE164Validation: true
})
.then(console.log)
.catch(console.error);

Finally, run your script with: node call.js

If everything goes well, you will start seeing the output in the console you are running your Voice Application. You will also receive a call that will stream a "Hello World," which further confirms that everything is behaving as it should.

call_request

Troubleshooting

  1. Are you not receiving the call at all? The first thing to check is that your SIP Service Provider configuration is correct. Next, double-check the username, password, and host. If your Provider has an Admin console, check if you can see the registration from Fonoster.

Next, make sure the from matches the Number given to you by your Provider. Also, double-check the to has the correct prefix (for example, +1, etc.).

  1. You receive the call but immediately hang up (did not hear a sound) First, verify that Ngrok is still running. Next, compare Ngrok's URL with the webhook on your Number. They both need to match!

Then observe the console's output where your Voice Application is running, and see if there are any errors.

Giving feedback to Team Fonoster

We want to provide you with the best possible experience. To do that, we need your valuable feedback. Because we know you are busy, we provide two ways to get quick feedback from you. From the command line, use the fonoster bug command to start a GitHub issue. Or, you can use the fonoster feedback command to complete a short survey (which takes less than 30 seconds).

· One min read
Pedro Sanders

Welcome to Fonoster's blog section, if you want to contribute with a Tutorial or Guide let our team know via Discord, we always welcome new contributors.