How to use In-App Calling (WebRTC)
In this guide we will show you how to use In-App Calling to place voice calls to web and mobile devices.
Bandwidth offers an In-App Calling solution that allows our customers to use WebRTC voice capabilities present in web and mobile devices to place calls to critical destinations served by the Bandwidth voice network. This allows access to Bandwidth network services, quality, and reach to advance any and all business needs surfaced by web browsers and mobile applications.
The Bandwidth In-App Calling capability is designed for simplicity, reliability and voice quality; leveraging Bandwidth's global voice network to deliver a voicepath that is managed from end to end.
Getting Started
As Bandwidth operates two separate networks for US & Canada and Global please refer to the relevant guide based on your use case.
US & Canada Network
A Bandwidth WebRTC Gateway is deployed in the US region. If your end-users are going to generate calls from the US & Canada region we recommend using this gateway. Other regions can be used but may incur latency.
Please ensure the following steps have been completed:
-
You have already created and set up your Bandwidth US account.
-
You have contracted for In-App calling and your account has been enabled for this service. Please contact your account manager if you have not done this.
Overview
Bandwidth In-App Calling is delivered by way of an SDK that is provided to the customer (that's you) to support development of your client experience. These Web and Mobile device SDKs enable the development of web and mobile applications that can negotiate with our Bandwidth WebRTC Gateway to establish voice calls into our network. The SDKs manage the initialization, call creation, call management, and call state change events that are needed to provide a comprehensive calling user experience.
In addition to managing the relationship with the WebRTC Gateway, our Bandwidth capabilities are also used to secure the connection by granting tokens that will ensure that calls via the Gateway will be limited to (and billed to) your account.
How it Works
Specifying Call Routing
Caller ID (From)
When placing a WebRTC call, the client must specify the From and To numbers. The From is the caller ID, a Bandwidth phone number, used to place an outbound call.
The Client SDK initiates a call into the WebRTC gateway, the From number generates an outbound call to the called destination, the To number which specifies the location.
Security and Permissions
In order to place calls into the Bandwidth Network (and of course be subject to billing for those calls) it is necessary to securely generate a Token that is associated with your account. That token is used by the web or mobile application user to indicate that the communications with the WebRTC gateway should be accepted by that gateway.
Authentication for In-App Calling
Retrieving an access token
CAUTION
The token should be retrieved from a server running in a secure environment and securely provided to clients. Client-side javascript does not have a mechanism for hiding these credentials so DO NOT place these directly in your client-side code.
Bandwidth accepts no responsibility for the loss of account credentials and any resulting network traffic, fraud, or undesired account access that results from failing to manage account access credentials in a completely secure manner.
The process to retrieve an access token requires you to have your API credentials. You will then be able to make a call to our token endpoint with these credentials.
In order to retrieve the token, you will use Basic Authentication APIUser:APISecret. Below is a sample request:
curl --request POST \
--url https://id.bandwidth.com/api/v1/oauth2/token \
--header 'Authorization: Basic aGdyYW5nZXI6Q3IwMGskaEBuayQ=' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
Now that we've shown the request, let's break down the parts of the API call.
Headers
Authorization - Authentication is required. You MUST provide your APIUser and APISecret using a Base64-encoded header with the Basic authentication scheme. The header value before encoding should take the form Basic <APIUser>:<APISecret>.
Content-Type - You MUST use application/x-www-form-urlencoded. This will URL encode (aka percent-encode) the parameters making them into key=value pairs which will be separated by an ampersand &.
Body
grant_type Currently, we only support client_credentials OAuth2 grant_type.
Response
An example response is:
{
`"access_token":` `"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImFsb2hvbW9yYSJ9.e30.kl3HYFQIcP4xZd78wUkdXxntxBu1d7b5ZCt99qVObC-gUZd5KSq2J7Q5rDb2LjP1_WVndcLQSqCoq3Anvp03hJWM6mamZL3dWHxjGLwkrIlzmNx9ZFGhTGIEsYLyaQqy8MonWYw2mJ4Z0APEfTVbTBHNIGrm_9GT6rIkdOwQFM-XgH1Tau4JbpFJun3n6o15WTgjzdEj9fIwd385CPwL-pAmOiozbYWUEzgqkXjSGHI11hiLDu-tv_8Ds06Cx4iCnL1F6_dFrnpD3CF0i6JJYVrvLmi6vgzoxp9YEIRBwaOZTSuYuYt03SQfbMZy8L2Z71sRKLLGt3TrxgtwyjefpQ",`
`"access_token_id":` `"a5xA3xMKEggGwvpSLtk2lRb",`
`"token_type":` `"Bearer",`
`"expires_in":` `60`
}
Let's see what each item in the response object is meant for:
access_token: This is the JSON Web Token (JWT) that will be passed in the Authorization header of the requests to the In-App Calling API. NOTE: The example above does not contain a valid token and cannot be used to actually authenticate.
access_token_id: This will be the ID of the access token to prevent tokens from being re-used. It will be the same as the jti claim within the access token.
token_type: This is used to identify the type of token and also the prefix to be used in the Authorization header.
expires_in: This is the length of time, in seconds, before a token expires. In the example above the value is 60. This means the token will be valid for 60 seconds (1 minutes) before it expires. You should use the token until 10-30 seconds before expiration, at which point you MUST request a new token in the same manner as described above.
Using the Access Token
Once you have obtained the token you can perform authenticated requests to the WebRTC Gateway using the Bandwidth WebRTC SDK.
Generating credentials for an access token
To generate an access token please contact your account manager and this will be provided to you.
Once you have received your credentials you can call our identity services endpoint. Please refer to (tbd link to be provided for EA) for more information. During the beta period please contact your account manager for the API method required to retrieve an access token.
As the token will be visible within your application we strongly advise to only use this scope. The token should be fetched from a server running in a secure environment, and provided to clients in a secure manner.
We recommend regenerating the token every 30 seconds before expiry. It is not advisable to regenerate the token for every in-app voice call as this will create an unnecessary delay in the call being connected.
Bandwidth accepts no responsibility for the loss of account credentials and any resulting network traffic, fraud, or undesired account access that results from failing to manage account access credentials in a completely secure manner. Minting of tokens is not included as a client SDK capability for the above reason.
Resources
The following resources are available to aid in the development of quality solutions using Bandwidth In-App calling.
SDKs
SDKs exposing all key capabilities are available in raw and packaged form.
Environment | Package site |
Web / Javascript | bw-webrtc-sdk |
Android / Kotlin | bandwidth-kotlin-webrtc |
iOS / Swift | https://github.com/Bandwidth-samples/swift-webrtc-sdk |
Sample Applications
Getting started with Bandwidth's In-App Calling SDKs is simple with sample applications to assist in the learning process.
Name | Language | Description | Sample Application |
Dialpad | React / Node | A simple dial pad application used to create calls using our WebRTC SDK. | in-app-calling-dialpad-node-react |
Android / Kotlin Sample | Kotlin | A simple dial pad application used to create calls using our Android SDK. | in-app-calling-kotlin-sample |
iOS / Swift Sample | Swift | A simple dial pad application used to create calls using our iOS SDK. | in-app-calling-swift-sample |
In-App Calling SDK
The key SDK functions are described in terms of the Javascript webrtc-browser SDK. Similar usage patterns show up in the Android and IOS client SDKs.
There are two important classes in the WebRTC Client SDK - The User Agent (UA) and the Session. The UA is used to encapsulate the data and behaviors associated with the client itself, and the Session encapsulates actual in progress calls. A real world model would be the phone (UA) and calls made by the phone (Session).
Initialization and management of the client, and the initiation of calls is managed by the UA, and once a call is in progress it can be altered by changes to the Session.
Client Initialization
There are a number of key initialization steps that are required in the web client before the client is capable of placing calls. This ensures that:
The Client is appropriately configured, and capable of connecting to the WebRTC Gateway.
The account security token has been made available to the SDK to ensure that all calls will be associated with the correct account.
The events that will happen on active calls, and with the websocket connection can be appropriately intercepted by the client and handled.
The connection with the WebRTC Gateway can be established and removed.
This is done by making changes to an instance of the UA with some of the methods described below.
Once all of the above initialization steps have been completed, the client is in a position to place calls to the Bandwidth Network via the WebRTC Gateway, and respond to events from the network that result.
The below methods on phone instances of the UA take care of readying the phone to make calls.
phone.setServerConfig(serverAddresses, serverDomain, iceServers);
The setServerConfig method takes 3 parameters that establish the relationship between the client and the network for making calls. This method should be called prior to any attempts to perform any other client or calling functions.
There are three parameters for the setServerConfig method call:
serverAddresses: List of the Bandwidth WebRTC gateway FQDN
serverDomain: String containing the domain name to use in interactions with the WebRTC Gateway. This domain is a necessary portion of the endpoint addresses.
iceServers: List of the STUN and TURN servers, containing STUN:// or TURN:// IP addresses. This optional parameter is by default set as an empty list []. If it is used as an empty list, an external STUN server is not used during the creation of the call. This mode is useful when the client has direct visibility of the public network IP addresses of the Bandwidth WebRTC Gateway.
phone.setOAuthToken(token)
All calls from web and mobile clients require a security token generated by Bandwidth to be present with any request to establish a call to the Bandwidth Network. The setOAuthToken method invoked on an instance of the UA will cause this token to be registered with the client, and used in subsequent calls to ensure that the calls are authentic and contain the correct account information.
There is a single parameter that is required for the setOAuthToken method - a string containing the Token that was previously fetched from Bandwidth.
Token: a string containing the Token minted by Bandwidth to secure the traffic from the client.
The token is cryptographically protected from tampering, and establishes the account ownership of the customer application, ensuring that our customers will only be presented and billed for traffic that they have authorized.
phone.setListeners()
There is little value in sending a call towards the Bandwidth network if there is no feedback on events that happen in the network while completing the call. The setListeners UA method allows the registration of callback functions that (if registered) will be invoked on various network and connection events, allowing the client to respond to normal and error conditions that are encountered in the network.
The setListeners configuration method is invoked on an instance of the UA, and has a single listeners object as the parameter. This listener object contains six or more elements, each of which is a function that will be invoked on the detection of the event in the network. These functions will be described in greater detail elsewhere.
The individual functions that can be provided in the listeners object are...
loginStateChanged: function(isLogin, cause)
The provided function is invoked when the connection state between the Bandwidth WebRTC server and the Client changes. This can occur when a requested connection is established in a bi-directional manner, or when that connection fails. There are other causes of this event that will be documented elsewhere.
outgoingCallProgress: function(call, response)
The provided function is invoked when there is a change in the state of the call from the client. A classic example of this is when a ringing state is detected.
callTerminated: function(call, message, cause)
the provided function is invoked when the call ends. A cause for the end of the call is provided.
callConfirmed: function(call, message, cause)
The provided function is invoked when the system has determined that the call has been accepted by the Bandwidth WebRTC gateway, and further progress of the call is anticipated.
callShowStreams: function(call, localStream, remoteStream)
The provided function is invoked when media streams have been established. This often corresponds with the answering of the call.
callHoldStateChanged(call, isHold, isRemote)
If the system is configured to support hold state conditions, this function will be invoked on changes in the hold state of the call.
phone.init()
The init method is used to establish the connection to the Bandwidth WebRTC gateway. This method is only valid once the UA has been configured.
phone.deinit()
The deinit method reverses the action of the init method, removing the connection between the client and the Bandwidth WebRTC gateway.
phone.isInitialized()
Checks if the init() method was called.
phone.checkAvailableDevices()
This method has two functions:
Checks if the WebRTC API is supported in the used browser.
If this is not supported, the Promise object will be rejected with the following string: “WebRTC is not supported in the browser”.
Checks available devices (speaker, microphone and camera).
If the speaker is not connected, the speaker Promise object is rejected with the following string: “Missing a speaker! Please connect one and reload”
If the microphone is not connected, the microphone is rejected with the following string: “Missing a microphone! Please connect one and reload”
Managing Calls from the Client
Once the UA has been configured and the connection to the Bandwidth WebRTC Gateway has been established, it is time to make and manage calls. Once the setup is done, the rest is relatively straightforward.
activeCall = phone.call(tn)
The call method invoked on the UA instance will cause the configured and connected UA to launch a call towards the Bandwidth network. Yes - it is that simple.
The call method takes one parameter:
The parameter represents the destination telephone number for the outbound call. This TN should be a valid NANP telephone number.
The call method returns an instance of a Session object, providing a handle that can be used for subsequent modification of the call while it is in progress. The methods applicable to the Session object instance will be discussed below.
In the sections below, the string activeCall will represent the Session instance used for subsequent call modifications.
activeCall.terminate();
Once a call has been established, one of the possible call modification actions is to end (or terminate) the call. The terminate method on the Session object will be used to cause the call to end.
activeCall.sendDTMF(digit)
If a session represents a call that has established an end-to-end connection, the sendDTMF method will cause a specified DTMF tone to the far end of the call connection. The digit parameter is single character string containing a character from the set [0-9,#,*]. This action is undefined if there is no audio connection to the destination of the call.
activeCall.hold(placeCallOnHold)
If a session represents a call that has established an end-to-end connection, the hold method places the call on a (local) hold, or removes it from a hold state if it is currently held. The single boolean parameter indicates that the call is to be held (true) or removed from hold (false). This action is undefined if there is no audio connection to the destination of the call.
activeCall.muteAudio(muted)
Once a call has been established, this method could be used to mute the audio.
activeCall.isLocalHold()
Returns a boolean value indicating whether the call is currently held as the result of an activeCall.hold(true) action.