@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.
@@ -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 androidx.compose.runtime.collectAsState
53
+ import io.getstream.video.android.core.Call
62
54
  import io.getstream.video.android.core.CameraDirection
63
- import android.content.BroadcastReceiver
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
- //, loggingLevel = LoggingLevel(priority = Priority.VERBOSE)
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
- ringtonePlayer?.stopRinging()
1599
- // No dedicated incoming-call native view anymore; UI handled by web layer
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
- 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;
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
- // Clear previous responses when a new call starts
34
- this.participantResponses.clear();
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) => {