Telnyx Flutter Voice SDK
Enable Telnyx real-time communication services on Flutter applications (Android / iOS / Web) :telephone_receiver: :fire:Quick Start with Telnyx Common (Beta)
Looking for a faster implementation? Check out Telnyx Common - available on pub.dev. Telnyx Common is a comprehensive Flutter package that abstracts away the complexity of implementing WebRTC voice calling functionality. It sits on top of the lower-leveltelnyx_webrtc package and provides a unified, easy-to-use API for developers who want to integrate voice calling capabilities into their Flutter applications without dealing with the intricate details of WebRTC, push notifications, and platform-specific implementations.
This is the quickest way to implement the SDK with minimal setup and configuration.
Note: Telnyx Common is currently in beta. While it significantly simplifies implementation, you may encounter some limitations or changes as the library evolves.
Table of Contents
- Features
- Usage
- Basic Usage
- Call Quality Metrics
- Advanced Usage - Push Notifications
- AI Agent Usage
- Additional Resources
- License
Features
- Create / Receive calls
- Hold calls
- Mute calls
- Dual Tone Multi Frequency
- Call quality metrics monitoring
Usage
SIP Credentials
In order to start making and receiving calls using the TelnyxRTC SDK you will need to get SIP Credentials:
- Access to https://portal.telnyx.com/
- Sign up for a Telnyx Account.
- Create a Credential Connection to configure how you connect your calls.
- Create an Outbound Voice Profile to configure your outbound call settings and assign it to your Credential Connection.
Platform Specific Configuration
Android
If you are implementing the SDK into an Android application it is important to remember to add the following permissions to your AndroidManifest in order to allow Audio and Internet permissions:iOS
on the iOS platform, you need to add the microphone permission to your Info.plist file:Basic Usage
Telnyx Client
TelnyxClient() is the core class of the SDK, and can be used to connect to our backend socket connection, create calls, check state and disconnect, etc. Once an instance is created, you can call the .connect() method to connect to the socket with either a token or credentials (see below). An error will appear as a socket response if there is no network available:Logging Configuration
The SDK provides a flexible logging system that allows you to control the verbosity of logs and even implement your own custom logging solution. There are two main aspects to configure:- Log Level
The
LogLevelenum determines which types of logs are displayed:
- Custom Logger
You can implement your own logging solution by extending the
CustomLoggerabstract class:
Config class:
Logging into Telnyx Client
To log into the Telnyx WebRTC client, you’ll need to authenticate using a Telnyx SIP Connection. Follow our quickstart guide to create JWTs (JSON Web Tokens) to authenticate. To log in with a token we use the connectWithToken() method. You can also authenticate directly with the SIP Connectionusername and password with the connectWithCredential() method:
Creating a call invitation
In order to make a call invitation, we first create an instance of the Call class with the .call instance. This creates a Call class which can be used to interact with calls (invite, accept, decline, etc). To then send an invite, we can use the .newInvite() method which requires you to provide your callerName, callerNumber, the destinationNumber (or SIP credential), and your clientState (any String value).Accepting a call
In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response callbacks:Decline / End Call
In order to end a call, we can get a stored instance of Call and call the .endCall(callID) method. To decline an incoming call we first create the call with the .createCall() method and then call the .endCall(callID) method:DTMF (Dual Tone Multi Frequency)
In order to send a DTMF message while on a call you can call the .dtmf(callID, tone), method where tone is a String value of the character you would like pressed:Mute a call
To mute a call, you can simply call the .onMuteUnmutePressed() method:Toggle loud speaker
To toggle loud speaker, you can simply call .enableSpeakerPhone(bool):Put a call on hold
To put a call on hold, you can simply call the .onHoldUnholdPressed() method:Call Quality Metrics
The SDK provides real-time call quality metrics through theonCallQualityChange callback on the Call object. This allows you to monitor call quality in real-time and provide feedback to users.
Enabling Call Quality Metrics
To enable call quality metrics, set thedebug parameter to true when creating or answering a call:
CallQualityMetrics Properties
TheCallQualityMetrics object provides the following properties:
| Property | Type | Description |
|---|---|---|
jitter | double | Jitter in seconds (multiply by 1000 for milliseconds) |
rtt | double | Round-trip time in seconds (multiply by 1000 for milliseconds) |
mos | double | Mean Opinion Score (1.0-5.0) |
quality | CallQuality | Call quality rating based on MOS |
inboundAudio | Map<String, dynamic>? | Inbound audio statistics |
outboundAudio | Map<String, dynamic>? | Outbound audio statistics |
CallQuality Enum
TheCallQuality enum provides the following values:
| Value | MOS Range | Description |
|---|---|---|
excellent | MOS > 4.2 | Excellent call quality |
good | 4.1 <= MOS <= 4.2 | Good call quality |
fair | 3.7 <= MOS <= 4.0 | Fair call quality |
poor | 3.1 <= MOS <= 3.6 | Poor call quality |
bad | MOS <= 3.0 | Bad call quality |
unknown | N/A | Unable to calculate quality |
Advanced Usage - Push Notifications
Adding push notifications - Android platform
The Android platform makes use of Firebase Cloud Messaging in order to deliver push notifications. To receive notifications when receiving calls on your Android mobile device you will have to enable Firebase Cloud Messaging within your application. For a detailed tutorial, please visit our official Push Notification Docs. Note: for flutter, an easy way to add the firebase configuration after setting up the firebase project is to simply run theflutterfire configure command in the terminal. For example, if your firebase project is called myproject you would run flutterfire configure myproject. This will generate all the required files and configurations for your project.
The Demo app uses the FlutterCallkitIncoming plugin to show incoming calls. To show a notification when receiving a call, you can follow the steps below:
- Listen for Background Push Notifications, Implement the
FirebaseMessaging.onBackgroundMessagemethod in yourmainmethod
- Optionally Add the
metadatato CallKitParamsextrafield
- Handle the push notification in the
_firebaseMessagingBackgroundHandlermethod
- Use the
TelnyxClient.getPushMetaData()method to retrieve the metadata when the app comes to the foreground. This data is only available on 1st access and becomesnullafterward.
- To Handle push calls on foreground, Listen for Call Events and invoke the
handlePushNotificationmethod
Best Practices for Push Notifications on Android
- Request for Notification Permissions for android 13+ devices to show push notifications. More information can be found here
- Push Notifications only work in foreground for apps that are run in
debugmode (You will not receive push notifications when you terminate the app while running in debug mode). - On Foreground calls, you can use the
FirebaseMessaging.onMessage.listenmethod to listen for incoming calls and show a notification.
- To handle push notifications on the background, use the
FirebaseMessaging.onBackgroundMessagemethod to listen for incoming calls and show a notification and make sure to set theTelnyxClient.setPushMetaDatawhen user answers the call.
-
When you call the
telnyxClient.handlePushNotificationit connects to thetelnyxClient, make sure not to call thetelnyxClient.connect()method after this. e.g an Edge case might be if you calltelnyxClient.connect()on Widgetinitmethod it will always call theconnectmethod -
Early Answer/Decline : Users may answer/decline the call too early before a socket connection is established. To handle this situation,
assert if the
IncomingInviteParamsis not null and only accept/decline if this is availalble.
Adding push notifications - iOS platform
The iOS Platform makes use of the Apple Push Notification Service (APNS) and Pushkit in order to deliver and receive push notifications For a detailed tutorial, please visit our official Push Notification Docs- Register/Invalidate the push device token for iOS
- For foreground calls to work, you need to register with callkit on the restorationHandler delegate function. You can also choose to register with callkit using iOS official documentation on CallKit.
- Listen for incoming calls in AppDelegate.swift class
- Listen for Call Events and invoke the
handlePushNotificationmethod
Handling Late Notifications
If notifications arrive very late due to no internet connectivity, It is good to always flag it as a missed call. You can do that using the code snippet below :Best Practices for Push Notifications on iOS
- Push Notifications only work in foreground for apps that are run in
debugmode (You will not receive push notifications when you terminate the app while running in debug mode). Make sure you are inreleasemode. Preferably test using Testfight or Appstore. To test if push notifications are working, disconnect the telnyx client (while app is in foreground) and make a call to the device. You should receive a push notification.
New Push Notification Features
Simplified Push Decline Method
The SDK now includes a simplified method for declining push notifications. Previously, you needed to log back into the socket, listen for events, wait for an invite, and manually send a bye message. New Approach: The SDK automatically handles call decline when you set the decline flag insetPushMetaData. The SDK will:
- Connect to the socket
- Send a login message with
decline_push: trueparameter - Automatically handle ending the call
- Disconnect from the socket
10-Second Answer Timeout
The SDK now includes an automatic timeout mechanism for push notifications. When you accept a push notification but no INVITE message arrives on the socket within 10 seconds, the SDK will:- Automatically consider the call cancelled
- Emit a bye message internally with
ORIGINATOR_CANCELtermination reason (SIP code 487) - Prevent indefinite waiting for missing INVITE messages
- A push notification is accepted (
isAnswer: true) - The SDK connects and waits for an INVITE message
- No INVITE is received within 10 seconds
AI Agent Usage
The Flutter Voice SDK supports Voice AI Agent implementations. To get started, follow the steps described here to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps:1. Logging in to communicate with the AI Agent.
To connect with an AI Assistant, you can use theanonymousLogin method. This allows you to establish a connection without traditional authentication credentials.
This method takes a targetId which is the ID of your AI assistant, and an optional targetVersionId. If a targetVersionId is not provided, the SDK will use the latest version available.
Note: After a successful anonymousLogin, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant.
Here’s an example of how to use it:
newInvite method to start a conversation with the AI Assistant.
2. Starting a Conversation with the AI Assistant
After a successfulanonymousLogin, you can initiate a call to your AI Assistant using the newInvite method. Because the session is now locked to the AI Assistant, the destinationNumber parameter in the newInvite method will be ignored. Any values provided for callerName and callerNumber will be passed on, but the call will always be routed to the AI Assistant specified during the login.
Here is an example of how to start the call:
endCall, mute, etc.
3. Receiving Transcript Updates
During an AI Assistant conversation, the SDK provides real-time transcript updates that include both the caller’s speech and the AI Assistant’s responses. This allows you to display a live conversation transcript in your application. To receive transcript updates, set up theonTranscriptUpdate callback on your TelnyxClient instance:
TranscriptItem contains the following properties:
id: Unique identifier for the transcript itemrole: Either ‘user’ (for the caller) or ‘assistant’ (for the AI Agent)content: The transcribed text contenttimestamp: When the transcript item was created
anonymousLogin. Regular calls between users do not provide transcript functionality.
4. Sending a text message to the AI Agent
In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. To send a text message to the AI Agent, use thesendConversationMessage method on the active call instance:
- The
sendConversationMessagemethod is only available during AI Assistant conversations - Text messages sent this way will appear in the transcript updates alongside spoken conversation
- The AI Agent will process and respond to text messages just like spoken input
- You must have an active call established before sending text messages
Additional Resources
Questions? Comments? Building something rad? Join our Slack channel and share.License
MIT Licence © Telnyx