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-plugin

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

$ flutter pub add stringee_plugin:^1.3.2

Check out plugin's documentation for more information.

Step 3: Setup

Android

Stringee Plugin 1.3.2 requires JDK 17 and Android API 21 or later. Set compileSdk to 36 and minSdk to 21 or later in android/app/build.gradle.

  1. Permissions The Stringee Android SDK requires some permissions from your AndroidManifest
    • Open up android/app/src/main/AndroidManifest.xml
    • Add the following lines:
      <!-- 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" />
      <!-- Audio and camera access -->
      <uses-permission android:name="android.permission.RECORD_AUDIO" />
      <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
      <uses-permission android:name="android.permission.CAMERA" />
      <!-- Bluetooth headset support -->
      <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
      <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
      <uses-feature android:name="android.hardware.camera" android:required="false" />

      Request RECORD_AUDIO, CAMERA, and, on Android 12 or later, BLUETOOTH_CONNECT at runtime before using the corresponding feature.

  2. ProGuard/R8 rules for Stringee and WebRTC are included in the plugin. Keep your application's existing minification configuration; you do not need to enable minification specifically for Stringee.

iOS

Stringee Plugin 1.3.2 requires iOS 13.0 or later. Set platform :ios, '13.0' in your ios/Podfile.

  1. From the command line run following command:

    pod install --repo-update
  2. After running CocoaPods, open the generated .xcworkspace file.

  3. Add the following keys to ios/Runner/Info.plist before the final </dict> element:

    <key>NSCameraUsageDescription</key>
    <string>$(PRODUCT_NAME) uses Camera</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>$(PRODUCT_NAME) uses Microphone</string>

Step 4: Connect to Stringee Server

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

For testing, go to Dashboard -> Tools -> Generate Access token and generate an access_token. In production, your server should generate the access_token. See the access token examples.

  1. Initialize StringeeClient:
    import 'dart:async';
    import 'package:stringee_plugin/stringee_plugin.dart';
    ...
    final StringeeClient _client = StringeeClient();
    StreamSubscription? _clientSubscription;
    StreamSubscription? _roomSubscription;
  2. Register the client's events in your State

    class _MyHomePageState extends State<MyHomePage> {
    ...
        @override
        void initState() {
            super.initState();
            ...
            /// Listen for the StringeeClient event
            _clientSubscription = _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;
                    default:
                        break;
                }
            });
            ...
        }
        ...
        /// Invoked when the StringeeClient is connected
        void handleDidConnectEvent() {}
    
        /// Invoked when the StringeeClient is disconnected
        void handleDiddisconnectEvent() {}
    
        /// Invoked when the StringeeClient connection fails
        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) {}
        ...
    }
  3. Connect
        @override
            void initState() {
                super.initState();
                ...
                String token = 'PUT YOUR TOKEN HERE';
                _client.connect(token);
                ...
            }

Step 5: Connect room

