Group audio call
This page provides a code example for implementing a group audio 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 audio 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 phone and microphone permission.
import 'package:permission_handler/permission_handler.dart';
final status = await [Permission.microphone, Permission.phone, Permission.bluetoothConnect].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, or when the audio description is updated.
final String _myUserId = "test user id";
final String _serviceId = "test service id";
PlanetKitConference? _conference;
List<Peer> _peers = [];
final _eventHandler = PlanetKitConferenceEventHandler(
onConnected: (conference) => print("connected"),
onDisconnected: (conference, reason, source, byRemote) => print("disconnected $reason"),
onPeerListUpdated: _onPeerListUpdated);
final _myMediaStatusHandler = PlanetKitMyMediaStatusHandler(
onMicMute: (status) => print("mic muted"),
onMicUnmute: (status) => print("mic unmuted"),
onAudioDescriptionUpdate: (status, averageVolumeLevel) => print("audio description updated"));
Join a group call
To join a group call, call PlanetKitManager.instance.joinConference()
with a PlanetKitJoinConferenceParam
that you can create using PlanetKitJoinConferenceParamBuilder()
.
Future<bool> joinConference(String roomId, String accessToken) async {
var builder = PlanetKitJoinConferenceParamBuilder()
.setMyUserId(_myUserId)
.setMyServiceId(_serviceId)
.setRoomServiceId(_serviceId)
.setRoomId(roomId)
.setAccessToken(accessToken);
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 {
String userId;
bool isMuted;
bool isOnHold;
bool isConnected = true;
int volume = 0;
PlanetKitPeerControl? _control;
Peer({required this.userId, required this.isMuted, required this.isOnHold});
Future<void> register(PlanetKitPeerControl control) async {
_control = control;
final _handler = PlanetKitPeerControlHandler(
onMicMute: (control) => isMuted = true,
onMicUnmute: (control) => isMuted = false,
onHold: (control, reason) => isOnHold = true,
onUnhold: (control) => isOnHold = false,
onAudioDescriptionUpdate: (control, averageVolumeLevel) =>
volume = averageVolumeLevel,
onDisconnect: (control) => isConnected = false,
);
await _control?.register(_handler);
}
Future<void> unregister() async {
await _control?.unregister();
}
}
void _onPeerListUpdated(PlanetKitConference conference, PlanetKitConferencePeerListUpdateParam updateParam) async {
// process added peers
for (var addedPeer in updateParam.addedPeers) {
final isMuted = await addedPeer.isMuted;
final holdStatus = await addedPeer.holdStatus;
final peer = Peer(
userId: addedPeer.userId.userId,
isMuted: isMuted,
isOnHold: holdStatus.isOnHold);
_peers.add(peer);
// create peer control to monitor peer updates
final peerControl = await _conference?.createPeerControl(addedPeer);
if (peerControl == null) {
print(
"fail to create PlanetKitPeerControl for peer: ${addedPeer.userId.userId}");
continue;
}
peer.register(peerControl);
}
// process removed peers
for (var removedPeer in updateParam.removedPeers) {
try {
final removed = _peers.firstWhere((item) => item.userId == removedPeer.userId.userId);
removed.unregister();
} catch (e) {
print("failed to remove peer: ${removedPeer.userId.userId}");
}
}
}
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.