Business Productivity
Building a PSTN call forwarding solution with the Amazon Chime SDK
The Amazon Chime SDK Public Switched Telephone Network (PSTN) Audio makes it easier for
developers to build customized telephony applications using the agility and operational simplicity of a
serverless AWS Lambda function. The CallAndBridge action enables developers to take an incoming call
from one phone number and forward/bridge the caller to a new outbound call. This is particularly useful
if you want to perform initial actions on the inbound call, like play a greeting or support IVR (Interactive
Voice Response) functionality before connecting the caller to the new outbound call. The destination
phone number may depend on factors like selections made in the IVR, time of day, or in a “follow-me”
type manner where you try connecting to a primary number, and attempt subsequent numbers if the
primary number(s) are unreachable. Using the CallAndBridge action also provides the ability to mask
personal phone numbers between callers and callees.
In this blog, we will walk through how to implement the CallAndBridge action to build a call forwarding
solution that includes a simple user interface (UI) to manage the mapping of inbound and outbound
phone numbers. The voice application is written as an AWS Lambda function using Python and provides
functionality to play a prompt or greeting to the inbound caller while the outbound call is established
before bridging the two participants together.
Call Forwarding Demo App Architecture
The AWS elements used in this demo are:
- Amazon Chime SDK PSTN Audio
- AWS Lambda
- Amazon DynamoDB
- Amazon Simple Storage Solution (S3)
- Amazon API Gateway
You can learn more about how to build PSTN-enabled voice applications in the Amazon Chime SDK by
consulting our documentation. Please note your AWS account will be charged for usage of these services.
The architecture includes the following components:
- handlerLambda – A Lambda function written in Python that updates the Product Type of
numbers in the Amazon Chime Phone Inventory and adds and removes numbers the DynamoDB
table. This is fronted by an API Gateway. - smaLambda – A Lambda function written in Python that is associated with the Amazon Chime
SDK PSTN Audio service and used to forward calls using the CallandBridge action - calledNumber – A DynamoDB table used to store where numbers should be forwarded to.
Managed by the local React client and queried by smaLambda Lambda function during call setup - outgoingWav – An S3 bucket to store wav files for playing customized messages
- PSTN Audio – Amazon Chime PSTN audio used to forward calls. Associated with the
smaHandler Lambda function - SIP Media Application rule – Amazon Chime SIP Media Application Rule used to route the
provisioned phone number to the smaLambda function - Voice Connector – Amazon Chime Voice Connector used to demonstrate changing Product Types of the
phone number - Phone Number – A number provisioned to use with the SIP Media Application rule
Prerequisites
- node V12+/npm installed
- yarn installed –
npm install --global yarn
- AWS Command Line Interface (AWS CLI) installed
- AWS Credentials configured for the account/region that will be used for this demo
- Permissions to create Amazon Chime SIP Media Applications and Phone Numbers (ensure your
Service Quota in us-east-1 or us-west-2 for Phone Numbers, Voice Connectors, SIP Media Applications &
SIP Media Application Rules have not been reached)
Deployment must be done in us-east-1 or us-west-2 to align with Amazon Chime SIP Media Application
resources
Walk-through
Deploying the back-end Resources
git clone https://github.com/aws-samples/amazon-chime-sma-call-forwarding
cd amazon-chime-sma-call-forwarding
./deploy.sh
Launching the local client
cd client
yarn
yarn start
After successfully deploying the CDK components, take note of the smaPhoneNumber in the output of the deployment script. This is the Amazon Chime SDK PSTN Audio phone number provisioned as described in the Resources Created section; it will be used as the inbound phone number in our demo.
We now want to setup a call forward for this number using the local React client. If you have started yarn successfully, it will output the URL that the client can be accessed – http://localhost:3000 – from here we can enable and disable call forwards.
To enable a call forward, first select “Forward a Number” and then select from the list the phone number that was created earlier. Next, populate the destination number in the “Number to Forward to” field.
Once submitted, make a test call to the phone number and you should be greeted with a “please wait while we connect your call” message while waiting for the destination number to answer – once answered, both participants can now converse, without either of the participants’ phone numbers have been revealed.
To disable a call forward, select “Remove a Forward”, select the number you want to remove the forward on, and select a Voice Connector to route the number to when not assigned to a SIP Media Application, and then click Submit. This demo created a Voice Connector specifically to demonstrate the moving of a number back and forth between your call forwarding application and a Voice Connector. You could have an on-site or cloud-based phone system registered with the Voice Connector where calls to the demo number would be routed to when not routed to the call forwarding application.
How it Works
Let’s first look at the components that are solely part of enabling and disabling call forwards. The local client is a simple React UI that communicates with the handlerLambda
function via API Gateway that configures the phone number Product Type and whether it is routed to your SIP Media Application or a Voice Connector. Enabling a forward also inserts a mapping of the dialed_number
to destination_number
into the calledNumber
DynamoDB table that the smaLambda
function will query when bridging calls. Disabling a forward removes the number mapping from the DynamoDB table.
At this point, we have the components that support the call flow. When a call is placed to the phone number configured with the SipMediaApplicationDialIn Product Type, a SIP Media Application rule will route the call to the SIP Media Application. This will invoke the smaLambda
function, which is the main call routing logic in this demo, with a NEW_INBOUND_CALL
event which calls new_call_handler
. In response the CallAndBridge action will be returned to the Amazon Chime SDK PSTN Audio service after querying DynamoDB for the destination number:
return respond(call_and_bridge_to_pstn_with_greeting(dialed_number, destination_number, 'please_wait_while_we_try_to_connect_you.wav'))
This will forward the incoming PSTN call to a new outbound call to the E.164 number stored in DynamoDB. The CallAndBridge action is encapsulated in the following function where we provide the greeting wav file in the optional RingbackTone
parameter:
def call_and_bridge_to_pstn_with_greeting(caller_id, destination, audio_file):
return {
'Type': 'CallAndBridge',
'Parameters': {
'CallTimeoutSeconds': 30,
'CallerIdNumber': caller_id,
'RingbackTone': {
'Type': 'S3',
'BucketName': os.environ['WavBucketName'],
'Key': audio_file
},
'Endpoints': [ {
'Uri': destination,
'BridgeEndpointType': 'PSTN'}]
}
}
It’s simple to change the behavior of the greeting played to the inbound caller by using the LoopGreetingWhileRinging
environment variable on the smaLambda function. By default (`True`) the greeting will be looped until the outbound destination number is answered. If we set this variable to False the greeting will be played in its entirety once before the outbound destination number is called. This results in a response to the `NEW_INBOUND_CALL` event with two separate actions, `PlayAudio` and `CallAndBridge`:
if loop_flag == 'True':
return respond(
call_and_bridge_to_pstn_with_greeting(
dialed_number,
destination_number,
'please_wait_while_we_try_to_connect_you.wav'))
else:
return respond(
play_audio(
call_id,
'please_wait_while_we_try_to_connect_you.wav'),
call_and_bridge_to_pstn(
dialed_number,
destination_number))
We can also remove the greeting entirely by using the call_and_bridge_to_pstn
Python function which does not pass a RingbackTone
parameter; the caller will immediately hear the ringing signal from the outbound call:
return respond(call_and_bridge_to_pstn(dialed_number, destination_number))
There are additional handlers added for failed actions that allow you to gracefully play a failure greeting to the inbound caller, hang up that call, or potentially try a second destination number in a “follow-me” type scenario should the first outbound destination be unreachable. Amazon CloudWatch Logs can be used to inspect verbose logging of call behavior to understand the exact flow the code takes for each call.
We can also use this solution to achieve number privacy between the two parties: the inbound caller has placed a call to the demo number and does not have visibility into what the final called destination number is. Similarly, when we create the outbound call we set the Caller ID to the demo number so the callee does not have visibility into the phone number of the inbound caller.
Cleanup
To clean up this demo, execute: cdk destroy
. Additionally, Amazon Chime SIP Media Applications, rules, Voice Connectors, and phone numbers should be manually removed in the Amazon Chime Console.
Conclusion
This demo has showcased how the Amazon Chime SDK PSTN Audio CallAndBridge action can be used for basic PSTN call bridging, amongst other actions such as PlayAudio and Hangup in a simple Python Lambda function. This blog also demonstrated how a simple table in DynamoDB can be used to store PSTN routing data. You can leverage the technology and the development patterns showcased in this demo to implement solutions that enable remote working, mobile workers with multiple contact phone numbers, Interactive Voice Response (IVR) menus and augment cloud-based or on-premise call centers while providing privacy on the calling and called party phone numbers. CallAndBridge is just one of a number of supported PSTN actions currently available.
See our github repo for the project code: https://github.com/aws-samples/amazon-chime-sma-call-forwarding
Additional reading
To read more about the Amazon Chime SDK PSTN Audio service visit https://docs.aws.amazon.com/chime/latest/dg/build-lambdas-for-sip-sdk.html
To learn more about our Chime Voice Connector SIP Trunking service, visit https://aws.amazon.com/chime/features/voice-connector/