Skip to content

Latest commit

 

History

History
389 lines (280 loc) · 15.3 KB

events.md

File metadata and controls

389 lines (280 loc) · 15.3 KB

Events

Listen to an event with addEventListener, which returns a subscription:

const subscription = RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
  // ...
});

subscription.remove();
Event iOS Android
didReceiveStartCallAction ✅ ✅
startCallFailed ✅ ✅
answerCall ✅ ✅
endCall ✅ ✅
didActivateAudioSession ✅ ✅
didDeactivateAudioSession ✅ ❌
didDisplayIncomingCall ✅ ✅
didPerformSetMutedCallAction ✅ ✅
didToggleHoldCallAction ✅ ✅
didPerformDTMFAction ✅ ✅
didResetProvider ✅ ❌
didLoadWithEvents ✅ ❌
showIncomingCallUi ❌ ✅
silenceIncomingCall ❌ ✅
createIncomingConnectionFailed ❌ ✅
checkReachability ❌ ✅
didChangeAudioRoute ✅ ✅
onHasActiveCall ❌ ✅

didReceiveStartCallAction

Device sends this event once it decides the app is allowed to start a call, either from the built-in phone screens (iOS/Recents, Android/Contact), or by the app calling RNCallKeep.startCall.

Try to start your app call action from here (e.g. get credentials of the user by data.handle and/or send INVITE to your SIP server)

If the system refuses a call started with startCall, you get startCallFailed instead.

Note: on iOS, when the call comes from Recents, Contacts or Siri, callUUID is not defined: CallKit doesn't manage the call yet. Generate a UUID and call startCall, which sends this event again with the callUUID.

RNCallKeep.addEventListener('didReceiveStartCallAction', ({ handle, callUUID, name }) => {

});
  • handle (string)
    • Phone number of the callee
  • callUUID (string)
    • The UUID of the call that is to be answered
  • name (string)
    • Name of the callee

startCallFailed

The system refused a call started with startCall: it shows no call, and didReceiveStartCallAction won't come for it. Stop what your app started for this call, and tell the user.

  • On iOS, CallKit refused the call. errorCode says why, for instance MaximumCallGroupsReached when calls already fill the maximumCallGroups option.
  • On Android, Telecom refused the call before creating it, for instance in managed mode while another outgoing call is dialing. Android doesn't say why. In self-managed mode, Android asks the user whether to end the ongoing call instead; if they cancel, Android doesn't tell the app, and this event isn't sent.

With errorCode CallUUIDAlreadyExists (iOS), CallKit already has a call with this UUID, for instance after a second startCall for the same call: that call goes on, so don't end it.

RNCallKeep.addEventListener('startCallFailed', ({ callUUID, handle, name, errorCode }) => {
  if (errorCode === 'CallUUIDAlreadyExists') {
    return; // the call with this UUID goes on
  }
  // Stop your app's call for callUUID, e.g. cancel the INVITE sent to your SIP server.
});
  • callUUID (string)
    • The UUID passed to startCall.
  • handle (string)
    • Phone number of the callee.
  • name (string)
    • The contactIdentifier passed to startCall.
  • error (string)
    • iOS only. CallKit's description of the error.
  • errorCode (string)

answerCall

User answer the incoming call

RNCallKeep.addEventListener('answerCall', ({ callUUID }) => {
  // Do your normal `Answering` actions here.
});
  • callUUID (string)
    • The UUID of the call that is to be answered.

endCall

User finish the call.

RNCallKeep.addEventListener('endCall', ({ callUUID }) => {
  // Do your normal `Hang Up` actions here
});
  • callUUID (string)
    • The UUID of the call that is to be ended.

didActivateAudioSession

The AudioSession has been activated by RNCallKeep.

RNCallKeep.addEventListener('didActivateAudioSession', () => {
  // you might want to do following things when receiving this event:
  // - Start playing ringback if it is an outgoing call
});

didDeactivateAudioSession

iOS only.

