flutter_pitel_voip 1.0.10+5
flutter_pitel_voip: ^1.0.10+5 copied to clipboard
flutter_pitel_voip is package support for voice-over-IP (VoIP) call. Support VoIP call between 2 extension or outgoing call mobile phone number.
flutter_pitel_voip
Integrate VoIP call to your project #
flutter_pitel_voip is package support for voip call. Please contact pitel to use the service.
Demo #

Pitel Connect Flow #
When user make call from Pitel Connect app, Pitel Server pushes a notification for all user login (who receives the call). When user "Accept" call, extension will re-register to receive call.

Features #
- Register Extension
- Call
- Hangup
- Turn on/off micro
- Turn on/of speaker
Installation #
- Install Packages
- Run this command:
flutter pub add flutter_pitel_voip
- Or add pubspec.yaml:
flutter_pitel_voip: any
- Get package
flutter pub get
- Import
import 'package:flutter_pitel_voip/flutter_pitel_voip.dart';
- Configure Project
- In file app.dart config easyloading
import 'package:flutter_easyloading/flutter_easyloading.dart';
// ....
return MaterialApp.router(
// ...
builder: EasyLoading.init(),
)
Android:
- In file
android/app/src/main/AndroidManifest.xml
<manifest...>
...
// Request permission
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
</manifest>
- Request full screen intent permission (Android 14+)
For Android 14 (API level 34) and above, you need to request the full screen intent permission to show incoming call notifications when the app is locked or in the background:
import 'package:flutter_callkit_incoming_timer/flutter_callkit_incoming.dart';
// Request permission in your app initialization or before making/receiving calls
await FlutterCallkitIncoming.requestFullIntentPermission();
This permission allows the app to launch a full-screen intent for incoming calls, ensuring users can see and answer calls even when the device is locked.
- In file
android/app/proguard-rules.pro. Proguard Rules: The following rule needs to be added in the proguard-rules.pro to avoid obfuscated keys:
# KEEP plugin Android classes
-keep class com.hiennv.flutter_callkit_incoming.** { *; }
# Keep Gson classes & TypeToken if plugin uses Gson
-keep class com.google.gson.** { *; }
-keepclassmembers class com.google.gson.reflect.TypeToken { *; }
IOS
- Request permission in file
Info.plist
<key>NSMicrophoneUsageDescription</key>
<string>Use microphone</string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
<string>voip</string>
</array>
- Make sure platform ios
13.0inPodfile
platform :ios, '13.0'
- Pushkit/ Push notification - Received VoIP and Wake app from Terminated State.
Note Please check PUSH_NOTIF.md. setup Pushkit (for IOS), push notification (for Android).
Troubleshooting #
[Android only]: If you give a error flutter_webrtc when run app in android. Please update code in file
$HOME/.pub-cache/hosted/pub.dartlang.org/flutter_webrtc-{version}/android/build.gradle
dependencies {
// Remove
// implementation 'com.github.webrtc-sdk:android:104.5112.03'
// Replace
implementation 'io.github.webrtc-sdk:android:104.5112.09'
}
Example #
Please checkout repo github to get example
Usage #
- In file
app.dart, Wrap MaterialApp with PitelVoip widget Please follow example
Note: handleRegisterCall, handleRegister, registerFunc in here
Widget build(BuildContext context) {
return PitelVoip( // Wrap with PitelVoip
handleRegister: handleRegister, // Handle register
handleRegisterCall: handleRegisterCall, // Handle register call
child: MaterialApp.router(
...
),
);
}
- In file
home_screen.dart. Please follow example. Add WidgetsBindingObserver to handle AppLifecycleState change
...
Widget build(BuildContext context) {
return PitelVoipCall(
// Wrap with PitelVoipCall
bundleId: '${bundle_id}',
appMode: 'dev', // dev or production
sipInfoData: sipInfoData,
goBack: () {
// go back function
},
goToCall: () {
// go to call screen
},
onCallState: (callState) {
// IMPORTANT: Set callState to your global state management. Example: bloc, getX, riverpod,..
// Example riverpod
// ref.read(callStateController.notifier).state = callState;
},
onRegisterState: (String registerState) {
// get Register Status in here
},
child: ...,
);
}
Properties
| Prop | Description | Type | Default |
|---|---|---|---|
| bundleId | bundleId IOS, packageId android | String | Required |
| appMode | debug mode or release mode | String | Required |
| sipInfoData | SIP information data | () {} | Required |
| goBack | goback navigation | () {} | Required |
| goToCall | navigation, go to call screen | () {} | Required |
| onCallState | set call status | (callState) {} | Required |
| onRegisterState | get extension register status | (String registerState) {} | Required |
| child | child widget | Widget | Required |
Register extension from data of Tel4vn provide. Example: 101, 102,… Create 1 button to fill data to register extension.
ElevatedButton(
onPressed: () asyns {
final PushNotifParams pushNotifParams = PushNotifParams(
teamId: '${apple_team_id}',
bundleId: '${bundle_id}',
);
final sipInfoData = SipInfoData.fromJson({
"authPass": "${Password}",
"registerServer": "${Domain}",
"outboundServer": "${Outbound Proxy}",
"port": PORT,
"accountName": "${UUser}", // Example 101
"displayName": "${Display Name}",
"wssUrl": "${URL WSS}"
});
final pitelClient = PitelServiceImpl();
final pitelSetting = await pitelClient.setExtensionInfo(sipInfoData, pushNotifParams);
// IMPORTANT: Set pitelSetting to your global state management. Example: bloc, getX, riverpod,..
// Example riverpod
// ref.read(pitelSettingProvider.notifier).state = pitelSettingRes;
},
child: const Text("Register"),),
- Logout extension
pitelClient.logoutExtension(sipInfoData);
- In file
call_screen.dartExample
import 'package:flutter/material.dart';
import 'package:flutter_pitel_voip/flutter_pitel_voip.dart';
class CallPage extends StatelessWidget {
const CallPage({super.key});
@override
Widget build(BuildContext context) {
// IMPORTANT: Get callState from your global state management. Example: bloc, getX, riverpod,..
// Example riverpod
// final callState = ref.watch(callStateController);
return CallScreen(
callState: callState, // callState from state management you set before
goBack: () {
// Call your go back function in here
},
bgColor: Colors.cyan,
);
}
}
Properties
| Prop | Description | Type | Default |
|---|---|---|---|
| goBack | go back navigation | () {} | Required |
| bgColor | background color | Color | Required |
| txtMute | Text display of micro mute | String | Optional |
| txtUnMute | Text display of micro unmute | String | Optional |
| txtSpeaker | Text display speaker | String | Optional |
| txtOutgoing | Text display direction outgoing call | String | Optional |
| txtIncoming | Text display direction incoming call | String | Optional |
| textStyle | Style for mic/speaker text | TextStyle | Optional |
| titleTextStyle | Style for display phone number text | TextStyle | Optional |
| timerTextStyle | Style for timer text | TextStyle | Optional |
| directionTextStyle | Style for direction text | TextStyle | Optional |
| showHoldCall | Show action button hold call | bool | Optional |
- Outgoing call
pitelCall.outGoingCall(
phoneNumber: "",
handleRegisterCall: (){},
);
Properties
| Prop | Description | Type | Default |
|---|---|---|---|
| phoneNumber | phone number for call out | String | Required |
| handleRegisterCall | re-register when call out | () {} | Required |
| nameCaller | set name caller | String | Optional |
How to test #
Using tryit to test voip call connection & conversation Link: https://tryit.jssip.net/ Setting:
- Access to link https://tryit.jssip.net/
- Enter extension: example 102
- Click Setting icon
- Enter information to input field

- Save
- Click icon -> to connect
