Suggestions

close search

Getting started with Stringee Call2 API using Flutter Plugin

Step 1: Prepare

  1. Before using Stringee Call2 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

  2. Create a Project on Stringee Dashboard

    Stringee create Project

  3. 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. Stringee buy Number

  4. 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

    Stringee Project answer_url

    If you do not have answer_url, you can use the following Project's answer_url to speed up 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.

    • Configure Number's answer_url: To receive a phone-to-app call, configure your Number's answer_url

    Stringee Number answer_url

    If you do not have answer_url, you can use the following Number's answer_url to speed up the process:

    Number's answer_url for Phone-to-App call (The call is routed to Your App, which is 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)

    When building an application, you should use your own answer_url.

Step 2: Install stringee-plugin

Install stringee-plugin from pub.dev by running the following command from the project root:

$ flutter pub add stringee_plugin

Check out plugin's documentation for more information.

Step 3: Setup

Android

  1. Permissions

    The Stringee Android SDK requires some permissions from your AndroidManifest. Open up android/app/src/main/AndroidManifest.xml then add the following lines:

    <!--Internet-->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    
    <!--Record-->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    
    <!--Audio-->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
    
    <!--Camera-->
    <uses-permission android:name="android.permission.CAMERA"/>
    
    <uses-feature
       android:name="android.hardware.camera"
       android:required="true"/>
    <uses-feature android:name="android.hardware.camera.autofocus"/>
    
    <!--Bluetooth-->
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> <!--Require for android 12 or higher-->
    <uses-feature
       android:name="android.hardware.bluetooth"
       android:required="false"/>
    <uses-feature
       android:name="android.hardware.bluetooth_le"
       android:required="false"/>
    
    <!--Graphic-->
    <uses-feature
       android:glEsVersion="0x00020000"
       android:required="true"/>
  2. 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. Create file proguard-rules.pro in your app/ dir and insert inside:

    -dontwarn org.webrtc.**
    -keep class org.webrtc.** { *; }
    -keep class com.stringee.** { *; }

    Then add the following lines to /app/buidl.gradle :

    android {
      ...
      buildTypes {
         ...
         release {
            ...
            useProguard true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
         }
      }
    }

iOS

  1. From the command line run following command:

    pod install --repo-update
  2. After running cocoapods command, open project file .xcworkspace

  3. In the "Build Settings" tab → "Other linker flags" add "$(inherited)" flag

  4. In the "Build Settings" tab → "Enable bitcode" select "NO"

  5. 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>
  6. In the "Build Settings" tab → "Allow Non-modular includes in Framework Modules" select "YES"

Step 4: Connect to Stringee Server

To connect to Stringee Server, 3-party authentication is required as described here: Client authentication

For testing purpose, go to Dashboard -> Tools -> Generate Access token and generate an access_token. In production, your server should generate the access_token. Sample code generates access token here: https://github.com/stringeecom/server-samples/tree/master/access_token

  1. Initialize StringeeClient:

    import 'package:stringee_plugin/stringee_plugin.dart';
    ...
    StringeeClient _client = StringeeClient();
  2. Register the client's events in your State

    // Listen for the StringeeClient event
    _client.eventStreamController.stream.listen((event) {
     Map<dynamic, dynamic> map = event;
     switch (map['eventType']) {
       case StringeeClientEvents.didConnect:
         handleDidConnectEvent();
         break;
       case StringeeClientEvents.didDisconnect:
         handleDiddisconnectEvent();
         break;
       case StringeeClientEvents.didFailWithError:
         int code = map['body']['code'];
         String msg = map['body']['message'];
         handleDidFailWithErrorEvent(code,msg);
         break;
       case StringeeClientEvents.requestAccessToken:
         handleRequestAccessTokenEvent();
         break;
       case StringeeClientEvents.didReceiveCustomMessage:
         handleDidReceiveCustomMessageEvent(map['body']);
         break;
       case StringeeClientEvents.incomingCall2:
         StringeeCall2 call2 = map['body'];
         handleIncomingCall2Event(call2);
         break;
       default:
         break;
     }
    });
    
    ...
    /// Invoked when the StringeeClient is connected
    void handleDidConnectEvent() {}
    
    /// Invoked when the StringeeClient is disconnected
    void handleDiddisconnectEvent() {}
    
    /// Invoked when StringeeClient connect false
    void handleDidFailWithErrorEvent(int code, String message) {}
    
    /// Invoked when your token is expired
    void handleRequestAccessTokenEvent() {}
    
    /// Invoked when get Custom message
    void handleDidReceiveCustomMessageEvent(Map<dynamic, dynamic> map) {}
    
    /// Invoked when receive an incoming of StringeeCall2
    void handleIncomingCall2Event(StringeeCall2 call2) {}
  3. Connect

String token = 'PUT YOUR TOKEN HERE'
_client.connect(token);

Step 5: Make an outgoing call

