Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new “VoIP calls” how-to guide for the React Native (mobile) SDK, covering PushKit/APNs on iOS and FCM/Telecom on Android, and updates navigation/supporting docs to incorporate the new page.
Changes:
- Introduces a comprehensive
VoIP callsguide underdocs/how-to/client/. - Adjusts sidebar ordering (
sidebar_position) across nearby client how-to pages to make room for the new guide. - Updates spellchecker allowlist to include VoIP/CallKit/PushKit/Telecom/APNs/FCM and related terms.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| spelling.txt | Adds VoIP-related proper nouns/terms to the spellchecker allowlist. |
| docusaurus.config.ts | Tweaks Shiki/Twoslash error filtering helper used during MDX rendering. |
| docs/how-to/client/voip-calls.mdx | New VoIP calls documentation page for React Native apps (iOS/Android). |
| docs/how-to/client/text-chat.mdx | Updates sidebar ordering to accommodate the new VoIP page. |
| docs/how-to/client/simulcast.mdx | Updates sidebar ordering to accommodate the new VoIP page. |
| docs/how-to/client/migration-guide.mdx | Updates sidebar ordering to accommodate the new VoIP page. |
| docs/how-to/client/ios-simulator-camera.mdx | Updates sidebar ordering to accommodate the new VoIP page. |
| docs/how-to/client/background-streaming.mdx | Adds a “See also” link pointing readers to the new VoIP calls guide. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
## Description Adds VoIP calling to the Fishjam React Native SDK. Calls ring through the native call UI — CallKit on iOS, Core Telecom on Android — even when the app is backgrounded or killed, and the media runs over a regular Fishjam room. **SDK — `@fishjam-cloud/react-native-client`** - `VoIPProvider` + `useVoIP()`: a call state machine (`available → incoming | connecting → active`) driven by native call events. The SDK owns the CallKit/Telecom session, the VoIP push token, and hold/mute/end-reason state; joining the room, peer tokens and media stay in the app, which reacts to `status` and reports back with `reportConnected()` / `reportConnectFailed()`. - Also re-exports the lower-level primitives from the WebRTC fork (`useVoIPEvents`, `useTelecom`, `fulfillIncomingCallConnected`, …) for apps that want to drive the native layer themselves. - Config plugin: new `android.enableVoIP`, FCM coexistence options (`voipMessagingService`, `voipFallbackMessagingService`) and a `voip` block for the native call timeouts and notification icon. On Android it injects the manifest entries (`IncomingCallActivity`, `EndCallNotificationReceiver`, `PushNotificationService` + FCM intent filter), the required permissions and the foreground service. On iOS it writes `FishjamVoIPEnabled`, the timeout `Info.plist` keys and the `INStartCallIntent` activity types needed for Recents redial. **New package — `@fishjam-cloud/ios-expo-voip`** An `ExpoAppDelegateSubscriber` with no JS and no VoIP logic of its own. It starts the PushKit registry at launch so a push arriving before the JS bundle loads can still ring, and routes Siri / Phone-app Recents intents into the SDK. It is a no-op unless the config plugin enabled VoIP. Added to the release workflow (published after the WebRTC fork, which its pod depends on) and to `bump-version.sh`; excluded from typedoc. **Example — `examples/mobile-client/voip-call`** A two-user calling app: an Expo client plus a small Deno push + signaling server (`/register`, `/users`, `/call`, `/ws`) that sends the APNs/FCM pushes. It exercises the whole surface — device registration, ringing while killed, hold & accept, and Recents redial. ## Motivation and Context Fishjam could already carry the media for a call, but not the call itself. To build one-to-one calling on top of it, an app had to write its own CallKit and Core Telecom integration, VoIP push handling, cold-start wake-up and answer-fulfillment handshake before it could join a room — a large amount of platform-specific native work, duplicated by every consumer. This moves that layer into the SDK. The app keeps what is genuinely its own (rooms, peer tokens, media, signaling between users) and reacts to a single `status` value, while the SDK owns the native call session on both platforms. ## Documentation impact - [ ] Documentation update required - [x] Documentation updated [in another PR](fishjam-cloud/documentation#279) - [ ] No documentation update required ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) --------- Co-authored-by: Miłosz Filimowski <MiloszFilimowski@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
| ::: | ||
|
|
||
| :::info[You need a push sender] | ||
| Delivering the push is your backend's job: it sends a **VoIP push via APNs** (iOS) |
There was a problem hiding this comment.
nitpick:
| Delivering the push is your backend's job: it sends a **VoIP push via APNs** (iOS) | |
| Delivering a push notification is your backend's job: it sends a **VoIP push via APNs** (iOS) |
| CallKit / Telecom. `status` becomes `incoming`. | ||
| 3. The user answers on the **system** call UI. `status` becomes `connecting`. | ||
| 4. **Your app** joins the Fishjam room and waits for the remote media. | ||
| 5. Once media is live, **your app** calls `reportConnected()`. The SDK confirms the |
There was a problem hiding this comment.
question: what's reportConnected()? is there a reference to this function somewhere here?
|
|
||
| ## 5. Connect calls to a room | ||
|
|
||
| This is the bridge between the two halves. `VoIPProvider` tells you a call needs a room; |
There was a problem hiding this comment.
nitpick: between the two halves sound a bit unclear to me while jumping straight from reading about persisting a voiptoken
| declare function getPeerToken(roomName: string): Promise<string>; | ||
| // ---cut--- | ||
| function useVoIPRoomConnection() { | ||
| const { status, currentCall, reportConnected, reportConnectFailed, endCall } = |
There was a problem hiding this comment.
suggestion:
it should be sth like voidStatus to avoid the connections status confusion
| const { status, currentCall, reportConnected, reportConnectFailed, endCall } = | |
| const { voipStatus, currentCall, reportConnected, reportConnectFailed, endCall } = |
|
|
||
| // Join the room the SDK is asking for; leave it when the call ends. | ||
| const targetRoom = | ||
| status === "connecting" || status === "active" |
There was a problem hiding this comment.
question: is the dependency on status needed here?
| **You tell the provider:** | ||
|
|
||
| - `reportConnected()` once media is live, or `reportConnectFailed()` if the join failed. | ||
| - `endCall('remote')` when the other side disappears from the room. |
There was a problem hiding this comment.
question: what does remote mean here and are there other options than remote?
There was a problem hiding this comment.
i see now below, maybe we can put an anchor link here if someone is curious, or just say it'll be explained below
Description
Adds a how-to guide for the React Native SDK's VoIP feature:
docs/how-to/client/voip-calls.mdx.The page covers the full app side: native setup (Expo / Bare tabs), the
VoipProvidercontract (join the room onconnecting,reportConnected()when media is live), incoming push payload, outgoing calls, ending calls andlastEndedReason, hold/mute, and Recents redial. All snippets type-check against the bumpedweb-client-sdksubmodule.Supporting changes: sidebar positions + a cross-link from Background streaming, a twoslash error-handling tweak in
docusaurus.config.ts, spelling entries, submodule bumps.Note: links to the
voip-callexample 404 until the SDK-side PR merges.