PJSIP and RingCentral — Part 4: host it on AWS Lambda

Tyler Liu
RingCentral Developers
4 min readJan 26, 2021

Welcome to Part 4 of the PJSIP and RingCentral article series. In Part 1 we introduced PJSIP to you and we also showed you a simple demo on how you use PJSIP for making phone calls through RingCentral. In Part 2 we focused on medias, we talked about both using a media player and recorder, we also provided code snippets to use wav files in a phone call. In part 3, we talked about DTMF. In this part, we are going to try AWS Lambda.

Disclaimer

This article is just a pure technical experiment. It is by no means the best practice. It is just to try and evaluate the possibility to host a telephone service on AWS Lambda. AWS Lambda is not designed for long-running services. So our telephone service will make an outbound call and quit which takes merely a couple of seconds.

Create a docker image

Creating a docker image will be the very first step, because PJSIP cannot run directly on AWS Lambda. To do this we need to put it into a docker container. Here is the Dockerfile:

FROM ubuntu
LABEL maintainer="Tyler Liu (tyler.liu@ringcentral.com)"
RUN apt-get update && apt-get install -y wget build-essential pkg-config
RUN wget https://github.com/pjsip/pjproject/archive/2.10.tar.gz && tar -zxvf 2.10.tar.gz
WORKDIR /pjproject-2.10/
RUN ./configure && make dep && make && make install
COPY ./src/* /src/
WORKDIR /src/
CMD /src/run.sh

The Dockerfile is pretty self-explanatory. We start with a base Ubuntu image, then we compile PJSIP, and last we copy our source code into the image and set the startup command.

For the source code part, there are two main files, the first is the C++ PJSIP file: index.cpp. It starts a PJSIP phone, makes an outbound call to a pre-defined number, plays a pre-recorded audio file and quits. We recommend you read the first three articles, so you can easily do this.

./src/run.sh is of the following content:

#!/bin/bash
g++ -o /tmp/a.out ./index.cpp $(pkg-config --cflags --libs libpjproject)
export LD_LIBRARY_PATH=/pjproject-2.10/pjsip/lib:/pjproject-2.10/pjlib/lib:/pjproject-2.10/pjmedia/lib:/pjproject-2.10/pjlib-util/lib:/pjproject-2.10/pjnath/lib:/pjproject-2.10/third_party/lib /tmp/a.out

It simply compiles the index.cpp file and runs it.

Use the following command to build the docker image:

docker build -t rc-pjsip-aws-lambda-demo:latest .

Test the docker image locally

To do that make sure to run this:

docker run -it --rm rc-pjsip-aws-lambda-demo

If everything goes well, the target phone should ring. When you pickup the phone call you should be able to hear the pre-recorded audio playing. After about 20 seconds the call should hang up itself.

Push docker image to AWS ECR

First you will need to create an AWS ECR repo:

aws ecr create-repository --repository-name rc-pjsip-aws-lambda-demo --image-scanning-configuration scanOnPush=true

In the output message of the command above, you can find your AWS account ID, something like 1234567890.dkr.ecr.us-east-1.amazonaws.com in which1234567890 is your AWS account ID.

In the content below, we will use 1234567890 as sample/fake AWS account ID. You need to replace it with a real one.

Next you will to tag the docker image:

docker tag rc-pjsip-aws-lambda-demo:latest 1234567890.dkr.ecr.us-east-1.amazonaws.com/rc-pjsip-aws-lambda-demo:latest

Finally you will push it to remote:

aws ecr get-login-password | docker login --username AWS --password-stdin 1234567890.dkr.ecr.us-east-1.amazonaws.comdocker push 1234567890.dkr.ecr.us-east-1.amazonaws.com/rc-pjsip-aws-lambda-demo:latest

Deploy to AWS Lambda

We will use the the famous serverless framework. First we need to create a serverless.yml file. I am not going to post all the content here, please read the source code here to find it all.

It’s just like normal AWS Lambda functions, but with a docker image as the executable:

functions:
app:
image: 1234567890.dkr.ecr.us-east-1.amazonaws.com/rc-pjsip-aws-lambda-demo@sha256:366c648f3dc0bedfa50e60b7c28afd7be2f1e6fa5dd043703b7475a47b614a40
events:
- http: 'GET /call'

One command to deploy everything to remote: yarn sls deploy .

Test it

To do that use this code:

curl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/prod/call

Known issues

AWS API Gateway has a maximum timeout value of 30 seconds. So your phone call can only last around 20 seconds(because the app startup costs around 10 seconds). To workaround it, you can define a proxy method.

Summary

In this article, we created a docker image for RingCentral with PJSIP. And we also covered how to deploy this docker image as an AWS Lambda function. It might not be the best practice to host a telephone service but it is quite interesting to learn all the technical details. I hope you enjoy reading this article as much as I did writing it.

Please let us know what you think by leaving your questions and comments below. To learn even more about other features we have make sure to visit our developer site and if you’re ever stuck make sure to go to our developer forum.

Want to stay up to date and in the know about new APIs and features? Join our Game Changer Program and earn great rewards for building your skills and learning more about RingCentral!

--

--