After the client connects to Stringee server, follow these steps to make a call:

  1. Initialize StringeeCall2

    import 'package:stringee_plugin/stringee_plugin.dart';
    ...
    StringeeCall2 _call2;
    ...
    _call2 = StringeeCall2(_client);
  2. Register the call2's events in your State

    // Listen for the StringeeCall event
    _call2.eventStreamController.stream.listen((event) {
     Map<dynamic, dynamic> map = event;
     switch (map['eventType']) {
       case StringeeCall2Events.didChangeSignalingState:
         handleSignalingStateChangeEvent(map['body']);
         break;
       case StringeeCall2Events.didChangeMediaState:
         handleMediaStateChangeEvent(map['body']);
         break;
       case StringeeCall2Events.didReceiveCallInfo:
         handleReceiveCallInfoEvent(map['body']);
         break;
       case StringeeCall2Events.didHandleOnAnotherDevice:
         handleHandleOnAnotherDeviceEvent(map['body']);
         break;
       case StringeeCall2Events.didReceiveLocalStream:
         handleReceiveLocalStreamEvent(map['body']);
         break;
       case StringeeCall2Events.didReceiveRemoteStream:
         handleReceiveRemoteStreamEvent(map['body']);
         break;
       default:
         break;
     }
    });
    ...
    /// Invoked when get Signaling state
    void handleSignalingStateChangeEvent(StringeeSignalingState state) {}
    
    /// Invoked when get Media state
    void handleMediaStateChangeEvent(StringeeMediaState state) {}
    
    /// Invoked when get Call info
    void handleReceiveCallInfoEvent(Map<dynamic, dynamic> info) {}
    
    /// Invoked when an incoming call is handle on another device
    void handleHandleOnAnotherDeviceEvent(StringeeSignalingState state) {}
    
    /// Invoked when get Local stream in video call
    void handleReceiveLocalStreamEvent(String callId) {}
    
    /// Invoked when get Remote stream in video call
    void handleReceiveRemoteStreamEvent(String callId) {}
  3. Make a call

Step 6: Handle an incoming call

When the client receives an incoming call from handleIncomingCall2Event(), use a StringeeCall received from handleIncomingCall2Event. Then follow these steps:

  1. Initialize the call

    /// Invoked when receive an incoming of StringeeCall2
    void handleIncomingCall2Event(StringeeCall2 call2) {
     _call2 = call2;
     // Must initAnswer before answer a call
     _call2.initAnswer();
    }
  2. Answer a call

    _call2.answer();

Step 7: Make a video call

  1. A StringeeCall2 is a voice call by default. If you want to make a video call, you must change value of field isVideoCall in your parameters to true

  2. Receive and display the local video

    Using our StringeeVideoView to display the local video

    void handleReceiveLocalStreamEvent(String callId) {
     setState(() {
       widget.hasLocalStream = true;
       widget.callId = callId;
     });
    }
    ...
    Widget localView = widget.hasLocalStream
       ? StringeeVideoView(
           callId, /// callId of StringeeCall
           true, /// true - local video, false - remote video
         )
       : Placeholder();
    ...
    return Scaffold(
            body: Stack(
              children: [
                remoteView,
                localView,
                ],
              ),
            );
  3. Receive and display the remote video

    Using our StringeeVideoView to display the remote video

    ...
    void handleReceiveRemoteStreamEvent(String callId) {
     setState(() {
       widget.hasRemoteStream = true;
       widget.callId = callId;
     });
    }
    ...
    Widget remoteView = widget.hasRemoteStream
         ? StringeeVideoView(
             callId,  /// callId of StringeeCall
             false, /// true - local video, false - remote video
           )
         : Placeholder();
    ...
    return Scaffold(
            body: Stack(
              children: [
                remoteView,
                localView,
                ],
              ),
            );

Step 8: Hangup

Hangup a call:

_call2.hangup();

Step 9: Reject

Reject a call:

_call2.reject();

Step 10: Mute

Mute the local sound:

bool mute = true; // true: mute, false: unmute
_call2.mute(mute);

Step 11: Manager audio device

Manager output audio device by using singleton class StringeeAudioManager:

  1. Listening for audio device change events:

    AudioDevice? selectedAudioDevice; // Default audio device
    List<AudioDevice> availableAudioDevices = []; // List of available audio devices
    ...
    // Create StringeeAudioEvent
    StringeeAudioEvent audioEvent = StringeeAudioEvent(onChangeAudioDevice: (selectedAudioDevice, availableAudioDevices) {
      // Save list of available audio devices and selected audio device
      this.availableAudioDevices = availableAudioDevices;
      this.selectedAudioDevice = selectedAudioDevice;
      // For the first time, you need choose an audio device that you want to use in your call. 
      // E.g: Video call get AudioDevice with type is AudioType.speakerPhone from availableAudioDevices or which device you want to use then call selectDevice(AudioDevice device) method
    });
    // Register the audioEvent to StringeeAudioManager
    StringeeAudioManager().addListener(audioEvent);
  2. Start audio manager:

    You need to start the audio manager before using it.

    StringeeAudioManager().start();
  3. Select audio device:

    To select an audio device, you can use the following code:

    // Select audio device
    StringeeAudioManager().selectDevice(audioDevice);
  4. Release audio manager:

    Before your app is closed, you should release the audio manager to avoid bugs when the call is ended or the app is closed:

    // Stop listening for audio events
    StringeeAudioManager().removeListener(audioEvent);
    // Stop the audio manager
    StringeeAudioManager().stop();

Step 12: Switch camera

Switch the local camera:

_call2.switchCamera();

Step 13: Turn on/off video

Turn on/off video:

bool enableVideo = true; // true: turn on, false: turn off
_call2.enableVideo(enableVideo);

Step 15: Handle incoming call notification

In case your app is in the background or terminated, you need to handle call notification by following this doc: https://developer.stringee.com/docs/push-notification/flutter.

Sample

You can view a full version of this sample app on GitHub: https://github.com/stringeecom/flutter-samples/tree/master/call_sample