Before using Stringee Call API for the first time, you must have a Stringee account.
If you do not have a Stringee account, sign up for free here: https://developer.stringee.com/account/register
Create a Project on Stringee Dashboard
Buy a Number (optional)
For app-to-phone, phone-to-app calling, buy a Number from Dashboard. If you only need app-to-app calling, skip this step.
Configure answer_url
For more information about answer_url, read Stringee Call API Overview. You can view answer_url sample code here: https://github.com/stringeecom/server-samples/tree/master/answer_url
Configure Project's answer_url: To make an app-to-app, app-to-phone call, configure your Project's answer_url
If you do not have answer_url, you can use the following Project's answer_url to accelerate the process:
Project's answer_url for App-to-App call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=false
Project's answer_url for App-to-Phone call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=true
(Source code: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/project_answer_url.php)
When building an application, you should use your own answer_url.
If you do not have answer_url, you can use the following Number's answer_url to accelerate the process:
Number's answer_url for Phone-to-App call (The call is routed to Your App which authenticated by USER_ID):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=false&to_number=USER_ID
Number's answer_url for Phone-to-Phone call (The call is routed to TO_NUMBER):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=true&stringeeNumber=STRINGEE_NUMBER&to_number=TO_NUMBER
(Source code: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/number_answer_url.php)
Download stringee-flutter-plugin here: https://github.com/stringeecom/stringee_flutter_plugin
Put stringee-flutter-plugin into the same directory of your project them add the following to your pubspec.yaml
file
dependencies:
stringee_flutter_plugin:
git:
url: https://github.com/stringeecom/stringee_flutter_plugin.git
Install the plugin by running the following command from the project root:
$ flutter pub get
Permissions
The Stringee Android SDK requires some permissions from your AndroidManifest
android/app/src/main/AndroidManifest.xml
// for internet access
<uses-permission android:name="android.permission.INTERNET" />
// for audio access
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
// for camera access
<uses-permission android:name="android.permission.CAMERA" />
// for bluetooth
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
Proguard
If your project uses ProGuard, you may have to add the following settings to the ProGuard configuration file to make sure Stringee builds correctly:
proguard-rules.pro
in your app/
dir and insert inside:#Flutter Wrapper
-dontwarn org.webrtc.**
-keep class org.webrtc.** { *; }
-keep class com.stringee.** { *; }
/app/buidl.gradle
:android {
buildTypes {
release {
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Add volley library
In your file build.gradle
add this line:
dependencies {
implementation 'com.android.volley:volley:1.2.1'
}
From the command line run following command:
pod install --repo-update
After run cocoapods command, open project file .xcworkspace
In the "Build Settings" tab -> "Other linker flags" add "$(inherited)" flag
In the "Build Settings" tab -> "Enable bitcode" select "NO"
Right-click the information property list file (Info.plist) and select Open As -> Source Code. Then insert the following XML snippet into the body of your file just before the final element:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) uses Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) uses Microphone</string>
In the "Build Settings" tab -> "Allow Non-modular includes in Framework Modules" select "YES"
In order to connect to Stringee Server, 3-parties authentication is required as described here: Client authentication
For testing purpose, go to Dashboard -> Tools -> Generate Access token and generates an access_token. In production, the access_token should be generated by your server, sample code generates access token here: https://github.com/stringeecom/server-samples/tree/master/access_token
Initialize StringeeClient:
import 'package:stringee_flutter_plugin/stringee_flutter_plugin.dart';
...
StringeeClient _stringeeClient = StringeeClient();
Register the client's events in your State
/// Listen for the StringeeClient event
_stringeeClient.registerEvent(StringeeClientListener(
/// Invoked when the StringeeClient is connected
onConnect: (stringeeClient, userId) {
debugPrint('onConnect: $userId');
},
/// Invoked when the StringeeClient is disconnected
onDisconnect: (stringeeClient) {
debugPrint('onDisconnect');
},
/// Invoked when StringeeClient connect false
onFailWithError: (stringeeClient, code, message) {
debugPrint('onFailWithError: code - $code - message - $message');
},
/// Invoked when your token is expired
onRequestAccessToken: (stringeeClient) {
debugPrint('onRequestAccessToken');
},
/// Invoked when receive an incoming of StringeeCall
onIncomingCall: (stringeeClient, stringeeCall) {
debugPrint('onIncomingCall: callId - ${stringeeCall.id}');
},
/// Invoked when receive an incoming of StringeeCall2
onIncomingCall2: (stringeeClient, stringeeCall2) {
debugPrint('onIncomingCall2: callId - ${stringeeCall2.id}');
},
));
Connect
...
String token = 'PUT YOUR TOKEN HERE'
...
_stringeeClient.connect(token);
After the client connects to Stringee server, follows these steps to make a call:
Initialize StringeeCall
import 'package:stringee_flutter_plugin/stringee_flutter_plugin.dart';
...
StringeeCall _stringeeCall = StringeeCall(
_stringeeClient, /// stringeeClient using to connect
'caller_userId', /// caller id
'callee_userId', /// callee id
);
Register the call's events in your State
_stringeeCall.registerEvent(StringeeCallListener(
/// Invoked when the call's signaling state changes
onChangeSignalingState: (stringeeCall, signalingState) {
debugPrint('onChangeSignalingState: signalingState - $signalingState');
},
/// Invoked when the call's media state changes
onChangeMediaState: (stringeeCall, mediaState) {
debugPrint('onChangeMediaState: mediaState - $mediaState');
},
/// Invoked when receive call info
onReceiveCallInfo: (stringeeCall, callInfo) {
debugPrint('onReceiveCallInfo: callInfo - $callInfo');
},
/// Invoked when an incoming call is handle on another device
onHandleOnAnotherDevice: (stringeeCall, signalingState) {
debugPrint('onHandleOnAnotherDevice: signalingState - $signalingState');
},
/// Invoked when local stream in video call is ready to play
onReceiveLocalStream: (stringeeCall) {
debugPrint('onReceiveLocalStream');
},
/// Invoked when remote stream in video call is ready to play
onReceiveRemoteStream: (stringeeCall) {
debugPrint('onReceiveLocalStream');
},
/// Invoked when the current audio device changes in android
onChangeAudioDevice: (stringeeCall, selectedAudioDevice, availableAudioDevices) {
debugPrint('onChangeAudioDevice: selectedAudioDevice - selectedAudioDevice');
},
));
Make a call
_stringeeCall.makeCall(params).then((result) {
debugPrint('makeCall: ${result['message']} - callId - ${_call.id} - from - ${_call.from} - to - ${_call.to}');
});
When the client receives an incoming call from onIncomingCall(), initialize a StringeeCall as described in 4.1, 4.2. Then follow these steps:
Initialize the answer
_stringeeCall.initAnswer().then((event) {
debugPrint('initAnswer: ${result['message']}');
});
Answer
_stringeeCall.answer().then((result) {
debugPrint('answer: ${result['message']}');
});
isVideoCall
of StringeeCall
to true
.Receive and display the local video and the remote video
Using our StringeeVideoView
to display the video
Widget? localScreen = null;
Widget? remoteScreen = null;
...
_stringeeCall.registerEvent(StringeeCallListener(
...
/// Invoked when local stream in video call is ready to play
onReceiveLocalStream: (stringeeCall) {
debugPrint('onReceiveLocalStream');
setState(() {
localScreen = new StringeeVideoView(
stringeeCall.id!, /// callId of StringeeCall
true, /// true - local video, false - remote video
alignment: Alignment.topRight,
margin: EdgeInsets.only(top: 25.0, right: 25.0),
height: 150.0,
width: 100.0,
);
});
},
/// Invoked when remote stream in video call is ready to play
onReceiveRemoteStream: (stringeeCall) {
debugPrint('onReceiveLocalStream');
setState(() {
remoteScreen = new StringeeVideoView(
stringeeCall.id!, /// callId of StringeeCall
false, /// true - local video, false - remote video
);
});
},
...
));
...
return new Scaffold(
...
body: new Stack(
children: <Widget>[
remoteScreen != null ? remoteScreen! : Placeholder(color: Colors.transparent),
localScreen != null ? localScreen!: Placeholder(color: Colors.transparent),
...
],
),
);
Hang up a call:
_stringeeCall.hangup().then((result) {
debugPrint('hangup: ${result['message']}');
});
Reject a call:
_stringeeCall.reject().then((result) {
debugPrint('reject: ${result['message']}');
});
Mute the local sound:
bool mute = true; // true: mute, false: unmute
_stringeeCall.mute(mute).then((result) {
debugPrint('mute: ${result['message']}');
});
Switch to speakerphone or earpiece:
bool isSpeaker = true; // true: speakerphone, false: earpiece
_stringeeCall.setSpeakerphoneOn(isSpeaker).then((result) {
debugPrint('setSpeakerphoneOn: ${result['message']}');
});
Switch to bluetooth device or device speaker:
bool bluetoothScoOn = true; // true: bluetooth device, false: device speaker
_stringeeCall.setBluetoothScoOn(bluetoothScoOn).then((result) {
debugPrint('setBluetoothScoOn: ${result['message']}');
});
Switch the local camera:
_stringeeCall.switchCamera().then((result) {
debugPrint('switchCamera: ${result['message']}');
});
Turn on/off video:
bool enableVideo = true; // true: turn on, false: turn off
_stringeeCall.enableVideo(enableVideo).then((result) {
debugPrint('enableVideo: ${result['message']}');
});
You can view a full version of this sample app on GitHub: https://github.com/stringeecom/flutter-samples/tree/master/call_sample