Voice
Voice in the Flutter SDK.
import 'package:nexus_flutter/nexus.dart';| Symbol | Kind | Summary |
|---|---|---|
NexusVoice | class | Nexus Voice — the client calling API. |
VoiceCallState | enum | Call state — the subset a client observes (mirrors the server machine). |
VoiceCallStateX | extension | |
VoiceEndpointType | enum | |
VoiceCallDirection | enum | |
NexusJoinToken | class | Everything a client needs to join the media plane for one leg. |
CallQualitySample | class | One transport-quality sample the engine emits; reported to the control plane and surfaced to the app for a live quality indicator. |
NexusCall | class | Immutable snapshot of the current call, exposed via a ValueListenable. |
NexusVoiceEngine | abstract class | The media-transport seam. |
VoiceEngineState | enum | |
NoopVoiceEngine | class | Default engine when none is registered: it does NO media. |
NexusCallKit | abstract class | Native calling seam — CallKit (iOS) / ConnectionService (Android) + VoIP push. |
CallKitActionType | enum | |
CallKitAction | class | |
NoopCallKit | class | No-op default. |
NexusVoiceOverlay | class | The SDK's built-in, auto-shown call screen. |
NexusIvrStatus | enum | State of an in-app IVR (visual phone-tree) session. |
NexusIvrSession | class | |
NexusIvrOverlay | class | The SDK's built-in IVR menu screen. |
showNexusIncomingCall() | function | Show the native incoming-call UI directly from a voice push payload. |
NexusVoice
classNexus Voice — the client calling API. Talks to the Voice control plane
(/partner/voice/*), drives a pluggable NexusVoiceEngine for media and an
optional NexusCallKit for the native call UI, and exposes the live call as
a ValueListenable. Follows the SDK rule: it NEVER throws into the app —
failures are logged and surface as a failed/ended call state.
current
fieldfinal ValueNotifier<NexusCall?> currentThe current call (null when idle). Listen to drive your call UI.
View sourceivr
fieldfinal ValueNotifier<NexusIvrSession?> ivrThe current in-app IVR menu session (null when not in a menu). Drives the
built-in NexusIvrOverlay; listen to build your own support-menu UI.
onIvr
fieldvoid Function(Map<String, dynamic> instruction)? onIvrOptional hook for IVR prompts returned by DTMF (play/collect instructions).
View sourceinit()
methodFuture<void> init()Turnkey setup — called automatically when voiceEnabled. Wires the SDK's
BUILT-IN WebRTC engine + native call UI (CallKit/ConnectionService) and
registers this device for incoming-call push so calls ring even when the
app is killed. Developers do NOT call this.
rebindIdentity()
methodFuture<void> rebindIdentity()Re-bind voice to the CURRENT identity — MUST be called after
identify()/reset(). Voice initialises at app start (before login), so it
first binds to voice:<deviceKey>; without re-binding, an identified user
keeps listening on the device room and never rings on voice:<distinctId>.
Re-joins the correct room and re-registers the push device under the new id.
useEngine()
methodvoid useEngine(NexusVoiceEngine engine)Advanced override — replace the built-in WebRTC engine.
Parameters
Prop
Type
useCallKit()
methodvoid useCallKit(NexusCallKit callKit)Advanced override — replace the built-in native call UI.
Parameters
Prop
Type
registerPushToken()
methodFuture<bool> registerPushToken({String? voipToken, String? fcmToken})Register this device's push tokens (iOS VoIP / Android FCM) for incoming calls when the app is backgrounded/killed. The SDK does this automatically; call it yourself with a token if your app owns FCM/OneSignal and wants to hand the SDK the exact token. Returns true once a token was registered.
Parameters
Prop
Type
Returns Future<bool>
ensurePermissions()
methodFuture<bool> ensurePermissions()Request the microphone permission a voice call needs, returning whether it is granted. Call this from your onboarding (a foreground moment with UI context) so an incoming call answered later from a killed/background state — where no permission dialog can be shown — already has audio access. The SDK also pre-warms it on voice init, but calling it during onboarding with your own rationale is the best UX.
Returns Future<bool>
openMicrophoneSettings()
methodFuture<bool> openMicrophoneSettings()Open this app's OS settings page so the user can grant the microphone after a permanent denial — iOS never re-prompts once the user has refused, so this is the only way back. Returns true if the settings page was opened.
Returns Future<bool>
placeCall()
methodFuture<NexusCall?> placeCall({required String to, VoiceEndpointType type = VoiceEndpointType.app, String? callerId, String? displayName, String? callerDisplayName, String? callerAvatarUrl, bool record = false, Map<String, dynamic> metadata = const {}})Place a call to to — a Nexus identity (app), a phone number (pstn) or a
SIP URI. This device joins as a WebRTC leg; the control plane dials to.
Parameters
Prop
Type
Returns Future<NexusCall?>
handleIncomingPush()
methodFuture<void> handleIncomingPush(Map<String, dynamic> data, {bool alreadyRinging = false})Handle an incoming-call push/data message. Call this from your FCM / VoIP
push handler with the payload the backend sent ({sessionId, from, ...}).
Shows the native incoming UI and arms answer/decline.
Parameters
Prop
Type
answer()
methodFuture<void> answer([String? sessionId])Answer the current inbound call — join as a WebRTC leg.
Parameters
Prop
Type
decline()
methodFuture<void> decline()Decline the current inbound call.
View sourcestartIvr()
methodFuture<bool> startIvr(String flowId)Open an in-app IVR menu (a visual phone-tree) for flowId — e.g. a support
entry point built in the dashboard. The built-in NexusIvrOverlay renders
it; the caller taps keys to navigate, and the SDK auto-connects a real call
when the flow routes to an agent. Returns false if the menu couldn't start.
Parameters
Prop
Type
Returns Future<bool>
pressIvrKey()
methodFuture<void> pressIvrKey(String digit)Press a key in the current IVR menu.
Parameters
Prop
Type
endIvr()
methodvoid endIvr()Dismiss the IVR menu (the user backed out).
View sourcehangup()
methodFuture<void> hangup()setMuted()
methodFuture<void> setMuted(bool muted)Parameters
Prop
Type
setSpeakerphone()
methodFuture<void> setSpeakerphone(bool on)Parameters
Prop
Type
setHold()
methodFuture<void> setHold(bool held)Parameters
Prop
Type
sendDtmf()
methodFuture<void> sendDtmf(String digit)Parameters
Prop
Type
setPresence()
methodFuture<void> setPresence(String status)Parameters
Prop
Type
dispose()
methodvoid dispose()VoiceCallState
enumenum VoiceCallStateCall state — the subset a client observes (mirrors the server machine).
| Value | Description |
|---|---|
VoiceCallState.idle | |
VoiceCallState.connecting | |
VoiceCallState.ringing | |
VoiceCallState.connected | |
VoiceCallState.onHold | |
VoiceCallState.reconnecting | |
VoiceCallState.ending | |
VoiceCallState.ended | |
VoiceCallState.failed | |
VoiceCallState.rejected | |
VoiceCallState.cancelled | |
VoiceCallState.timeout |
VoiceCallStateX
extensionextension VoiceCallStateX on VoiceCallStateisTerminal
propertybool get isTerminalisActive
propertybool get isActiveVoiceEndpointType
enumenum VoiceEndpointType| Value | Description |
|---|---|
VoiceEndpointType.webrtc | |
VoiceEndpointType.sip | |
VoiceEndpointType.pstn | |
VoiceEndpointType.app |
VoiceCallDirection
enumenum VoiceCallDirection| Value | Description |
|---|---|
VoiceCallDirection.inbound | |
VoiceCallDirection.outbound |
NexusJoinToken
classEverything a client needs to join the media plane for one leg. Minted by the control plane; the client never fabricates any of it.
View sourceNexusJoinToken
constructorconst NexusJoinToken({required this.room, required this.token, required this.url, this.turnUrls = const [], this.turnUsername, this.turnPassword})Parameters
Prop
Type
tryParse()
static methodstatic NexusJoinToken? tryParse(Map<String, dynamic>? join)Parameters
Prop
Type
Returns NexusJoinToken?
room
fieldfinal String roomtoken
fieldfinal String tokenurl
fieldfinal String urlturnUrls
fieldfinal List<String> turnUrlsturnUsername
fieldfinal String? turnUsernameturnPassword
fieldfinal String? turnPasswordCallQualitySample
classOne transport-quality sample the engine emits; reported to the control plane and surfaced to the app for a live quality indicator.
View sourceCallQualitySample
constructorconst CallQualitySample({this.rttMs, this.jitterMs, this.packetLoss, this.bitrateKbps, this.mos, this.codec, this.candidateType})Parameters
Prop
Type
rttMs
fieldfinal int? rttMsjitterMs
fieldfinal int? jitterMspacketLoss
fieldfinal double? packetLossbitrateKbps
fieldfinal int? bitrateKbpsmos
fieldfinal double? moscodec
fieldfinal String? codeccandidateType
fieldfinal String? candidateTypetoJson()
methodMap<String, Object?> toJson()Returns Map<String, Object?>
NexusCall
classImmutable snapshot of the current call, exposed via a ValueListenable.
NexusCall
constructorconst NexusCall({required this.sessionId, required this.direction, required this.state, this.legId, this.remoteAddress, this.remoteName, this.remoteAvatar, this.muted = false, this.onHold = false, this.speakerphone = false, this.startedAt, this.connectedAt, this.quality, this.endReason, this.metadata = const {}})Parameters
Prop
Type
sessionId
fieldfinal String sessionIdlegId
fieldfinal String? legIddirection
fieldfinal VoiceCallDirection directionstate
fieldfinal VoiceCallState stateremoteAddress
fieldfinal String? remoteAddressremoteName
fieldfinal String? remoteNameremoteAvatar
fieldfinal String? remoteAvatarmuted
fieldfinal bool mutedonHold
fieldfinal bool onHoldspeakerphone
fieldfinal bool speakerphonestartedAt
fieldfinal DateTime? startedAtconnectedAt
fieldfinal DateTime? connectedAtquality
fieldfinal CallQualitySample? qualityendReason
fieldfinal String? endReasonmetadata
fieldfinal Map<String, dynamic> metadatacopyWith()
methodNexusCall copyWith({String? legId, VoiceCallState? state, bool? muted, bool? onHold, bool? speakerphone, DateTime? connectedAt, CallQualitySample? quality, String? endReason})Parameters
Prop
Type
Returns NexusCall
NexusVoiceEngine
abstract classabstract class NexusVoiceEngineThe media-transport seam. Nexus Voice's control plane is engine-agnostic; the
actual WebRTC connection to the media plane (LiveKit) is provided by a
NexusVoiceEngine. Ship a real engine by registering one via
Nexus.instance.voice.useEngine(...) — e.g. a thin adapter over
livekit_client (see the SDK README). Keeping media out of the core keeps the
base package dependency-light and lets any transport slot in.
states
propertyStream<VoiceEngineState> get statesTransport state changes (local connection to the media room).
View sourceremoteCount
propertyStream<int> get remoteCountNumber of REMOTE participants in the room. The call is "connected" (the other party answered/joined) when this is > 0; it drops when they leave.
View sourcequality
propertyStream<CallQualitySample> get qualityPeriodic quality samples (reported to the control plane + shown in-app).
View sourceconnect()
methodFuture<void> connect(NexusJoinToken token)Connect to the media plane for a leg and start capturing/playing audio.
Parameters
Prop
Type
disconnect()
methodFuture<void> disconnect()Tear down the media connection.
View sourcesetMuted()
methodFuture<void> setMuted(bool muted)Parameters
Prop
Type
setSpeakerphone()
methodFuture<void> setSpeakerphone(bool on)Parameters
Prop
Type
sendDtmf()
methodFuture<void> sendDtmf(String digit)Send a DTMF digit over the media session (RFC 4733).
Parameters
Prop
Type
VoiceEngineState
enumenum VoiceEngineState| Value | Description |
|---|---|
VoiceEngineState.connecting | |
VoiceEngineState.connected | |
VoiceEngineState.reconnecting | |
VoiceEngineState.disconnected | |
VoiceEngineState.failed |
NoopVoiceEngine
classclass NoopVoiceEngine implements NexusVoiceEngineDefault engine when none is registered: it does NO media. It logs and reports
a connected state so control-plane flows can be exercised end-to-end without
audio (useful in tests / before wiring a real transport). It never throws.
states
propertyStream<VoiceEngineState> get statesremoteCount
propertyStream<int> get remoteCountquality
propertyStream<CallQualitySample> get qualityconnect()
methodFuture<void> connect(NexusJoinToken token)Parameters
Prop
Type
disconnect()
methodFuture<void> disconnect()setMuted()
methodFuture<void> setMuted(bool muted)Parameters
Prop
Type
setSpeakerphone()
methodFuture<void> setSpeakerphone(bool on)Parameters
Prop
Type
sendDtmf()
methodFuture<void> sendDtmf(String digit)Parameters
Prop
Type
NexusCallKit
abstract classabstract class NexusCallKitNative calling seam — CallKit (iOS) / ConnectionService (Android) + VoIP push.
The SDK reports call lifecycle to the OS so incoming calls ring on the lock
screen and in-call actions come from the system UI. Provide a real
implementation (e.g. over flutter_callkit_incoming) via
Nexus.instance.voice.useCallKit(...). The default is a no-op so the SDK runs
without the native dependency.
actions
propertyStream<CallKitAction> get actionsActions the user takes from the system UI (answer / decline / mute / …).
View sourcereportIncoming()
methodFuture<void> reportIncoming({required String callId, required String handle, String? displayName, String? avatarUrl, bool hasVideo = false})Show the system incoming-call UI. Returns when displayed.
Parameters
Prop
Type
reportOutgoing()
methodFuture<void> reportOutgoing({required String callId, required String handle, String? displayName})Start a native OUTGOING call entry (configures the VoIP audio session).
Parameters
Prop
Type
reportConnected()
methodFuture<void> reportConnected(String callId)Tell the OS the call connected (starts its timer / active-call UI).
Parameters
Prop
Type
reportEnded()
methodFuture<void> reportEnded(String callId)Tell the OS the call ended (dismisses the call UI).
Parameters
Prop
Type
voipToken()
methodFuture<String?> voipToken()The current VoIP push token (APNs PushKit / FCM), for the app to register with the backend so incoming calls can wake a killed app. Null if none.
Returns Future<String?>
CallKitActionType
enumenum CallKitActionType| Value | Description |
|---|---|
CallKitActionType.answer | |
CallKitActionType.decline | |
CallKitActionType.end | |
CallKitActionType.muted | |
CallKitActionType.hold | |
CallKitActionType.dtmf |
CallKitAction
class View sourceCallKitAction
constructorconst CallKitAction(this.type, this.callId, {this.value})Parameters
Prop
Type
type
fieldfinal CallKitActionType typecallId
fieldfinal String callIdvalue
fieldfinal Object? valueNoopCallKit
classclass NoopCallKit implements NexusCallKitNo-op default. The SDK still works for in-app (foreground) calling; the OS call UI simply isn't shown until a real CallKit implementation is registered.
View sourceactions
propertyStream<CallKitAction> get actionsreportIncoming()
methodFuture<void> reportIncoming({required String callId, required String handle, String? displayName, String? avatarUrl, bool hasVideo = false})Parameters
Prop
Type
reportOutgoing()
methodFuture<void> reportOutgoing({required String callId, required String handle, String? displayName})Parameters
Prop
Type
reportConnected()
methodFuture<void> reportConnected(String callId)Parameters
Prop
Type
reportEnded()
methodFuture<void> reportEnded(String callId)Parameters
Prop
Type
voipToken()
methodFuture<String?> voipToken()Returns Future<String?>
NexusVoiceOverlay
classclass NexusVoiceOverlay extends StatefulWidgetThe SDK's built-in, auto-shown call screen. Renders full-screen whenever
there is an active call (Nexus.instance.voice.current) — outbound and
incoming — with mute / speaker / hold / hangup (and accept / decline while
ringing inbound). Auto-mounted when voiceEnabled; opt out with
NexusConfig(autoShowOverlay: false) and place your own UI, or wrap
NexusVoiceOverlay yourself.
NexusVoiceOverlay
constructorconst NexusVoiceOverlay({super.key, this.child})Parameters
Prop
Type
child
fieldfinal Widget? childNexusIvrStatus
enumenum NexusIvrStatusState of an in-app IVR (visual phone-tree) session. The caller sees the
current prompt; when awaitingInput is true a keypad is shown and each
press calls NexusVoice.pressIvrKey. On reaching a "talk to an agent" step
the SDK connects a real call automatically (status → connecting), and the
NexusIvrSession clears once that call takes over.
| Value | Description |
|---|---|
NexusIvrStatus.active | |
NexusIvrStatus.connecting | |
NexusIvrStatus.ended |
NexusIvrSession
class View sourceNexusIvrSession
constructorconst NexusIvrSession({required this.sessionId, this.prompt, this.awaitingInput = false, this.maxDigits = 1, this.status = NexusIvrStatus.active, this.endedReason})Parameters
Prop
Type
sessionId
fieldfinal String sessionIdprompt
fieldfinal String? promptawaitingInput
fieldfinal bool awaitingInputmaxDigits
fieldfinal int maxDigitsstatus
fieldfinal NexusIvrStatus statusendedReason
fieldfinal String? endedReasoncopyWith()
methodNexusIvrSession copyWith({String? prompt, bool? awaitingInput, int? maxDigits, NexusIvrStatus? status, String? endedReason})Parameters
Prop
Type
Returns NexusIvrSession
NexusIvrOverlay
classclass NexusIvrOverlay extends StatelessWidgetThe SDK's built-in IVR menu screen. Auto-shown whenever an IVR session is
active (alongside NexusVoiceOverlay); opt out with autoShowOverlay: false
and build your own from Nexus.instance.voice.ivr.
NexusIvrOverlay
constructorconst NexusIvrOverlay({super.key})Parameters
Prop
Type
Functions
showNexusIncomingCall()
functionFuture<void> showNexusIncomingCall(Map<dynamic, dynamic> data)Show the native incoming-call UI directly from a voice push payload.
Only needed on Android, where the incoming-call push is an FCM data message the SDK handles in a background Dart isolate. On iOS the ring is raised natively from the APNs VoIP (PushKit) payload before Dart is involved at all, so nothing here runs on that path.
The SDK wires its own FCM background handler, so apps do not normally call this; it stays public for apps that own their FCM handler end to end.
Parameters
Prop
Type
