Suggestions

close search

Getting started with Stringee Video Conference API using Flutter Plugin

Step 1: Prepare

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

Step 2: Install stringee-flutter-plugin

  1. 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
  2. Install the plugin by running the following command from the project root:
    $ flutter pub get

Step 3: Setup

Android

  1. Permissions The Stringee Android SDK requires some permissions from your AndroidManifest
    • Open up android/app/src/main/AndroidManifest.xml
    • Add the following lines:
      // for internet access
      <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" />
      // 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" />
  2. Proguard If your project uses ProGuard, you may have to add the following settings to the ProGuard configuration file to ensure Stringee builds correctly:
    • Create file proguard-rules.pro in your app/ dir and insert inside:
      #Flutter Wrapper
      -dontwarn org.webrtc.**
      -keep class org.webrtc.** { *; }
      -keep class com.stringee.** { *; }
    • 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 run 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

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

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

    class _MyHomePageState extends State<MyHomePage> {
    ...
        @override
        Future<void> initState() {
            super.initState();
            ...
            /// 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.incomingCall:
                        StringeeCall call = map['body'];
                        handleIncomingCallEvent(call);
                        break;
                    case StringeeClientEvents.incomingCall2:
                        StringeeCall2 call = map['body'];
                        handleIncomingCall2Event(call);
                        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 StringeeCall
        void handleIncomingCallEvent(StringeeCall call) {}
    
        /// Invoked when receive an incoming of StringeeCall2
        void handleIncomingCall2Event(StringeeCall2 call) {}
        ...
    }
  3. Connect
        @override
            Future<void> initState() {
                super.initState();
                ...
                String token = 'PUT YOUR TOKEN HERE'
                _client.connect(token);
                ...
            }

Step 5: Connect room

After the client connects to Stirngee server, follows these steps to connect room:

  1. Initialize StringeeVideo
    import 'package:stringee_flutter_plugin/stringee_flutter_plugin.dart';
    ...
    StringeeVideo _video;
  2. Create and connect to room

In order to create room, you will need to use rest api, described here: https://developer.stringee.com/docs/rest-api-reference/room-management.

In order to connect to room, you will need token to the room credential : room_token. In production application, the room_token should be generated by your server sample code generates room token here: https://developer.stringee.com/docs/room-token

```
StringeeRoom _room;
List<StringeeVideoTrack> tracks = [];
List<StringeeRoomUser> users = [];
...
_video.connect('YOUR_ROOM_TOKEN').then((value) {
    if (value['status']) {
        _room = value['body']['room'];
        tracks = value['body']['videoTracks'];
        users = value['body']['users'];
    }
});
```

In which:

  1. Register the room's events

    /// Listen for the StringeeRoom event
    _room.eventStreamController.stream.listen((event) {
        Map<dynamic, dynamic> map = event;
        switch (map['eventType']) {
            case StringeeRoomEvents.didJoinRoom:
                handleJoinRoomEvent(map['body']);
                break;
            case StringeeRoomEvents.didLeaveRoom:
                handleLeaveRoomEvent(map['body']);
                break;
            case StringeeRoomEvents.didAddVideoTrack:
                handleAddVideoTrackEvent(map['body']);
                break;
            case StringeeRoomEvents.didRemoveVideoTrack:
                handleRemoveVideoTrackEvent(map['body']);
                break;
            case StringeeRoomEvents.didReceiveRoomMessage:
                handleReceiveRoomMessageEvent(map['body']);
                break;
            default:
                break;
        }
    }
    ...
    
    /// Invoked when the another user join room
    void handleJoinRoomEvent(StringeeRoomUser joinUser) {}
    
    /// Invoked when the another user leave room
    void handleLeaveRoomEvent(StringeeRoomUser leaveUser) {}
    
    /// Invoked when the add track to room
    void handleAddVideoTrackEvent(StringeeVideoTrack addTrack) {}
    
    /// Invoked when the remove track from room
    void handleRemoveVideoTrackEvent(StringeeVideoTrack removeTrack) {}
    
    /// Invoked when receive message in room
    void handleReceiveRoomMessageEvent(Map<dynamic, dynamic> bodyMap) {}

    Step 6: Create local video track and publish to room

/// Create video track options
StringeeVideoTrackOptions options = StringeeVideoTrackOptions(
    audio: true,
    video: true,
    screen: false,
);
/// Create local video track
_video.createLocalVideoTrack(options).then((value) {
    if (value['status']) {
    /// After create Track success, you can publish track to room
    _room.publish(value['body']).then((value) {
        if (value['status']) {
            }
        });
    }
});

Step 7: Subscribe another video track

After receiver another video track, you need to subscribe track to display video

StringeeVideoTrackOptions options = StringeeVideoTrackOptions(
    audio: track.audioEnable,
    video: track.videoEnable,
    screen: track.isScreenCapture,
);

_room.subscribe(track, options).then((value) {
    if (value['status']) {
        setState(() {
            _trackList.add(track);
        });
    }
});

Step 8: Display track

After Subscribe another video track success or punlish your track success, you can display video

StringeeVideoView videoView = track.attach(
    isOverlay: true,
    height: 200.0,
    width: 150.0,
    scalingType: ScalingType.fit,
);
...
return new Scaffold(
    backgroundColor: Colors.black,
    body: new Stack(
        children: <Widget>[
            ...
            videoView,
        ],
    ),
);

Step 8: Un publish video track:

If you don't want to show your track in room anymore, you can remove your track in room by un publish it:

_room.unPublish(_localTrack).then((result) {
     if (result['status']) {
        }
    });

Step 9: Un subscribe video track:

If you don't want to receive another track's audio or track'svideo in room anymore, you can un subscribe this track:

_room.unsubscribe(removeTrack).then((value) {
    if (value['status']) {
    }
});

Step 10: Leave room

After you unpublish your track in room, you need to release this and then you can leave room

_room.unPublish(your_track).then((result) {
    if (result['status']) {
        your_track.close().then((value) {
            if (result['status']) {
                // allClient: - true: All devices connected as your userId leave room, false: only this devices leave room
                _room.leave(allClient: false).then((value) {
            });
          }
        });
      }
    });

Step 11: Mute

Mute local sound:

```
bool mute = true; // true: mute, false: unmute
your_track.mute(mute).then((result) {
    bool status = result['status'];
    if (status) {
        ///success
        }
    }
});
```

Step 12: Switch camera

Switch camera in local:

```
your_track.switchCamera().then((result) {
    bool status = result['status'];
    if (status) {
        ///success
    }else{
        ///false
    }
});
```

Step 13: Turn on/off video

Turn on/off video:

```
bool enableVideo = true; // true: turn on, false: turn off
your_track.enableVideo(enableVideo).then((result) {
    bool status = result['status'];
    if (status) {
        ///success
    }else{
        ///false
    }
});
```

Step 14: Share the screen (require android API >= 21)

  1. Create capture screen track:

    Before start capture screen, you need to create and start a Foreground service with foregroundServiceType is mediaProjection.

    StringeeVideoTrack screenTrack;
    bool _sharingScreen = false;
    ...
    _video.createCaptureScreenTrack().then((result) {
        bool status = result['status'];
        if (status) {
            setState(() {
                _sharingScreen = true;
                screenTrack = result['body'];
              });
            // After create capture screen track success, you can publish this track to room
            _room.publish(screenTrack).then((result) {
            if (result['status']) {
                // success
            }
          });
        }
    });
  2. Display capture video:

    After start capture success, you will receive a StringeeVideoTrack which is your capture screen track or other screen track from didAddVideoTrack:

    Widget screenView = (_sharingScreen)
        ? screenTrack.attach(
            alignment: Alignment.topRight,
            isOverlay: true,    /// required in android for make sure which overlaps the other
            margin: EdgeInsets.only(top: 100.0, right: 25.0),
            height: 200.0,
            width: 150.0,
          )
        : Placeholder();
    ...
    return new Scaffold(
      backgroundColor: Colors.black,
      body: new Stack(
        children: <Widget>[
            ...
            screenView
        ],
      ),
    );
    ...
  3. Stop capture screen:

Like local track if you don't want to share screen track anymore, you can unpublish this track, follow step 8.

Sample

You can view a completed version of this sample app on GitHub: https://github.com/stringeecom/stringee_flutter_plugin/tree/master/example