After the client connects to Stringee server, follow these steps to connect to a room:

  1. Initialize StringeeVideo

    import 'package:stringee_plugin/stringee_plugin.dart';
    ...
    late StringeeVideo _video;
    ...
    _video = StringeeVideo(_client);

    When creating StringeeVideo, you must pass StringeeClient, which you used to connect in step 4.

  2. Create and join room

    To create a room, use the Room Management REST API.

    To join the room, you need a room credential named room_token. In production, the room token should be generated by your server as described in Room token.

    StringeeVideoRoom? _room;
    StringeeVideoTrack? _localTrack;
    StringeeVideoTrackInfo? _remoteTrackInfo;
    StringeeVideoTrack? _remoteTrack;
    ...
    _video.joinRoom('YOUR_ROOM_TOKEN').then((value) {
        if (value['status']) {
            _room = value['body']['room'];
            registerRoomEvents(_room!);
            List<StringeeVideoTrackInfo> trackInfos = value['body']['videoTrackInfos'];
            List<StringeeRoomUser> users = value['body']['users'];
        }
    });

    In which:

    • trackInfos: list StringeeVideoTrackInfo available in room
    • users: list StringeeRoomUser available in room
  3. Register the room's events

    /// Register events only after joinRoom returns a StringeeVideoRoom object.
    void registerRoomEvents(StringeeVideoRoom room) {
        _roomSubscription = 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;
            case StringeeRoomEvents.trackReadyToPlay:
                handleTrackReadyToPlayEvent(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(StringeeVideoTrackInfo addTrackInfo) {
        _remoteTrackInfo = addTrackInfo;
    }
    
    /// Invoked when the remove track from room
    void handleRemoveVideoTrackEvent(StringeeVideoTrackInfo removeTrackInfo) {
        _remoteTrackInfo = null;
        _remoteTrack = null;
    }
    
    /// Invoked when receive message in room
    void handleReceiveRoomMessageEvent(Map<dynamic, dynamic> bodyMap) {}
    
    /// Invoked when track is ready to display video
    void handleTrackReadyToPlayEvent(StringeeVideoTrack track) {
        _remoteTrack = track;
    }

    Step 6: Create local video track and publish to room

/// Create video track options
StringeeVideoTrackOption options = StringeeVideoTrackOption(
    audio: true,
    video: true,
    screen: false,
);
/// Create local video track
_video.createLocalVideoTrack(options).then((value) {
    if (value['status']) {
        /// Save the local track, then publish it to the room.
        _localTrack = value['body'];
        _room!.publish(_localTrack!).then((value) {
            if (value['status']) {
                // Success
            }
        });
    }
});

Step 7: Subscribe to another video track

After receiving another video track information, you need to subscribe the track to display the video

final trackInfo = _remoteTrackInfo;
if (trackInfo == null) {
    return;
}
StringeeVideoTrackOption options = StringeeVideoTrackOption(
    audio: trackInfo.audioEnable,
    video: trackInfo.videoEnable,
    screen: trackInfo.isScreenCapture,
);

_room!.subscribe(trackInfo, options).then((value) {
    if (value['status']) {
        // Success
    }
});

Step 8: Display track

After subscribing another video track successfully or publishing your track successfully, you can display the video

final track = _remoteTrack;
if (track == null) {
    return const SizedBox.shrink();
}
StringeeVideoView videoView = track.attach(
    isMirror: track.isLocal,
    height: 200.0,
    width: 150.0,
    scalingType: ScalingType.fit,
);
...
return new Scaffold(
    backgroundColor: Colors.black,
    body: new Stack(
        children: <Widget>[
            ...
            videoView,
        ],
    ),
);

Step 9: Unpublish video track

If you want to stop publishing your track in the room, remove it by unpublishing it:

final localTrack = _localTrack;
if (localTrack == null) {
    return;
}
_room!.unpublish(localTrack).then((result) {
    if (result['status']) {
        // Success
    }
});

Step 10: Unsubscribe video track

If you don't want to receive another track's audio or video in the room, you can unsubscribe this track:

final trackInfo = _remoteTrackInfo;
if (trackInfo == null) {
    return;
}
_room!.unsubscribe(trackInfo).then((value) {
    if (value['status']) {
        // Success
    }
});

Step 11: Leave room

To leave the room, call leave(...) on the StringeeVideoRoom object:

_room!.leave(allClient: false).then((result) {
    if (result['status']) {
        // Success
    }
});

Step 12: Mute

Mute the local sound:

bool mute = true; // true: mute, false: unmute
final localTrack = _localTrack;
if (localTrack == null) {
    return;
}
localTrack.mute(mute).then((result) {
    if (result['status']) {
        ///success
    }
});

Step 13: Switch camera

Switch the local camera:

final localTrack = _localTrack;
if (localTrack == null) {
    return;
}
localTrack.switchCamera().then((result) {
    if (result['status']) {
        ///success
    }
});

Step 14: Turn on/off video

Turn on/off video:

bool enableVideo = true; // true: turn on, false: turn off
final localTrack = _localTrack;
if (localTrack == null) {
    return;
}
localTrack.enableVideo(enableVideo).then((result) {
    if (result['status']) {
        ///success
    }
});

Sample

You can view a completed version of this sample app on GitHub: Stringee Flutter plugin example