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
Create a Project on Stringee Dashboard
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.
android/app/src/main/AndroidManifest.xml
// 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" />
// for bluetooth access
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
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'
}
}
}
From the command line run following command:
pod install --repo-update
After running 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"
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. Here is a sample code generates access token here: https://github.com/stringeecom/server-samples/tree/master/access_token
import 'package:stringee_plugin/stringee_plugin.dart';
...
StringeeClient _client = StringeeClient();
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;
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) {}
...
}
@override
Future<void> initState() {
super.initState();
...
String token = 'PUT YOUR TOKEN HERE'
_client.connect(token);
...
}
After the client connects to Stringee server, follow these steps to connect to a room:
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.
Create and join room
To create room, you will need to use rest api, described here: https://developer.stringee.com/docs/rest-api-reference/room-management.
To join the 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
late StringeeRoom? _room;
...
_video.joinRoom('YOUR_ROOM_TOKEN').then((value) {
if (value['status']) {
_room = value['body']['room'];
List<StringeeVideoTrackInfo> trackInfos = value['body']['videoTrackInfos'];
List<StringeeRoomUser> users = value['body']['users'];
}
});
In which:
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;
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(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) {}
/// Invoked when track is ready to display video
void handleTrackReadyToPlayEvent(StringeeVideoTrack track) {}
/// 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']) {
// Success
}
});
}
});
After receiving another video track information, you need to subscribe the track to display the video
StringeeVideoTrackOptions options = StringeeVideoTrackOptions(
audio: track.audioEnable,
video: track.videoEnable,
screen: track.isScreenCapture,
);
_room!.subscribe(trackInfo, options).then((value) {
if (value['status']) {
// Success
}
});
After subscribing another video track successfully or publishing your track successfully, you can display the 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,
],
),
);
If you don't want to stop showing your track in the room, you can remove your track from the room by unpublishing it:
_room!.unPublish(_localTrack).then((result) {
if (result['status']) {
// Success
}
});
If you don't want to receive another track's audio or video in the room, you can unsubscribe this track:
_room!.unsubscribe(removeTrackInfo).then((value) {
if (value['status']) {
// Success
}
});
To leave the room, you can call the following method:
_room!.leave(allClient: false).then((result) {
if (result['status']) {
// Success
}
});
Mute the local sound:
bool mute = true; // true: mute, false: unmute
your_track.mute(mute).then((result) {
if (result['status']) {
///success
}
});
Switch the local camera:
your_track.switchCamera().then((result) {
if (result['status']) {
///success
}
});
Turn on/off video:
bool enableVideo = true; // true: turn on, false: turn off
your_track.enableVideo(enableVideo).then((result) {
if (result['status']) {
///success
}
});
After leaving the room, you need to release all resources in the StringeeRoom. Call this function to release all resources:
_room!.destroy();
You can view a completed version of this sample app on GitHub: https://github.com/stringeecom/stringee_flutter_plugin/tree/master/example