Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/client/src/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,15 +656,15 @@ export class Call {
reasonToEndCallReason[
rejectReason as keyof typeof reasonToEndCallReason
] ?? 'rejected';
globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
await this.reject(rejectReason);
globalThis.streamRNVideoSDK?.callingX?.endCall(this, endCallReason);
} else {
// if reject was undefined, we still have to cancel the call automatically
// when I am the creator and everyone else left the call
const hasOtherParticipants = this.state.remoteParticipants.length > 0;
if (this.isCreatedByMe && !hasOtherParticipants) {
globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
await this.reject('cancel');
globalThis.streamRNVideoSDK?.callingX?.endCall(this, 'canceled');
}
}
}
Expand Down
10 changes: 7 additions & 3 deletions packages/client/src/helpers/RNSpeechDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ export class RNSpeechDetector {
: await navigator.mediaDevices.getUserMedia({ audio: true });
this.audioStream = audioStream;

this.pc1.addEventListener('icecandidate', async (e) => {
await this.pc2.addIceCandidate(e.candidate);
this.pc1.addEventListener('icecandidate', (e) => {
this.pc2.addIceCandidate(e.candidate).catch(() => {
// do nothing
});
});
this.pc2.addEventListener('icecandidate', async (e) => {
await this.pc1.addIceCandidate(e.candidate);
this.pc1.addIceCandidate(e.candidate).catch(() => {
// do nothing
});
});
this.pc2.addEventListener('track', (e) => {
e.streams[0].getTracks().forEach((track) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,25 +317,19 @@ class CallNotificationManager(
if (call.isIncoming() && !call.isActive && optimisticState == OptimisticState.NONE) {
return NotificationCompat.CallStyle.forIncomingCall(
caller,
NotificationIntentFactory.getPendingBroadcastIntent(
context,
CallingxModuleImpl.CALL_END_ACTION,
call.id
) {
putExtra(
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
)
putExtra(
CallingxModuleImpl.EXTRA_SOURCE,
CallRepository.EventSource.SYS.name.lowercase()
)
},
NotificationIntentFactory.getPendingNotificationIntent(
context,
CallingxModuleImpl.CALL_END_ACTION,
call.id,
CallRepository.EventSource.SYS.name.lowercase(),
false
),
NotificationIntentFactory.getPendingNotificationIntent(
context,
CallingxModuleImpl.CALL_ANSWERED_ACTION,
call.id,
CallRepository.EventSource.SYS.name.lowercase()
CallRepository.EventSource.SYS.name.lowercase(),
true
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ object NotificationIntentFactory {
context: Context,
action: String,
callId: String,
source: String
source: String,
includeLaunchActivity: Boolean
): PendingIntent {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
getReceiverActivityIntent(context, action, callId, source)
getReceiverActivityIntent(context, action, callId, source, includeLaunchActivity)
} else {
getPendingServiceIntent(context, action, callId, source)
}
Expand All @@ -47,7 +48,7 @@ object NotificationIntentFactory {
)
}

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

val launchActivity = context.packageManager.getLaunchIntentForPackage(context.packageName)
val launchActivityIntent =
Intent(launchActivity).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
launchActivity?.let { base ->
Intent(base).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
}

// intents are started in order and build a synthetic back stack
// the last intent is the one on top, so the launch activity should come first
val intents =
if (includeLaunchActivity && launchActivityIntent != null) {
arrayOf(launchActivityIntent, receiverIntent)
} else {
arrayOf(receiverIntent)
}

return PendingIntent.getActivities(
context,
requestCodeFor(callId, REQUEST_CODE_RECEIVER_ACTIVITY),
arrayOf(launchActivityIntent, receiverIntent),
intents,
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package io.getstream.rn.callingx.notifications
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.telecom.DisconnectCause
import io.getstream.rn.callingx.CallingxModuleImpl
import io.getstream.rn.callingx.debugLog
import io.getstream.rn.callingx.getDisconnectCauseString

// For Android 12+
class NotificationReceiverActivity : Activity() {
Expand All @@ -21,33 +23,54 @@ class NotificationReceiverActivity : Activity() {
finish()
}

//re-send intent from notification to the turbo module
private fun handleIntent(intent: Intent?) {
if (intent == null) {
return
val nonNullIntent = intent ?: return
val action = nonNullIntent.action ?: return

when (action) {
CallingxModuleImpl.CALL_ANSWERED_ACTION -> onCallAnswered(nonNullIntent)
CallingxModuleImpl.CALL_END_ACTION -> onCallEnded(nonNullIntent)
}
}

if (intent.action == CallingxModuleImpl.CALL_ANSWERED_ACTION) {
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] answered call action")
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)

if (callId != null) {
Intent(CallingxModuleImpl.CALL_OPTIMISTIC_ACCEPT_ACTION)
.apply {
setPackage(packageName)
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
}
.also { sendBroadcast(it) }
}
private fun onCallAnswered(intent: Intent) {
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] answered call action")
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)

Intent(CallingxModuleImpl.CALL_ANSWERED_ACTION)
if (callId != null) {
Intent(CallingxModuleImpl.CALL_OPTIMISTIC_ACCEPT_ACTION)
.apply {
setPackage(packageName)
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
}
.also { sendBroadcast(it) }
}

Intent(CallingxModuleImpl.CALL_ANSWERED_ACTION)
.apply {
setPackage(packageName)
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
}
.also { sendBroadcast(it) }
}

private fun onCallEnded(intent: Intent) {
debugLog("[Callingx] NotificationReceiverActivity", "[receiver] rejected call action")
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)

Intent(CallingxModuleImpl.CALL_END_ACTION)
.apply {
setPackage(packageName)
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
putExtra(
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
)
}
.also { sendBroadcast(it) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package io.getstream.rn.callingx.notifications
import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.telecom.DisconnectCause
import android.util.Log
import io.getstream.rn.callingx.CallingxModuleImpl
import io.getstream.rn.callingx.getDisconnectCauseString

class NotificationReceiverService : Service() {

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

when (action) {
CallingxModuleImpl.CALL_ANSWERED_ACTION -> onCallAnswered(intent)
CallingxModuleImpl.CALL_END_ACTION -> onCallEnded(intent)
}

stopSelf(startId)
Expand Down Expand Up @@ -60,4 +63,25 @@ class NotificationReceiverService : Service() {
}
}
}

/** Mirrors [NotificationReceiverActivity] on API levels below 33 where the service receives notification actions. */
private fun onCallEnded(intent: Intent) {
val callId = intent.getStringExtra(CallingxModuleImpl.EXTRA_CALL_ID)
val source = intent.getStringExtra(CallingxModuleImpl.EXTRA_SOURCE)
try {
Intent(CallingxModuleImpl.CALL_END_ACTION)
.apply {
setPackage(packageName)
putExtra(CallingxModuleImpl.EXTRA_CALL_ID, callId)
putExtra(CallingxModuleImpl.EXTRA_SOURCE, source)
putExtra(
CallingxModuleImpl.EXTRA_DISCONNECT_CAUSE,
getDisconnectCauseString(DisconnectCause(DisconnectCause.REJECTED))
)
}
.also { sendBroadcast(it) }
} catch (e: Exception) {
Log.e(TAG, "Error sending call end intent", e)
}
}
}
2 changes: 1 addition & 1 deletion packages/react-native-callingx/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"devDependencies": {
"@react-native-community/cli": "20.0.1",
"@react-native/babel-preset": "^0.81.5",
"@stream-io/react-native-webrtc": "137.1.2",
"@stream-io/react-native-webrtc": "137.1.3",
"@types/react": "^19.1.0",
"del-cli": "^6.0.0",
"react": "19.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@
#import <WebRTC/RTCVideoRenderer.h>
#import <WebRTC/RTCVideoFrameBuffer.h>
#import "WebRTCModule.h"
#import "WebRTCModuleOptions.h"
#import "WebRTCModuleOptions.h"


6 changes: 4 additions & 2 deletions packages/react-native-sdk/ios/StreamVideoReactNative.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
#import <AudioToolbox/AudioToolbox.h>

// Import Swift-generated header for ScreenShareAudioMixer
#if __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
#import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
#if __has_feature(modules)
@import stream_react_native_webrtc.Swift;
#elif __has_include("stream_react_native_webrtc-Swift.h")
#import "stream_react_native_webrtc-Swift.h"
#elif __has_include(<stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>)
#import <stream_react_native_webrtc/stream_react_native_webrtc-Swift.h>
#endif

// Do not change these consts, it is what is used react-native-webrtc
Expand Down
Loading
Loading