Skip to content

Commit 9f01cc4

Browse files
feat: update ringing-tutorial with callingx (#2184)
### 💡 Overview Also updated the sample to expo 55 Docs PR: GetStream/getstream.io-tutorials#107 --------- Co-authored-by: Artem Grintsevich <greenfrvr@gmail.com>
1 parent 67b71eb commit 9f01cc4

File tree

22 files changed

+5335
-4151
lines changed

22 files changed

+5335
-4151
lines changed

packages/client/src/Call.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -656,15 +656,15 @@ export class Call {
656656
reasonToEndCallReason[
657657
rejectReason as keyof typeof reasonToEndCallReason
658658
] ?? 'rejected';
659-
globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
660659
await this.reject(rejectReason);
660+
globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
661661
} else {
662662
// if reject was undefined, we still have to cancel the call automatically
663663
// when I am the creator and everyone else left the call
664664
const hasOtherParticipants = this.state.remoteParticipants.length > 0;
665665
if (this.isCreatedByMe && !hasOtherParticipants) {
666-
globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
667666
await this.reject('cancel');
667+
globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
668668
}
669669
}
670670
}

packages/client/src/helpers/RNSpeechDetector.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,15 @@ export class RNSpeechDetector {
2323
: await navigator.mediaDevices.getUserMedia({ audio: true });
2424
this.audioStream = audioStream;
2525

26-
this.pc1.addEventListener('icecandidate', async (e) => {
27-
await this.pc2.addIceCandidate(e.candidate);
26+
this.pc1.addEventListener('icecandidate', (e) => {
27+
this.pc2.addIceCandidate(e.candidate).catch(() => {
28+
// do nothing
29+
});
2830
});
2931
this.pc2.addEventListener('icecandidate', async (e) => {
30-
await this.pc1.addIceCandidate(e.candidate);
32+
this.pc1.addIceCandidate(e.candidate).catch(() => {
33+
// do nothing
34+
});
3135
});
3236
this.pc2.addEventListener('track', (e) => {
3337
e.streams[0].getTracks().forEach((track) => {

packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/notifications/CallNotificationManager.kt

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -317,25 +317,19 @@ class CallNotificationManager(
317317
if (call.isIncoming() && !call.isActive && optimisticState == OptimisticState.NONE) {
318318
return NotificationCompat.CallStyle.forIncomingCall(
319319
caller,
320-
NotificationIntentFactory.getPendingBroadcastIntent(
321-
context,
322-
CallingxModuleImpl.CALL_END_ACTION,
323-
call.id
324-
) {
325-
putExtra(
326-
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
327-
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
328-
)
329-
putExtra(
330-
CallingxModuleImpl.EXTRA_SOURCE,
331-
CallRepository.EventSource.SYS.name.lowercase()
332-
)
333-
},
320+
NotificationIntentFactory.getPendingNotificationIntent(
321+
context,
322+
CallingxModuleImpl.CALL_END_ACTION,
323+
call.id,
324+
CallRepository.EventSource.SYS.name.lowercase(),
325+
false
326+
),
334327
NotificationIntentFactory.getPendingNotificationIntent(
335328
context,
336329
CallingxModuleImpl.CALL_ANSWERED_ACTION,
337330
call.id,
338-
CallRepository.EventSource.SYS.name.lowercase()
331+
CallRepository.EventSource.SYS.name.lowercase(),
332+
true
339333
)
340334
)
341335
}

packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationIntentFactory.kt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ object NotificationIntentFactory {
2222
context: Context,
2323
action: String,
2424
callId: String,
25-
source: String
25+
source: String,
26+
includeLaunchActivity: Boolean
2627
): PendingIntent {
2728
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
28-
getReceiverActivityIntent(context, action, callId, source)
29+
getReceiverActivityIntent(context, action, callId, source, includeLaunchActivity)
2930
} else {
3031
getPendingServiceIntent(context, action, callId, source)
3132
}
@@ -47,7 +48,7 @@ object NotificationIntentFactory {
4748
)
4849
}
4950

50-
fun getReceiverActivityIntent(context: Context, action: String, callId: String, source: String): PendingIntent {
51+
fun getReceiverActivityIntent(context: Context, action: String, callId: String, source: String, includeLaunchActivity: Boolean): PendingIntent {
5152
val receiverIntent =
5253
Intent(context, NotificationReceiverActivity::class.java).apply {
5354
this.action = action
@@ -57,14 +58,25 @@ object NotificationIntentFactory {
5758

5859
val launchActivity = context.packageManager.getLaunchIntentForPackage(context.packageName)
5960
val launchActivityIntent =
60-
Intent(launchActivity).apply {
61-
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
61+
launchActivity?.let { base ->
62+
Intent(base).apply {
63+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
64+
}
65+
}
66+
67+
// intents are started in order and build a synthetic back stack
68+
// the last intent is the one on top, so the launch activity should come first
69+
val intents =
70+
if (includeLaunchActivity && launchActivityIntent != null) {
71+
arrayOf(launchActivityIntent, receiverIntent)
72+
} else {
73+
arrayOf(receiverIntent)
6274
}
6375

6476
return PendingIntent.getActivities(
6577
context,
6678
requestCodeFor(callId, REQUEST_CODE_RECEIVER_ACTIVITY),
67-
arrayOf(launchActivityIntent, receiverIntent),
79+
intents,
6880
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
6981
)
7082
}

packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverActivity.kt

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package io.getstream.rn.callingx.notifications
33
import android.app.Activity
44
import android.content.Intent
55
import android.os.Bundle
6+
import android.telecom.DisconnectCause
67
import io.getstream.rn.callingx.CallingxModuleImpl
78
import io.getstream.rn.callingx.debugLog
9+
import io.getstream.rn.callingx.getDisconnectCauseString
810

911
// For Android 12+
1012
class NotificationReceiverActivity : Activity() {
@@ -21,33 +23,54 @@ class NotificationReceiverActivity : Activity() {
2123
finish()
2224
}
2325

24-
//re-send intent from notification to the turbo module
2526
private fun handleIntent(intent: Intent?) {
26-
if (intent == null) {
27-
return
27+
val nonNullIntent = intent ?: return
28+
val action = nonNullIntent.action ?: return
29+
30+
when (action) {
31+
CallingxModuleImpl.CALL_ANSWERED_ACTION -> onCallAnswered(nonNullIntent)
32+
CallingxModuleImpl.CALL_END_ACTION -> onCallEnded(nonNullIntent)
2833
}
34+
}
2935

30-
if (intent.action == CallingxModuleImpl.CALL_ANSWERED_ACTION) {
31-
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] answered call action")
32-
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
33-
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
34-
35-
if (callId != null) {
36-
Intent(CallingxModuleImpl.CALL_OPTIMISTIC_ACCEPT_ACTION)
37-
.apply {
38-
setPackage(packageName)
39-
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
40-
}
41-
.also { sendBroadcast(it) }
42-
}
36+
private fun onCallAnswered(intent: Intent) {
37+
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] answered call action")
38+
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
39+
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
4340

44-
Intent(CallingxModuleImpl.CALL_ANSWERED_ACTION)
41+
if (callId != null) {
42+
Intent(CallingxModuleImpl.CALL_OPTIMISTIC_ACCEPT_ACTION)
4543
.apply {
4644
setPackage(packageName)
4745
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
48-
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
4946
}
5047
.also { sendBroadcast(it) }
5148
}
49+
50+
Intent(CallingxModuleImpl.CALL_ANSWERED_ACTION)
51+
.apply {
52+
setPackage(packageName)
53+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
54+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
55+
}
56+
.also { sendBroadcast(it) }
57+
}
58+
59+
private fun onCallEnded(intent: Intent) {
60+
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] rejected call action")
61+
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
62+
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
63+
64+
Intent(CallingxModuleImpl.CALL_END_ACTION)
65+
.apply {
66+
setPackage(packageName)
67+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
68+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
69+
putExtra(
70+
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
71+
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
72+
)
73+
}
74+
.also { sendBroadcast(it) }
5275
}
5376
}

packages/react-native-callingx/android/src/main/java/io/getstream/rn/callingx/notifications/NotificationReceiverService.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package io.getstream.rn.callingx.notifications
33
import android.app.Service
44
import android.content.Intent
55
import android.os.IBinder
6+
import android.telecom.DisconnectCause
67
import android.util.Log
78
import io.getstream.rn.callingx.CallingxModuleImpl
9+
import io.getstream.rn.callingx.getDisconnectCauseString
810

911
class NotificationReceiverService : Service() {
1012

@@ -23,6 +25,7 @@ class NotificationReceiverService : Service() {
2325

2426
when (action) {
2527
CallingxModuleImpl.CALL_ANSWERED_ACTION -> onCallAnswered(intent)
28+
CallingxModuleImpl.CALL_END_ACTION -> onCallEnded(intent)
2629
}
2730

2831
stopSelf(startId)
@@ -60,4 +63,25 @@ class NotificationReceiverService : Service() {
6063
}
6164
}
6265
}
66+
67+
/** Mirrors [NotificationReceiverActivity] on API levels below 33 where the service receives notification actions. */
68+
private fun onCallEnded(intent: Intent) {
69+
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
70+
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
71+
try {
72+
Intent(CallingxModuleImpl.CALL_END_ACTION)
73+
.apply {
74+
setPackage(packageName)
75+
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
76+
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
77+
putExtra(
78+
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
79+
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
80+
)
81+
}
82+
.also { sendBroadcast(it) }
83+
} catch (e: Exception) {
84+
Log.e(TAG, "Error sending call end intent", e)
85+
}
86+
}
6387
}

packages/react-native-callingx/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"devDependencies": {
6262
"@react-native-community/cli": "20.0.1",
6363
"@react-native/babel-preset": "^0.81.5",
64-
"@stream-io/react-native-webrtc": "137.1.2",
64+
"@stream-io/react-native-webrtc": "137.1.3",
6565
"@types/react": "^19.1.0",
6666
"del-cli": "^6.0.0",
6767
"react": "19.1.0",

packages/react-native-sdk/ios/StreamVideoReactNative-Bridging-Header.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212
#import <WebRTC/RTCVideoRenderer.h>
1313
#import <WebRTC/RTCVideoFrameBuffer.h>
1414
#import "WebRTCModule.h"
15-
#import "WebRTCModuleOptions.h"
15+
#import "WebRTCModuleOptions.h"
16+
17+

packages/react-native-sdk/ios/StreamVideoReactNative.m

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
#import <AudioToolbox/AudioToolbox.h>
1414

1515
// Import Swift-generated header for ScreenShareAudioMixer
16-
#if __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
17-
#import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
16+
#if __has_feature(modules)
17+
@import stream_react_native_webrtc.Swift;
1818
#elif __has_include("stream_react_native_webrtc-Swift.h")
1919
#import "stream_react_native_webrtc-Swift.h"
20+
#elif __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
21+
#import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
2022
#endif
2123

2224
// Do not change these consts, it is what is used react-native-webrtc

0 commit comments

Comments
 (0)