Skip to content

feat: callkit/telecom integration#2028

Open
greenfrvr wants to merge 175 commits intomainfrom
feat/callkit-telecom-integration
Open

feat: callkit/telecom integration#2028
greenfrvr wants to merge 175 commits intomainfrom
feat/callkit-telecom-integration

Conversation

@greenfrvr
Copy link
Contributor

@greenfrvr greenfrvr commented Dec 2, 2025

💡 Overview

Current pull request provides implementation of CallKit/Android Telecom functionality which includes the following:

  • Improved integration allows to register both incoming and regular ongoing calls in CallKit/Telecom
  • Unified system notification in calling style for Android
  • Synchronization of stream call mute state and corresponding registered call in CallKit/Telecom
  • Android keep call alive functionality within internal background task implementation, instead of using notifee implementation
  • Improved reject call when busy implementation

As part of the PR following dependencies became redundant:

  • react-native-voip-push-notification
  • react-native-callkeep

Now neither ringing flow nor call alive functionality don't depend on @notifee/react-native which will allow to get rid of that dependency in near future.

📝 Implementation notes

🎫 Ticket: https://linear.app/stream/issue/RN-17/android-support-for-telecom-manager

📑 Docs: https://github.com/GetStream/docs-content/pull/881

Summary by CodeRabbit

  • New Features

    • New native calling package with CallKit/Telecom integration, VoIP support, and background/headless task handling.
    • Android keep-alive foreground service to maintain calls.
    • Runtime audio-state introspection for easier debugging.
  • Improvements

    • Simplified push/ringing configuration and unified VOIP event flow.
    • Better audio session handling with optional CallKit bypass on iOS.
    • Streamlined notification/channel management and resources.
  • Chores

    • Replaced legacy callkeep/voip integrations with the new calling package.

greenfrvr and others added 30 commits December 2, 2025 20:23
…lkit-telecom-integration

# Conflicts:
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	yarn.lock
greenfrvr and others added 30 commits February 9, 2026 17:24
### 💡 Overview
When CallKit deactivates the audio session after a call ends, it fires
didDeactivateAudioSession. Currently that callback only tells
RTCAudioSession the session is deactivated — but the ADM is not touched.
After telling WebRTC the session is deactivated, we will reset the ADM
so it's in a clean state, with no stale references from the previous
call.

