Skip to main content
Version: 1.0

Group audio call

This page provides a code example for implementing a group audio call.

Prerequisites

Before you begin, you must do the following:

Considerations for implementing a group audio call

After calling joinConference(), you must check the reason property of the returned PlanetKitJoinConferenceResult.

  • If the reason is PlanetKitStartFailReason.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)

Note

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.