The AudioSession has been deactivated by RNCallKeep.

RNCallKeep.addEventListener('didDeactivateAudioSession', () => {

});

didDisplayIncomingCall

Sent for an incoming call reported with displayIncomingCall, or from native code with reportNewIncomingCall (for example when a push arrives):

  • On iOS, once CallKit has accepted or refused the call. error is set when it refused.
  • On Android, once Telecom has created the call, so methods that act on the call work from this event. If Android refuses the call, you get createIncomingConnectionFailed instead.
RNCallKeep.addEventListener('didDisplayIncomingCall', ({ error, callUUID, handle, localizedCallerName, hasVideo, fromPushKit, payload }) => {
  // you might want to do following things when receiving this event:
  // - Start playing ringback if it is an outgoing call
});
  • error (string)
    • iOS only.
  • errorCode (string)
  • callUUID (string)
    • The UUID of the call.
  • handle (string)
    • Phone number of the caller
  • localizedCallerName (string)
    • Name of the caller to be displayed on the native UI
  • name (string)
    • Android only. The same as localizedCallerName, for apps written when only reportNewIncomingCall sent this event.
  • hasVideo (string)
    • 1 (video enabled)
    • 0 (video not enabled)
  • fromPushKit (string)
    • 1 (call triggered from PushKit)
    • 0 (call not triggered from PushKit, and always on Android)
  • payload (object or string)
    • iOS: the VoIP push payload passed to reportNewIncomingCall.
    • Android: the payload passed to the native reportNewIncomingCall (a string) or displayIncomingCall (a Bundle, sent as an object). Absent when there is none.

didPerformSetMutedCallAction

A call was muted by the system or the user:

RNCallKeep.addEventListener('didPerformSetMutedCallAction', ({ muted, callUUID }) => {

});
  • muted (boolean)
  • callUUID (string)
    • The UUID of the call.

didToggleHoldCallAction

A call was held or unheld by the current user

RNCallKeep.addEventListener('didToggleHoldCallAction', ({ hold, callUUID }) => {

});
  • hold (boolean)
  • callUUID (string)
    • The UUID of the call.

didChangeAudioRoute

Triggered when the audio route has been changed.

RNCallKeep.addEventListener('didChangeAudioRoute', ({ output }) => {

});

didPerformDTMFAction

Used type a number on his dialer

RNCallKeep.addEventListener('didPerformDTMFAction', ({ digits, callUUID }) => {

});
  • digits (string)
    • The digits that emit the dtmf tone
  • callUUID (string)
    • The UUID of the call.

didResetProvider

iOS only.

The underlying native provider for RNCallKeep has been reset.

RNCallKeep.addEventListener('didResetProvider', () => {
  // Likely an error has occurred, you may want to hang up all calls
  // and log errors.
});

didLoadWithEvents

iOS only.

Called as soon as JS context initializes if there were some actions performed by user before JS context has been created.

Since iOS 13, you must display incoming call on receiving PushKit push notification. But if app was killed, it takes some time to create JS context. If user answers the call (or ends it) before JS context has been initialized, user actions will be passed as events array of this event. Similar situation can happen if user would like to start a call from Recents or similar iOS app, assuming that your app was in killed state.

In order for this event to reliably fire, it's necessary to perform setup in AppDelegate.m

NOTE: You still need to subscribe / handle the rest events as usuall. This is just a helper whcih cache and propagate early fired events if and only if for "the native events which DID fire BEFORE js bridge is initialed", it does NOT mean this will have events each time when the app reopened.

// register `didLoadWithEvents` somewhere early in your app when it is ready to handle callkeep events.

RNCallKeep.addEventListener('didLoadWithEvents', (events) => {
  // `events` is passed as an Array chronologically, handle or ignore events based on the app's logic
  // see example usage in https://github.com/react-native-webrtc/react-native-callkeep/pull/169 or https://github.com/react-native-webrtc/react-native-callkeep/pull/205
});
  • events Array
    • name: string Native event name like: RNCallKeepPerformAnswerCallAction
    • data: object Object with data passed together with specific event so it can be handled in the same way like original event, for example ({ callUUID }) for answerCall event if name is RNCallKeepPerformAnswerCallAction