---------

Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com>
…all (#2122)

### 💡 Overview

displayIncomingCall resolved its JS promise immediately before the call
was actually registered

### 📝 Implementation notes

Make the promise resolve only after native registration confirms
success/failure

🎫 Ticket: https://linear.app/stream/issue/XYZ-123

📑 Docs: https://github.com/GetStream/docs-content/pull/<id>

---------

Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com>
### 💡 Overview

* isCallRegistered mixed two concepts: app-level “we started tracking
this call” vs Telecom/CallKit registration completion.
This change makes intent explicit (isCallTracked) and ensures Android
behavior matches iOS by returning true immediately when tracking starts.

* removed pushTappedIncomingCallCId$, it was unnecessary anymore
* ignore duplicate invocations on ios

---------

Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com>
Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com>
### 💡 Overview

Added legacy arch support for callingx package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…integration

# Conflicts:
#	packages/client/src/Call.ts
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	yarn.lock
### 💡 Overview

Sending proper reasons to callkit/telecom would show the appropriate
states in the native view

For example, in callkit.. "call failed" - "call ended" - "call missed"
are appropirately shown based on what we pass
# Conflicts:
#	packages/client/src/types.ts
#	sample-apps/react-native/dogfood/ios/Podfile.lock
#	sample-apps/react-native/dogfood/package.json
#	yarn.lock
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Adds a new calling experience package with native iOS CallKit and
Android call UI, incoming/outgoing call handling, notifications,
ringtones, background/headless tasks, and a keep-alive foreground
service.
  * Exposes a debug audio-state log for troubleshooting.

* **Documentation**
* Ship comprehensive README and usage docs for the new calling package.

* **Chores**
* Add build/release scripts and workspace packaging; update dependencies
and sample apps to opt into the new calling package.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### 💡 Overview

This PR solves an issue with quickly answered CallKit call. The problem
was that CXProvider delegate was not set by the moment CallKit answer
event was omitted and was not added to delayed events store. Current
implementation ensures that delegate will be set up before we report the
call, so that all consequent events will be handled.
### 💡 Overview

This PR canges the way how ringing flow is initialized via push
notification.
We intercept firebase notification service, start FGS and register
incoming call, before JS is fully loaded to match Android 10 seconds
window for starting FGS from background.

Also PR includes some refactoring: 
* added global broadcast receiver which listens for call related events
and emit them with event bus. This allows to handle events for cases
when native module is not loaded (previously there was local broadcast
receiver, which depend on native module instance).
* improvements for FGS lifecycle. previously headless task commands were
invoked as `startForegroundService` which could lead to error.
* redundant stop headless task calls are removed as for end call paths
fgs will be killed with corresponding headless tasks
* added singleton for tracked call ids tracking which allow to store
data with no dependency to native module lifecycle (important for
initiating call register from native pn service)
* added promise resolution for `startCall` the same manner it was done
for `displayIncomingCall`. this fixes behavior of `startCallingxCall`,
as we want to execute `setCurrentCallActive` synchronously after
`startCall` invocation
* added pending actions management for disconnect/answer/mute actions,
which fixes race condition for cases when action was requested
before/during Telecom API processes call registration
* moved `rejectCallWhenBusy` and `canPostNotifications` check to native
side


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added Firebase Cloud Messaging integration for push notifications on
incoming calls
* Introduced stopService API to allow users to manually stop the calling
service when needed

* **Bug Fixes**
  * Improved call event handling architecture with new event bus system
* Enhanced service lifecycle management and notification delivery
reliability
* Fixed call ring notification handling to work correctly with Firebase
integration

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Santhosh Vaiyapuri <3846977+santhoshvai@users.noreply.github.com>
Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com>
### 💡 Overview

This PR contains optimistic notification updates. The aim is to improve
notifications interaction UX.
Case: when push notification is shown and the app is in the killed
state, user still can interact with notification, but JS logic will be
executed only when JS bundle is loaded. Depending on device it make take
some time after user press some action and notification changes its
state. With notification optimistic updates for reject/accept actions
notification will change it's state immediately, with no waiting for
corresponding JS logic execution.
### 💡 Overview

As [per
documentation](https://developer.android.com/reference/android/telecom/CallControl#disconnect(android.telecom.DisconnectCause,%20java.util.concurrent.Executor,%20android.os.OutcomeReceiver%3Cjava.lang.Void,android.telecom.CallException%3E))
Telecom API disconnect method accepts limited disconnect cause codes.
This PR adjust disconnect reason codes mapping, so that only valid
values can be passed to Telecom API disconnect method. Using codes
outside that range causes a crash:

<img width="2133" height="325" alt="image"
src="https://github.com/user-attachments/assets/db0af743-1453-4b6c-aeec-cb9ecc5ad96a"
/>
…2119)

### 💡 Overview

According to callkit spec 

1. we need to fulfill or fail based on server result for accept and
endcall if there is no websocket established yet
2. If websocket was established we must immediately fulfill or fail
accordingly

* This avoids other calls to interfere while joining or ending happens
(which can technically but rarely happen)
* **Importantly** - Fixes the issue of quick decline not working due to
JS bridge not loading at all - [link to the issue in
callkeep](#2119)

#### Apple docs excerpt below


https://developer.apple.com/documentation/PushKit/responding-to-voip-notifications-from-pushkit

- If the recipient of a call answers before the app establishes a
connection to your server, don’t fulfill the
[CXAnswerCallAction](https://developer.apple.com/documentation/CallKit/CXAnswerCallAction)
object sent to the
[provider(_:perform:)](https://developer.apple.com/documentation/CallKit/CXProviderDelegate/provider(_:perform:)-h4in)
method of your delegate immediately. Instead, wait until you establish a
connection and then fulfill the object. While it waits for your app to
fulfill the request, the incoming call interface lets the user know that
the call is connecting, but not yet ready.

---------

Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com>
### 💡 Overview

This PR contains multi call support for Android Telecom integration.
Main goal is to be able to manage notification for several simultaneous
calls. E.g. if user is in active call they might receive new incoming
call. For that new call new notification should be displayed and user
should be able to reject/accept new incoming call.

Call repository refactor will allow to implement several simultaneous
calls in future when "on hold" functionality will be presented.


https://github.com/user-attachments/assets/0aa1cacd-c658-4a0b-b99d-58dce238fba5

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved notification handling and management for multiple concurrent
calls
* Fixed call acceptance to automatically leave other active calls before
joining a new call
* Enhanced cleanup of call state when registration times out or calls
end

* **Refactor**
* Refactored internal call state tracking to provide better support for
simultaneous calls

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Santhosh Vaiyapuri <santhoshvai@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants