@capgo/capacitor-stream-call 0.0.51 → 0.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapgoCapacitorStreamCall.podspec +2 -2
- package/Package.swift +1 -1
- package/README.md +24 -14
- package/android/build.gradle +2 -2
- package/android/src/main/java/ee/forgr/capacitor/streamcall/CustomNotificationHandler.kt +4 -3
- package/android/src/main/java/ee/forgr/capacitor/streamcall/RingtonePlayer.kt +109 -109
- package/android/src/main/java/ee/forgr/capacitor/streamcall/StreamCallPlugin.kt +75 -90
- package/dist/docs.json +39 -0
- package/dist/esm/definitions.d.ts +7 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js +9 -7
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +9 -7
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +9 -7
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/StreamCallPlugin/StreamCallPlugin.swift +63 -12
- package/ios/Sources/StreamCallPlugin/TouchInterceptView.swift +59 -2
- package/package.json +1 -1
|
@@ -1,45 +1,42 @@
|
|
|
1
1
|
package ee.forgr.capacitor.streamcall
|
|
2
2
|
|
|
3
3
|
import TouchInterceptWrapper
|
|
4
|
+
import android.Manifest
|
|
4
5
|
import android.app.Activity
|
|
5
6
|
import android.app.Application
|
|
6
7
|
import android.app.KeyguardManager
|
|
8
|
+
import android.content.BroadcastReceiver
|
|
7
9
|
import android.content.Context
|
|
10
|
+
import android.content.Intent
|
|
11
|
+
import android.content.IntentFilter
|
|
12
|
+
import android.content.pm.PackageManager
|
|
8
13
|
import android.graphics.Color
|
|
9
14
|
import android.media.RingtoneManager
|
|
10
15
|
import android.net.Uri
|
|
16
|
+
import android.os.Build
|
|
11
17
|
import android.os.Bundle
|
|
12
18
|
import android.os.Handler
|
|
13
19
|
import android.os.Looper
|
|
14
20
|
import android.view.View
|
|
15
21
|
import android.view.ViewGroup
|
|
22
|
+
import android.view.WindowManager
|
|
16
23
|
import android.widget.FrameLayout
|
|
24
|
+
import androidx.compose.runtime.collectAsState
|
|
17
25
|
import androidx.compose.ui.platform.ComposeView
|
|
26
|
+
import androidx.core.app.ActivityCompat
|
|
27
|
+
import androidx.core.content.ContextCompat
|
|
18
28
|
import androidx.core.view.isVisible
|
|
19
29
|
import com.getcapacitor.BridgeActivity
|
|
30
|
+
import com.getcapacitor.JSArray
|
|
20
31
|
import com.getcapacitor.JSObject
|
|
21
32
|
import com.getcapacitor.Plugin
|
|
22
33
|
import com.getcapacitor.PluginCall
|
|
23
34
|
import com.getcapacitor.PluginMethod
|
|
24
35
|
import com.getcapacitor.annotation.CapacitorPlugin
|
|
25
|
-
import io.getstream.android.push.permissions.ActivityLifecycleCallbacks
|
|
26
|
-
import io.getstream.video.android.core.Call
|
|
27
|
-
import io.getstream.video.android.core.GEO
|
|
28
|
-
import io.getstream.video.android.core.StreamVideo
|
|
29
|
-
import io.getstream.video.android.core.StreamVideoBuilder
|
|
30
|
-
import io.getstream.video.android.core.notifications.NotificationConfig
|
|
31
|
-
import io.getstream.video.android.core.notifications.NotificationHandler
|
|
32
|
-
import io.getstream.video.android.core.sounds.toSounds
|
|
33
|
-
import io.getstream.video.android.model.StreamCallId
|
|
34
|
-
import io.getstream.video.android.model.User
|
|
35
|
-
import io.getstream.video.android.model.streamCallId
|
|
36
|
-
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
37
|
-
import kotlinx.coroutines.launch
|
|
38
|
-
import io.getstream.video.android.model.Device
|
|
39
|
-
import kotlinx.coroutines.tasks.await
|
|
40
36
|
import com.google.firebase.messaging.FirebaseMessaging
|
|
41
37
|
import io.getstream.android.push.PushProvider
|
|
42
38
|
import io.getstream.android.push.firebase.FirebasePushDeviceGenerator
|
|
39
|
+
import io.getstream.android.push.permissions.ActivityLifecycleCallbacks
|
|
43
40
|
import io.getstream.android.video.generated.models.CallAcceptedEvent
|
|
44
41
|
import io.getstream.android.video.generated.models.CallCreatedEvent
|
|
45
42
|
import io.getstream.android.video.generated.models.CallEndedEvent
|
|
@@ -47,26 +44,36 @@ import io.getstream.android.video.generated.models.CallMissedEvent
|
|
|
47
44
|
import io.getstream.android.video.generated.models.CallRejectedEvent
|
|
48
45
|
import io.getstream.android.video.generated.models.CallRingEvent
|
|
49
46
|
import io.getstream.android.video.generated.models.CallSessionEndedEvent
|
|
47
|
+
import io.getstream.android.video.generated.models.CallSessionParticipantLeftEvent
|
|
50
48
|
import io.getstream.android.video.generated.models.CallSessionStartedEvent
|
|
51
|
-
import io.getstream.video.android.core.sounds.RingingConfig
|
|
52
|
-
import kotlinx.coroutines.CoroutineScope
|
|
53
|
-
import kotlinx.coroutines.Dispatchers
|
|
54
|
-
import android.Manifest
|
|
55
|
-
import android.content.pm.PackageManager
|
|
56
|
-
import androidx.core.app.ActivityCompat
|
|
57
|
-
import androidx.core.content.ContextCompat
|
|
58
49
|
import io.getstream.android.video.generated.models.VideoEvent
|
|
50
|
+
import io.getstream.log.Priority
|
|
59
51
|
import io.getstream.video.android.compose.theme.VideoTheme
|
|
60
52
|
import io.getstream.video.android.compose.ui.components.call.activecall.CallContent
|
|
61
|
-
import
|
|
53
|
+
import io.getstream.video.android.core.Call
|
|
62
54
|
import io.getstream.video.android.core.CameraDirection
|
|
63
|
-
import android.
|
|
64
|
-
import android.content.Intent
|
|
65
|
-
import android.content.IntentFilter
|
|
66
|
-
import com.getcapacitor.JSArray
|
|
67
|
-
import io.getstream.android.video.generated.models.CallSessionParticipantLeftEvent
|
|
55
|
+
import io.getstream.video.android.core.GEO
|
|
68
56
|
import io.getstream.video.android.core.RealtimeConnection
|
|
57
|
+
import io.getstream.video.android.core.StreamVideo
|
|
58
|
+
import io.getstream.video.android.core.StreamVideoBuilder
|
|
59
|
+
import io.getstream.video.android.core.call.CallType
|
|
69
60
|
import io.getstream.video.android.core.events.ParticipantLeftEvent
|
|
61
|
+
import io.getstream.video.android.core.logging.LoggingLevel
|
|
62
|
+
import io.getstream.video.android.core.notifications.NotificationConfig
|
|
63
|
+
import io.getstream.video.android.core.notifications.NotificationHandler
|
|
64
|
+
import io.getstream.video.android.core.notifications.internal.service.CallServiceConfigRegistry
|
|
65
|
+
import io.getstream.video.android.core.notifications.internal.service.DefaultCallConfigurations
|
|
66
|
+
import io.getstream.video.android.core.sounds.RingingConfig
|
|
67
|
+
import io.getstream.video.android.core.sounds.toSounds
|
|
68
|
+
import io.getstream.video.android.model.Device
|
|
69
|
+
import io.getstream.video.android.model.StreamCallId
|
|
70
|
+
import io.getstream.video.android.model.User
|
|
71
|
+
import io.getstream.video.android.model.streamCallId
|
|
72
|
+
import kotlinx.coroutines.CoroutineScope
|
|
73
|
+
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
74
|
+
import kotlinx.coroutines.Dispatchers
|
|
75
|
+
import kotlinx.coroutines.launch
|
|
76
|
+
import kotlinx.coroutines.tasks.await
|
|
70
77
|
|
|
71
78
|
// I am not a religious pearson, but at this point, I am not sure even god himself would understand this code
|
|
72
79
|
// It's a spaghetti-like, tangled, unreadable mess and frankly, I am deeply sorry for the code crimes commited in the Android impl
|
|
@@ -76,7 +83,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
76
83
|
private var state: State = State.NOT_INITIALIZED
|
|
77
84
|
private var overlayView: ComposeView? = null
|
|
78
85
|
private var barrierView: View? = null
|
|
79
|
-
private var ringtonePlayer: RingtonePlayer? = null
|
|
80
86
|
private val mainHandler = Handler(Looper.getMainLooper())
|
|
81
87
|
private var savedContext: Context? = null
|
|
82
88
|
private var bootedToHandleCall: Boolean = false
|
|
@@ -112,62 +118,15 @@ public class StreamCallPlugin : Plugin() {
|
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
override fun handleOnPause() {
|
|
115
|
-
this.ringtonePlayer.let { it?.pauseRinging() }
|
|
116
121
|
super.handleOnPause()
|
|
117
122
|
}
|
|
118
123
|
|
|
119
124
|
override fun handleOnResume() {
|
|
120
|
-
this.ringtonePlayer.let { it?.resumeRinging() }
|
|
121
125
|
super.handleOnResume()
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
override fun load() {
|
|
125
129
|
// general init
|
|
126
|
-
ringtonePlayer = RingtonePlayer(
|
|
127
|
-
this.activity.application,
|
|
128
|
-
cancelIncomingCallService = {
|
|
129
|
-
val streamVideoClient = this.streamVideoClient
|
|
130
|
-
if (streamVideoClient == null) {
|
|
131
|
-
android.util.Log.d("StreamCallPlugin", "StreamVideo SDK client is null, no incoming call notification can be constructed")
|
|
132
|
-
return@RingtonePlayer
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
val callServiceClass = Class.forName("io.getstream.video.android.core.notifications.internal.service.CallService")
|
|
137
|
-
val companionClass = callServiceClass.declaredClasses.first { it.simpleName == "Companion" }
|
|
138
|
-
// Instead of getting INSTANCE, we'll get the companion object through the enclosing class
|
|
139
|
-
val companionField = callServiceClass.getDeclaredField("Companion")
|
|
140
|
-
companionField.isAccessible = true
|
|
141
|
-
val companionInstance = companionField.get(null)
|
|
142
|
-
|
|
143
|
-
val removeIncomingCallMethod = companionClass.getDeclaredMethod(
|
|
144
|
-
"removeIncomingCall",
|
|
145
|
-
Context::class.java,
|
|
146
|
-
Class.forName("io.getstream.video.android.model.StreamCallId"),
|
|
147
|
-
Class.forName("io.getstream.video.android.core.notifications.internal.service.CallServiceConfig")
|
|
148
|
-
)
|
|
149
|
-
removeIncomingCallMethod.isAccessible = true
|
|
150
|
-
|
|
151
|
-
// Get the default config using reflection
|
|
152
|
-
val defaultConfigClass = Class.forName("io.getstream.video.android.core.notifications.internal.service.DefaultCallConfigurations")
|
|
153
|
-
val defaultField = defaultConfigClass.getDeclaredField("INSTANCE")
|
|
154
|
-
val defaultInstance = defaultField.get(null)
|
|
155
|
-
val defaultMethod = defaultConfigClass.getDeclaredMethod("getDefault")
|
|
156
|
-
val defaultConfig = defaultMethod.invoke(defaultInstance)
|
|
157
|
-
|
|
158
|
-
val app = this.activity.application
|
|
159
|
-
val cId = streamVideoClient.state.ringingCall.value?.cid?.let { StreamCallId.fromCallCid(it) }
|
|
160
|
-
if (app == null || cId == null || defaultConfig == null) {
|
|
161
|
-
android.util.Log.e("StreamCallPlugin", "Some required parameters are null - app: ${app == null}, cId: ${cId == null}, defaultConfig: ${defaultConfig == null}")
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Call the method
|
|
165
|
-
removeIncomingCallMethod.invoke(companionInstance, app, cId, defaultConfig)
|
|
166
|
-
} catch (e : Throwable) {
|
|
167
|
-
android.util.Log.e("StreamCallPlugin", "Reflecting streamNotificationManager and the config DID NOT work", e);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
)
|
|
171
130
|
initializeStreamVideo()
|
|
172
131
|
setupViews()
|
|
173
132
|
super.load()
|
|
@@ -206,6 +165,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
206
165
|
|
|
207
166
|
if (action === "io.getstream.video.android.action.INCOMING_CALL") {
|
|
208
167
|
android.util.Log.d("StreamCallPlugin", "handleOnNewIntent: Matched INCOMING_CALL action")
|
|
168
|
+
// We need to make sure the activity is visible on locked screen in such case
|
|
169
|
+
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, true)
|
|
209
170
|
activity?.runOnUiThread {
|
|
210
171
|
val cid = intent.streamCallId(NotificationHandler.INTENT_EXTRA_CALL_CID)
|
|
211
172
|
android.util.Log.d("StreamCallPlugin", "handleOnNewIntent: INCOMING_CALL - Extracted cid: $cid")
|
|
@@ -213,8 +174,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
213
174
|
android.util.Log.d("StreamCallPlugin", "handleOnNewIntent: INCOMING_CALL - cid is not null, processing.")
|
|
214
175
|
val call = streamVideoClient?.call(id = cid.id, type = cid.type)
|
|
215
176
|
android.util.Log.d("StreamCallPlugin", "handleOnNewIntent: INCOMING_CALL - Got call object: ${call?.id}")
|
|
216
|
-
// Start ringtone only; UI handled in web layer
|
|
217
|
-
ringtonePlayer?.startRinging()
|
|
218
177
|
|
|
219
178
|
// Try to get caller information from the call
|
|
220
179
|
kotlinx.coroutines.GlobalScope.launch {
|
|
@@ -296,9 +255,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
296
255
|
kotlinx.coroutines.GlobalScope.launch {
|
|
297
256
|
try {
|
|
298
257
|
call.reject()
|
|
299
|
-
|
|
300
|
-
// Stop ringtone
|
|
301
|
-
ringtonePlayer?.stopRinging()
|
|
258
|
+
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, false)
|
|
302
259
|
|
|
303
260
|
// Notify that call has ended using our helper
|
|
304
261
|
updateCallStatusAndNotify(call.id, "rejected")
|
|
@@ -547,6 +504,7 @@ public class StreamCallPlugin : Plugin() {
|
|
|
547
504
|
)
|
|
548
505
|
|
|
549
506
|
val soundsConfig = incomingOnlyRingingConfig()
|
|
507
|
+
|
|
550
508
|
// Initialize StreamVideo client
|
|
551
509
|
streamVideoClient = StreamVideoBuilder(
|
|
552
510
|
context = contextToUse,
|
|
@@ -555,8 +513,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
555
513
|
user = savedCredentials.user,
|
|
556
514
|
token = savedCredentials.tokenValue,
|
|
557
515
|
notificationConfig = notificationConfig,
|
|
558
|
-
sounds = soundsConfig.toSounds()
|
|
559
|
-
|
|
516
|
+
sounds = soundsConfig.toSounds(),
|
|
517
|
+
// loggingLevel = LoggingLevel(priority = Priority.DEBUG)
|
|
560
518
|
).build()
|
|
561
519
|
|
|
562
520
|
// don't do event handler registration when activity may be null
|
|
@@ -758,7 +716,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
758
716
|
val keyguardManager = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
|
759
717
|
if (keyguardManager.isKeyguardLocked) {
|
|
760
718
|
android.util.Log.d("StreamCallPlugin", "Stop ringing and move to background")
|
|
761
|
-
this.ringtonePlayer?.stopRinging()
|
|
762
719
|
moveAllActivitiesToBackgroundOrKill(context)
|
|
763
720
|
}
|
|
764
721
|
|
|
@@ -865,9 +822,12 @@ public class StreamCallPlugin : Plugin() {
|
|
|
865
822
|
// Notify that a call has started or state updated (e.g., participants changed but still active)
|
|
866
823
|
// The actual check for "last participant" is now handled by CallSessionParticipantLeftEvent
|
|
867
824
|
updateCallStatusAndNotify(call.cid, "joined")
|
|
825
|
+
// Make sure activity is visible on lock screen
|
|
826
|
+
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, true)
|
|
868
827
|
} ?: run {
|
|
869
828
|
// Notify that call has ended using our helper
|
|
870
829
|
updateCallStatusAndNotify("", "left")
|
|
830
|
+
changeActivityAsVisibleOnLockScreen(this@StreamCallPlugin.activity, false)
|
|
871
831
|
}
|
|
872
832
|
}
|
|
873
833
|
}
|
|
@@ -967,9 +927,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
967
927
|
kotlinx.coroutines.GlobalScope.launch {
|
|
968
928
|
try {
|
|
969
929
|
android.util.Log.d("StreamCallPlugin", "internalAcceptCall: Coroutine started for call ${call.id}")
|
|
970
|
-
// Stop ringtone
|
|
971
|
-
ringtonePlayer?.stopRinging()
|
|
972
|
-
android.util.Log.d("StreamCallPlugin", "internalAcceptCall: Ringtone player stopped for call ${call.id}")
|
|
973
930
|
|
|
974
931
|
// Hide incoming call view first
|
|
975
932
|
runOnMainThread {
|
|
@@ -1274,6 +1231,12 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1274
1231
|
android.util.Log.d("StreamCallPlugin", "Leaving call $callId (not creator, >2 participants)")
|
|
1275
1232
|
call.leave()
|
|
1276
1233
|
}
|
|
1234
|
+
|
|
1235
|
+
// Here, we'll also mark the activity as not-visible on lock screen
|
|
1236
|
+
this@StreamCallPlugin.savedActivity?.let {
|
|
1237
|
+
changeActivityAsVisibleOnLockScreen(it, false)
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1277
1240
|
} catch (e: Exception) {
|
|
1278
1241
|
android.util.Log.e("StreamCallPlugin", "Error getting call info for $callId, defaulting to leave()", e)
|
|
1279
1242
|
// Fallback to leave if we can't determine the call info
|
|
@@ -1328,7 +1291,6 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1328
1291
|
}
|
|
1329
1292
|
overlayView?.isVisible = false
|
|
1330
1293
|
bridge?.webView?.setBackgroundColor(Color.WHITE) // Restore webview opacity
|
|
1331
|
-
this@StreamCallPlugin.ringtonePlayer?.stopRinging()
|
|
1332
1294
|
|
|
1333
1295
|
// Also hide incoming call view if visible
|
|
1334
1296
|
android.util.Log.d("StreamCallPlugin", "Hiding incoming call view for call $callId")
|
|
@@ -1339,6 +1301,29 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1339
1301
|
updateCallStatusAndNotify(callId, "left")
|
|
1340
1302
|
}
|
|
1341
1303
|
|
|
1304
|
+
private fun changeActivityAsVisibleOnLockScreen(activity: Activity, visible: Boolean) {
|
|
1305
|
+
if (visible) {
|
|
1306
|
+
// Ensure the activity is visible over the lock screen when launched via full-screen intent
|
|
1307
|
+
android.util.Log.d("StreamCallPlugin", "Mark the mainActivity as visible on the lockscreen")
|
|
1308
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
1309
|
+
activity.setShowWhenLocked(true)
|
|
1310
|
+
activity.setTurnScreenOn(true)
|
|
1311
|
+
} else {
|
|
1312
|
+
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
|
|
1313
|
+
}
|
|
1314
|
+
} else {
|
|
1315
|
+
// Ensure the activity is NOT visible over the lock screen when launched via full-screen intent
|
|
1316
|
+
android.util.Log.d("StreamCallPlugin", "Clear the flag for the mainActivity for visible on the lockscreen")
|
|
1317
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
|
1318
|
+
activity.setShowWhenLocked(false)
|
|
1319
|
+
activity.setTurnScreenOn(false)
|
|
1320
|
+
} else {
|
|
1321
|
+
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1342
1327
|
@OptIn(DelicateCoroutinesApi::class)
|
|
1343
1328
|
private fun transEndCallRaw(call: Call) {
|
|
1344
1329
|
val callId = call.id
|
|
@@ -1595,8 +1580,8 @@ public class StreamCallPlugin : Plugin() {
|
|
|
1595
1580
|
runOnMainThread {
|
|
1596
1581
|
android.util.Log.d("StreamCallPlugin", "Hiding UI elements for call $callCid (one-time cleanup)")
|
|
1597
1582
|
overlayView?.isVisible = false
|
|
1598
|
-
|
|
1599
|
-
|
|
1583
|
+
// here we will also make sure we don't show on lock screen
|
|
1584
|
+
changeActivityAsVisibleOnLockScreen(this.activity, false)
|
|
1600
1585
|
}
|
|
1601
1586
|
|
|
1602
1587
|
android.util.Log.d("StreamCallPlugin", "Cleaned up resources for ended call: $callCid")
|
package/dist/docs.json
CHANGED
|
@@ -546,6 +546,38 @@
|
|
|
546
546
|
"docs": "ID of the HTML element where the video will be rendered",
|
|
547
547
|
"complexTypes": [],
|
|
548
548
|
"type": "string | undefined"
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
"name": "pushNotificationsConfig",
|
|
552
|
+
"tags": [],
|
|
553
|
+
"docs": "",
|
|
554
|
+
"complexTypes": [
|
|
555
|
+
"PushNotificationsConfig"
|
|
556
|
+
],
|
|
557
|
+
"type": "PushNotificationsConfig"
|
|
558
|
+
}
|
|
559
|
+
]
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"name": "PushNotificationsConfig",
|
|
563
|
+
"slug": "pushnotificationsconfig",
|
|
564
|
+
"docs": "",
|
|
565
|
+
"tags": [],
|
|
566
|
+
"methods": [],
|
|
567
|
+
"properties": [
|
|
568
|
+
{
|
|
569
|
+
"name": "pushProviderName",
|
|
570
|
+
"tags": [],
|
|
571
|
+
"docs": "",
|
|
572
|
+
"complexTypes": [],
|
|
573
|
+
"type": "string"
|
|
574
|
+
},
|
|
575
|
+
{
|
|
576
|
+
"name": "voipProviderName",
|
|
577
|
+
"tags": [],
|
|
578
|
+
"docs": "",
|
|
579
|
+
"complexTypes": [],
|
|
580
|
+
"type": "string"
|
|
549
581
|
}
|
|
550
582
|
]
|
|
551
583
|
},
|
|
@@ -610,6 +642,13 @@
|
|
|
610
642
|
"docs": "Team name to call",
|
|
611
643
|
"complexTypes": [],
|
|
612
644
|
"type": "string | undefined"
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
"name": "video",
|
|
648
|
+
"tags": [],
|
|
649
|
+
"docs": "Whether to start the call with video enabled, defaults to false",
|
|
650
|
+
"complexTypes": [],
|
|
651
|
+
"type": "boolean | undefined"
|
|
613
652
|
}
|
|
614
653
|
]
|
|
615
654
|
},
|
|
@@ -21,6 +21,11 @@ export interface LoginOptions {
|
|
|
21
21
|
apiKey: string;
|
|
22
22
|
/** ID of the HTML element where the video will be rendered */
|
|
23
23
|
magicDivId?: string;
|
|
24
|
+
pushNotificationsConfig?: PushNotificationsConfig;
|
|
25
|
+
}
|
|
26
|
+
export interface PushNotificationsConfig {
|
|
27
|
+
pushProviderName: string;
|
|
28
|
+
voipProviderName: string;
|
|
24
29
|
}
|
|
25
30
|
/**
|
|
26
31
|
* @typedef CallState
|
|
@@ -107,6 +112,8 @@ export interface CallOptions {
|
|
|
107
112
|
ring?: boolean;
|
|
108
113
|
/** Team name to call */
|
|
109
114
|
team?: string;
|
|
115
|
+
/** Whether to start the call with video enabled, defaults to false */
|
|
116
|
+
video?: boolean;
|
|
110
117
|
}
|
|
111
118
|
/**
|
|
112
119
|
* @interface StreamCallPlugin
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n}\n\n/**\n * @typedef CallState\n * @description Represents all possible call states from API and UI\n */\nexport type CallState =\n // User-facing states\n | 'idle'\n | 'ringing'\n | 'joining'\n | 'reconnecting'\n | 'joined'\n | 'leaving'\n | 'left'\n // Event-specific states\n | 'created'\n | 'session_started'\n | 'rejected'\n | 'missed'\n | 'accepted'\n | 'ended'\n | 'unknown';\n\n/**\n * @typedef CallType\n * @description Represents the pre-defined types of a call.\n * - `default`: Simple 1-1 or group video calling with sensible defaults. Video/audio enabled, backstage disabled. Admins/hosts have elevated permissions.\n * - `audio_room`: For audio-only spaces (like Clubhouse). Backstage enabled (requires `goLive`), pre-configured permissions for requesting to speak.\n * - `livestream`: For one-to-many streaming. Backstage enabled (requires `goLive`), access granted to all authenticated users.\n * - `development`: For testing ONLY. All permissions enabled, backstage disabled. **Not recommended for production.**\n */\nexport type CallType = 'default' | 'audio_room' | 'livestream' | 'development';\n\n/**\n * @interface CallMember\n * @description Information about a call member/participant\n * @property {string} userId - User ID of the member\n * @property {string} [name] - Display name of the user\n * @property {string} [imageURL] - Profile image URL of the user\n * @property {string} [role] - Role of the user in the call\n */\nexport interface CallMember {\n /** User ID of the member */\n userId: string;\n /** Display name of the user */\n name?: string;\n /** Profile image URL of the user */\n imageURL?: string;\n /** Role of the user in the call */\n role?: string;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {CallState} state - Current state of the call\n * @property {string} [userId] - User ID of the participant who triggered the event\n * @property {string} [reason] - Reason for the call state change\n * @property {CallMember} [caller] - Information about the caller (for incoming calls)\n * @property {CallMember[]} [members] - List of call members\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: CallState;\n /** User ID of the participant in the call who triggered the event */\n userId?: string;\n /** Reason for the call state change, if applicable */\n reason?: string;\n /** Information about the caller (for incoming calls) */\n caller?: CallMember;\n /** List of call members */\n members?: CallMember[];\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string[]} userIds - IDs of the users to call\n * @property {CallType} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n * @property {string} [team] - Team name to call\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: CallType;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n /** Team name to call */\n team?: string;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Listen for lock-screen incoming call (Android only).\n * Fired when the app is shown by full-screen intent before user interaction.\n */\n addListener(\n eventName: 'incomingCall',\n listenerFunc: (event: IncomingCallPayload) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n\n /**\n * Check if camera is enabled\n * @returns {Promise<CameraEnabledResponse>} Camera enabled status\n * @example\n * const isCameraEnabled = await StreamCall.isCameraEnabled();\n * console.log(isCameraEnabled);\n */\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n\n /**\n * Get the current call status\n * @returns {Promise<CallEvent>} Current call status as a CallEvent\n * @example\n * const callStatus = await StreamCall.getCallStatus();\n * console.log(callStatus);\n */\n getCallStatus(): Promise<CallEvent>;\n\n /**\n * Set speakerphone on\n * @param {{ name: string }} options - Speakerphone name\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setSpeaker({ name: 'speaker' });\n */\n setSpeaker(options: { name: string }): Promise<SuccessResponse>;\n\n /**\n * Switch camera\n * @param {{ camera: 'front' | 'back' }} options - Camera to switch to\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.switchCamera({ camera: 'back' });\n */\n switchCamera(options: { camera: 'front' | 'back' }): Promise<SuccessResponse>;\n\n /**\n * Get detailed information about an active call including caller details\n * @param options - Options containing the call ID\n */\n getCallInfo(options: { callId: string }): Promise<CallEvent>;\n}\n\n/**\n * @interface IncomingCallPayload\n * @description Payload delivered with \"incomingCall\" event (Android lock-screen).\n * @property {string} cid - Call CID (type:id)\n * @property {string} type - Always \"incoming\" for this event\n * @property {CallMember} [caller] - Information about the caller\n */\nexport interface IncomingCallPayload {\n /** Full call CID (e.g. default:123) */\n cid: string;\n /** Event type (currently always \"incoming\") */\n type: 'incoming';\n /** Information about the caller */\n caller?: CallMember;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * @interface LoginOptions\n * @description Configuration options for logging into the Stream Video service\n * @property {string} token - Stream Video API token for authentication\n * @property {string} userId - Unique identifier for the current user\n * @property {string} name - Display name for the current user\n * @property {string} [imageURL] - Avatar URL for the current user\n * @property {string} apiKey - Stream Video API key for your application\n * @property {string} [magicDivId] - DOM element ID where video will be rendered\n */\nexport interface LoginOptions {\n /** Stream Video API token */\n token: string;\n /** User ID for the current user */\n userId: string;\n /** Display name for the current user */\n name: string;\n /** Optional avatar URL for the current user */\n imageURL?: string;\n /** Stream Video API key */\n apiKey: string;\n /** ID of the HTML element where the video will be rendered */\n magicDivId?: string;\n pushNotificationsConfig?: PushNotificationsConfig;\n}\n\nexport interface PushNotificationsConfig {\n pushProviderName: string;\n voipProviderName: string;\n}\n\n/**\n * @typedef CallState\n * @description Represents all possible call states from API and UI\n */\nexport type CallState =\n // User-facing states\n | 'idle'\n | 'ringing'\n | 'joining'\n | 'reconnecting'\n | 'joined'\n | 'leaving'\n | 'left'\n // Event-specific states\n | 'created'\n | 'session_started'\n | 'rejected'\n | 'missed'\n | 'accepted'\n | 'ended'\n | 'unknown';\n\n/**\n * @typedef CallType\n * @description Represents the pre-defined types of a call.\n * - `default`: Simple 1-1 or group video calling with sensible defaults. Video/audio enabled, backstage disabled. Admins/hosts have elevated permissions.\n * - `audio_room`: For audio-only spaces (like Clubhouse). Backstage enabled (requires `goLive`), pre-configured permissions for requesting to speak.\n * - `livestream`: For one-to-many streaming. Backstage enabled (requires `goLive`), access granted to all authenticated users.\n * - `development`: For testing ONLY. All permissions enabled, backstage disabled. **Not recommended for production.**\n */\nexport type CallType = 'default' | 'audio_room' | 'livestream' | 'development';\n\n/**\n * @interface CallMember\n * @description Information about a call member/participant\n * @property {string} userId - User ID of the member\n * @property {string} [name] - Display name of the user\n * @property {string} [imageURL] - Profile image URL of the user\n * @property {string} [role] - Role of the user in the call\n */\nexport interface CallMember {\n /** User ID of the member */\n userId: string;\n /** Display name of the user */\n name?: string;\n /** Profile image URL of the user */\n imageURL?: string;\n /** Role of the user in the call */\n role?: string;\n}\n\n/**\n * @interface CallEvent\n * @description Event emitted when call state changes\n * @property {string} callId - Unique identifier of the call\n * @property {CallState} state - Current state of the call\n * @property {string} [userId] - User ID of the participant who triggered the event\n * @property {string} [reason] - Reason for the call state change\n * @property {CallMember} [caller] - Information about the caller (for incoming calls)\n * @property {CallMember[]} [members] - List of call members\n */\nexport interface CallEvent {\n /** ID of the call */\n callId: string;\n /** Current state of the call */\n state: CallState;\n /** User ID of the participant in the call who triggered the event */\n userId?: string;\n /** Reason for the call state change, if applicable */\n reason?: string;\n /** Information about the caller (for incoming calls) */\n caller?: CallMember;\n /** List of call members */\n members?: CallMember[];\n}\n\nexport interface CameraEnabledResponse {\n enabled: boolean;\n}\n\n/**\n * @interface SuccessResponse\n * @description Standard response indicating operation success/failure\n * @property {boolean} success - Whether the operation succeeded\n */\nexport interface SuccessResponse {\n /** Whether the operation was successful */\n success: boolean;\n}\n\n/**\n * @interface CallOptions\n * @description Options for initiating a video call\n * @property {string[]} userIds - IDs of the users to call\n * @property {CallType} [type=default] - Type of call\n * @property {boolean} [ring=true] - Whether to send ring notification\n * @property {string} [team] - Team name to call\n */\nexport interface CallOptions {\n /** User ID of the person to call */\n userIds: string[];\n /** Type of call, defaults to 'default' */\n type?: CallType;\n /** Whether to ring the other user, defaults to true */\n ring?: boolean;\n /** Team name to call */\n team?: string;\n /** Whether to start the call with video enabled, defaults to false */\n video?: boolean;\n}\n\n/**\n * @interface StreamCallPlugin\n * @description Capacitor plugin for Stream Video calling functionality\n */\nexport interface StreamCallPlugin {\n /**\n * Login to Stream Video service\n * @param {LoginOptions} options - Login configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.login({\n * token: 'your-token',\n * userId: 'user-123',\n * name: 'John Doe',\n * apiKey: 'your-api-key'\n * });\n */\n login(options: LoginOptions): Promise<SuccessResponse>;\n\n /**\n * Logout from Stream Video service\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.logout();\n */\n logout(): Promise<SuccessResponse>;\n\n /**\n * Initiate a call to another user\n * @param {CallOptions} options - Call configuration\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.call({\n * userId: 'user-456',\n * type: 'video',\n * ring: true\n * });\n */\n call(options: CallOptions): Promise<SuccessResponse>;\n\n /**\n * End the current call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.endCall();\n */\n endCall(): Promise<SuccessResponse>;\n\n /**\n * Enable or disable microphone\n * @param {{ enabled: boolean }} options - Microphone state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setMicrophoneEnabled({ enabled: false });\n */\n setMicrophoneEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Enable or disable camera\n * @param {{ enabled: boolean }} options - Camera state\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setCameraEnabled({ enabled: false });\n */\n setCameraEnabled(options: { enabled: boolean }): Promise<SuccessResponse>;\n\n /**\n * Add listener for call events\n * @param {'callEvent'} eventName - Name of the event to listen for\n * @param {(event: CallEvent) => void} listenerFunc - Callback function\n * @returns {Promise<{ remove: () => Promise<void> }>} Function to remove listener\n * @example\n * const listener = await StreamCall.addListener('callEvent', (event) => {\n * console.log(`Call ${event.callId} is now ${event.state}`);\n * });\n */\n addListener(\n eventName: 'callEvent',\n listenerFunc: (event: CallEvent) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Listen for lock-screen incoming call (Android only).\n * Fired when the app is shown by full-screen intent before user interaction.\n */\n addListener(\n eventName: 'incomingCall',\n listenerFunc: (event: IncomingCallPayload) => void,\n ): Promise<{ remove: () => Promise<void> }>;\n\n /**\n * Remove all event listeners\n * @returns {Promise<void>}\n * @example\n * await StreamCall.removeAllListeners();\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Accept an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.acceptCall();\n */\n acceptCall(): Promise<SuccessResponse>;\n\n /**\n * Reject an incoming call\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.rejectCall();\n */\n rejectCall(): Promise<SuccessResponse>;\n\n /**\n * Check if camera is enabled\n * @returns {Promise<CameraEnabledResponse>} Camera enabled status\n * @example\n * const isCameraEnabled = await StreamCall.isCameraEnabled();\n * console.log(isCameraEnabled);\n */\n isCameraEnabled(): Promise<CameraEnabledResponse>;\n\n /**\n * Get the current call status\n * @returns {Promise<CallEvent>} Current call status as a CallEvent\n * @example\n * const callStatus = await StreamCall.getCallStatus();\n * console.log(callStatus);\n */\n getCallStatus(): Promise<CallEvent>;\n\n /**\n * Set speakerphone on\n * @param {{ name: string }} options - Speakerphone name\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.setSpeaker({ name: 'speaker' });\n */\n setSpeaker(options: { name: string }): Promise<SuccessResponse>;\n\n /**\n * Switch camera\n * @param {{ camera: 'front' | 'back' }} options - Camera to switch to\n * @returns {Promise<SuccessResponse>} Success status\n * @example\n * await StreamCall.switchCamera({ camera: 'back' });\n */\n switchCamera(options: { camera: 'front' | 'back' }): Promise<SuccessResponse>;\n\n /**\n * Get detailed information about an active call including caller details\n * @param options - Options containing the call ID\n */\n getCallInfo(options: { callId: string }): Promise<CallEvent>;\n}\n\n/**\n * @interface IncomingCallPayload\n * @description Payload delivered with \"incomingCall\" event (Android lock-screen).\n * @property {string} cid - Call CID (type:id)\n * @property {string} type - Always \"incoming\" for this event\n * @property {CallMember} [caller] - Information about the caller\n */\nexport interface IncomingCallPayload {\n /** Full call CID (e.g. default:123) */\n cid: string;\n /** Event type (currently always \"incoming\") */\n type: 'incoming';\n /** Information about the caller */\n caller?: CallMember;\n}\n"]}
|
package/dist/esm/web.js
CHANGED
|
@@ -21,18 +21,20 @@ export class StreamCallWeb extends WebPlugin {
|
|
|
21
21
|
role: event.call.created_by.role,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
-
if (!this.currentCall) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
// if (!this.currentCall) {
|
|
25
|
+
console.log('Creating new call', event.call.id);
|
|
26
|
+
this.currentCall = (_b = this.client) === null || _b === void 0 ? void 0 : _b.call(event.call.type, event.call.id);
|
|
27
|
+
// this.currentActiveCallId = this.currentCall?.cid;
|
|
28
|
+
setTimeout(() => {
|
|
28
29
|
this.notifyListeners('callEvent', {
|
|
29
30
|
callId: event.call.id,
|
|
30
31
|
state: CallingState.RINGING,
|
|
31
32
|
caller,
|
|
32
33
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
}, 100);
|
|
35
|
+
// Clear previous responses when a new call starts
|
|
36
|
+
this.participantResponses.clear();
|
|
37
|
+
// }
|
|
36
38
|
if (this.currentCall) {
|
|
37
39
|
console.log('Call found', this.currentCall.id);
|
|
38
40
|
this.callStateSubscription = (_c = this.currentCall) === null || _c === void 0 ? void 0 : _c.state.callingState$.subscribe((s) => {
|