Group video call
This page provides a code example for implementing a group video call.
Prerequisites
Before you begin, you must do the following:
- Initialize PlanetKit.
- Get a proper access token.
- Check the overall API usage flow in Group call flow.
Considerations for implementing a group video call
After calling joinConference()
, you must check the reason
property of the returned PlanetKitJoinConferenceResult
.
- If the
reason
isPlanetKitStartFailReason.none
, it means success. - Otherwise, it means failure and you must take an appropriate action based on the
reason
.
Request device permissions
Use Dart permission_handler package to request microphone, phone, Bluetooth connection, and camera permission.
import 'package:permission_handler/permission_handler.dart';
final status = await [Permission.microphone, Permission.phone, Permission.bluetoothConnect, Permission.camera].request();
Prepare variables
Prepare variables for key properties and event handlers.
PlanetKitConferenceEventHandler
is used to handle status change events of a group call. For more information, see Group call flow.PlanetKitMyMediaStatusHandler
is used to handle the local user's media status change events. You can update the local user's UI based on these events, such as when the mic becomes muted or unmuted, when the audio description is updated, or when the video status is updated.
final String _myUserId = "test user id";
final String _serviceId = "test service id";
PlanetKitConference? _conference;
List<Peer> _peers = [];
bool isMyAudioMuted = false;
bool isMyVideoPaused = false;
bool isVideoEnabled = false;
int volume = 0;
final _eventHandler = PlanetKitConferenceEventHandler(
onConnected: (conference) => print("connected"),
onDisconnected: (conference, reason, source, byRemote) => print("disconnected $reason"),
onPeerListUpdated: _onPeerListUpdated);
final _myMediaStatusHandler = PlanetKitMyMediaStatusHandler(
onAudioDescriptionUpdate: (status, averageVolumeLevel) => volume = averageVolumeLevel,
onMicMute: (status) => isMyAudioMuted = true,
onMicUnmute: (status) => isMyAudioMuted = false,
onVideoStatusUpdate: (status, videoStatus) {
if (videoStatus.state == PlanetKitVideoState.enabled) {
isMyVideoPaused = false;
isVideoEnabled = true;
} else if (videoStatus.state == PlanetKitVideoState.disabled) {
isVideoEnabled = false;
} else if (videoStatus.state == PlanetKitVideoState.paused) {
isMyVideoPaused = true;
isVideoEnabled = true;
}
});
Join a group call
To join a group call, call PlanetKitManager.instance.joinConference()
with a PlanetKitJoinConferenceParam
that you can create using PlanetKitJoinConferenceParamBuilder()
.
- To join a group video call, call
setMediaType()
ofPlanetKitJoinConferenceParamBuilder
withPlanetKitMediaType.audiovideo
. - The local user's initial video state can be set with
setInitialMyVideoState()
ofPlanetKitJoinConferenceParamBuilder
.- The default value of the
initialMyVideoState
property isPlanetKitInitialMyVideoState.resume
. - If the local user's initial video state is set to paused by calling
setInitialMyVideoState()
withPlanetKitInitialMyVideoState.pause
, the local user's video is not transmitted. To transmit the local user's video after the call is connected, callresumeMyVideo()
.
- The default value of the
Future<bool> joinConference(String roomId, String accessToken) async {
var builder = PlanetKitJoinConferenceParamBuilder()
.setMyUserId(_myUserId)
.setMyServiceId(_serviceId)
.setRoomServiceId(_serviceId)
.setRoomId(roomId)
.setAccessToken(accessToken);
.setMediaType(PlanetKitMediaType.audiovideo)
.setInitialMyVideoState(initialMyVideoState);
PlanetKitJoinConferenceParam? param;
try {
param = builder.build();
} catch (error) {
print("failed to build join conference param $error");
return false;
}
final result =
await PlanetKitManager.instance.joinConference(param, _eventHandler);
if (result.reason != PlanetKitStartFailReason.none) {
print("join conference result ${result.reason}");
return false;
}
// Store conference instance and set MyMediaStatusHandler.
_conference = result.conference;
_conference?.myMediaStatus.setHandler(_myMediaStatusHandler);
return true;
}
Manage peers using PlanetKitPeerControl
Manage peers in the group call using PlanetKitConferenceEventHandler.onPeerListUpdated()
and PlanetKitPeerControl
. When the peer list is updated, create a PlanetKitPeerControl
for the peer to be monitored.
class Peer {
final PlanetKitPeerControl control;
bool videoAvailable = false;
Peer({required this.control});
void register() async {
final handler =
PlanetKitPeerControlHandler(onVideoUpdate: (control, videoStatus) {
videoAvailable =
videoStatus.state == PlanetKitVideoState.enabled ? true : false;
});
await control.register(handler);
}
void unregister() async {
await control.unregister();
}
void startVideo(String viewId) async {
await control.startVideo(viewId);
}
void stopVideo(String viewId) async {
await control.stopVideo(viewId);
}
}
Render video
To render the peer's video, you must use PlanetKitVideoViewBuilder
to create PlanetKitVideoView
and add it toPlanetKitPeerControl
.
After creating the PlanetKitVideoView
for the peer's video, add the peer's video view to PlanetKitPeerControl
by calling startVideo(viewId)
.
Your media type must be PlanetKitMediaType.audiovideo
to view peer's video.
class PeerView extends StatelessWidget {
final Peer peer;
PeerView({required this.peer});
Widget build(BuildContext context) {
if (peer.videoAvailable) {
return VideoView(peer: peer);
} else {
return Text("video not available");
}
}
}
class VideoView extends StatelessWidget {
const VideoView({super.key, required this.peer});
final Peer peer;
Widget build(BuildContext context) {
final videoView = PlanetKitVideoViewBuilder.instance
.create(PlanetKitViewScaleType.fitCenter);
videoView.onCreate.listen((id) {
peer.startVideo(id);
});
videoView.onDispose.listen((id) {
peer.stopVideo(id);
});
return videoView;
}
}
Leave a group call
To leave a group call, call leaveConference()
.
Future<bool> leaveConference() async {
return await _conference?.leaveConference() ?? false;
}
Additional implementation for CallKit integration (Optional)
This step applies to iOS applications only.
When using the CallKit framework, you must set callKitType
to PlanetKitCallKitType.user
in PlanetKitJoinConferenceParam
.
Then, you must call PlanetKitConference.notifyCallKitAudioActivation()
on CXProviderDelegate.provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession)
to ensure audio activation in PlanetKit.