showIncomingCallUi

Android only. Self Managed only.

Only when CallKeep is setup to be in self managed mode. Signals that the app must show an incoming call UI. The implementor must either call displayIncomingCall from react native or native android code to make this event fire.

RNCallKeep.addEventListener('showIncomingCallUi', ({ handle, callUUID, name }) => {

});

The following values will match those initially passed to displayIncomingCall

  • handle (string)
    • Phone number of the incoming caller.
  • callUUID (string)
    • The UUID of the call.
  • name (string)
    • Caller Name.

silenceIncomingCall

Android only. Self Managed only.

Corresponds to the native onSilence event. The implementor should silence the corresponding incoming calls notification sound when and if this event is fired.

RNCallKeep.addEventListener('silenceIncomingCall', ({ handle, callUUID, name }) => {

});

The following values will match those initially passed to silenceIncomingCall

  • handle (string)
    • Phone number of the incoming caller.
  • callUUID (string)
    • The UUID of the call.
  • name (string)
    • Caller Name.

createIncomingConnectionFailed

Android only. Self Managed only.

Corresponds to the native onCreateIncomingConnectionFailed callback. The implementor should reject the incoming SIP INVITE with an appropriate status code, such as 483 User Busy. Android unfortunately does not provide the exact reason for refusing to let you accept an incoming call, but they do list a set of reasons here

RNCallKeep.addEventListener('createIncomingConnectionFailed', ({ handle, callUUID, name }) => {

});

The following values will match those initially passed to silenceIncomingCall

  • handle (string)
    • Phone number of the incoming caller.
  • callUUID (string)
    • The UUID of the call.
  • name (string)
    • Caller Name.

checkReachability

Android only.

On Android when the application is in background, after a certain delay the OS will close every connection with informing about it. So we have to check if the application is reachable before making a call from the native phone application.

RNCallKeep.addEventListener('checkReachability', () => {
  RNCallKeep.setReachable();
});

onHasActiveCall

Android only.

A listener that tells the JS side if a native call has been answered while there was an active self-managed call

RNCallKeep.addEventListener('onHasActiveCall', () => {
  // eg: End active app call if native call is answered
});

Listening from native code (iOS)

iOS also posts these events to NotificationCenter.default, under the names below, with the event's data as userInfo. Native code can observe them before a React Native runtime exists, or while JavaScript is busy; the events JavaScript receives are unchanged. didLoadWithEvents and didChangeAudioRoute are not posted.

Each notification is posted on the thread that sends the event, which can be CallKit's private queue (didDisplayIncomingCall, for instance). Observe with queue: .main, as below, or move to the main queue yourself before touching the UI or the app's state.

Event Notification name
didReceiveStartCallAction RNCallKeepDidReceiveStartCallAction
startCallFailed RNCallKeepStartCallFailed
answerCall RNCallKeepPerformAnswerCallAction
endCall RNCallKeepPerformEndCallAction
didActivateAudioSession RNCallKeepDidActivateAudioSession
didDeactivateAudioSession RNCallKeepDidDeactivateAudioSession
didDisplayIncomingCall RNCallKeepDidDisplayIncomingCall
didPerformSetMutedCallAction RNCallKeepDidPerformSetMutedCallAction
didToggleHoldCallAction RNCallKeepDidToggleHoldAction
didPerformDTMFAction RNCallKeepDidPerformDTMFAction
didResetProvider RNCallKeepProviderReset
NotificationCenter.default.addObserver(
  forName: Notification.Name("RNCallKeepPerformAnswerCallAction"), object: nil, queue: .main
) { notification in
  let callUUID = notification.userInfo?["callUUID"] as? String
  // ...
}

On Android, native code receives CallKeep's local broadcasts: see Setup from native code (Android).