Skip to main content
Version: 1.0

1-to-1 audio call

This page provides a code example for implementing a 1-to-1 audio call.

Prerequisites

Before you begin, you must do the following:

Considerations for implementing a 1-to-1 audio call

To receive call notifications on the callee side, you must implement a notification system or integrate an external push notification system such as Apple Push Notification service (APNs) or Firebase Cloud Messaging (FCM).

You also need to know what information must be delivered to the callee. Refer to Role of the app server, which describes cc_param, the data that must be delivered by your application.

After calling makeCall() or verifyCall(), you must check the reason property of the returned PlanetKitMakeCallResult or PlanetKitVerifyCallResult.

  • 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.

  • PlanetKitCallEventHandler is used to handle status change events of a 1-to-1 call. For more information, see 1-to-1 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";
PlanetKitCall? _call;

final _eventHandler = PlanetKitCallEventHandler(
onWaitConnected: (call) => print("wait connected"),
onVerified: (call, peerUseResponderPreparation) => print("verified"),
onConnected: (call, isInResponderPreparation, shouldFinishPreparation) => print("connected"),
onDisconnected: (call, reason, source, byRemote) => print("disconnected $reason"));

final _myMediaStatusHandler = PlanetKitMyMediaStatusHandler(
onMicMute: (status) => print("mic muted"),
onMicUnmute: (status) => print("mic unmuted"),
onAudioDescriptionUpdate: (status, averageVolumeLevel) => print("audio description updated"));

Make an outgoing call (caller side)

To make a call, call PlanetKitManager.instance.makeCall() with a PlanetKitMakeCallParam that you can create using PlanetKitMakeCallParamBuilder().

Future<bool> makeCall(String peerId, String accessToken) async {
final builder = PlanetKitMakeCallParamBuilder()
.setMyUserId(_myUserId)
.setMyServiceId(_serviceId)
.setPeerUserId(peerId)
.setPeerServiceId(_serviceId)
.setAccessToken(accessToken);

PlanetKitMakeCallParam? param;
try {
param = builder.build();
} catch (error) {
print("failed to build make call param $error");
return false;
}

final result = await PlanetKitManager.instance.makeCall(param, _eventHandler);

if (result.reason != PlanetKitStartFailReason.none) {
print("make call failed. reason: $result.reason");
return false;
}

// Store call instance and set MyMediaStatusHandler.
_call = result.call;
_call?.myMediaStatus.setHandler(_myMediaStatusHandler);
return true;
}

Respond to an incoming call (callee side)

When you receive a push message from the app server, you must parse the cc_param from the message and create a ccParam. This data is a required argument that must be passed when responding to a call.

To respond to a call, call PlanetKitManager.instance.verifyCall() with a proper PlanetKitVerifyCallParam. To build a PlanetKitVerifyCallParam, use PlanetKitVerifyCallParamBuilder().

Future<bool> verifyCall(String ccParamString) async {
final ccParam = await PlanetKitCcParam.createCcParam(ccParamString);
if (ccParam == null) {
print("failed to create ccparam string $ccParamString");
return false;
}

final builder = PlanetKitVerifyCallParamBuilder()
.setMyUserId(_myUserId)
.setMyServiceId(_serviceId)
.setCcParam(ccParam);

PlanetKitVerifyCallParam? param;
try {
param = builder.build();
} catch (error) {
print("failed to build verify call param $error");
return false;
}

final result =
await PlanetKitManager.instance.verifyCall(param, _eventHandler);

if (result.reason != PlanetKitStartFailReason.none) {
print("make call result $result.reason");
return false;
}

// Store call instance and set MyMediaStatusHandler.
_call = result.call;
_call?.myMediaStatus.setHandler(_myMediaStatusHandler);
return true;
}

Accept an incoming call (callee side)

In general, the recipient needs time to decide whether to accept a new call after responding to the call. To accept a call, call PlanetKitCall.acceptCall().

Tip

The _call variable is a PlanetKitCall instance that has been verified by verifyCall().

Future<void> acceptCall() async {
return await _call?.acceptCall() ?? false;
}

End a call

To end a call, call endCall().

Future<bool> endCall() async {
return await _call?.endCall() ?? 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 PlanetKitMakeCallParam and PlanetKitVerifyCallParam.

Then, you must call PlanetKitCall.notifyCallKitAudioActivation() on CXProviderDelegate.provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) to ensure audio activation in PlanetKit.