@capgo/capacitor-stream-call 0.0.6 → 0.0.18

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.
@@ -23,9 +23,10 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
23
23
  CAPPluginMethod(name: "setMicrophoneEnabled", returnType: CAPPluginReturnPromise),
24
24
  CAPPluginMethod(name: "setCameraEnabled", returnType: CAPPluginReturnPromise),
25
25
  CAPPluginMethod(name: "acceptCall", returnType: CAPPluginReturnPromise),
26
- CAPPluginMethod(name: "isCameraEnabled", returnType: CAPPluginReturnPromise)
26
+ CAPPluginMethod(name: "isCameraEnabled", returnType: CAPPluginReturnPromise),
27
+ CAPPluginMethod(name: "getCallStatus", returnType: CAPPluginReturnPromise)
27
28
  ]
28
-
29
+
29
30
  private enum State {
30
31
  case notInitialized
31
32
  case initializing
@@ -37,7 +38,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
37
38
  private static let tokenRefreshSemaphore = DispatchSemaphore(value: 1)
38
39
  private var currentToken: String?
39
40
  private var tokenWaitSemaphore: DispatchSemaphore?
40
-
41
+
41
42
  private var overlayView: UIView?
42
43
  private var hostingController: UIHostingController<CallOverlayView>?
43
44
  private var overlayViewModel: CallOverlayViewModel?
@@ -45,19 +46,47 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
45
46
  private var activeCallSubscription: AnyCancellable?
46
47
  private var lastVoIPToken: String?
47
48
  private var touchInterceptView: TouchInterceptView?
48
-
49
+
49
50
  private var streamVideo: StreamVideo?
50
-
51
+
51
52
  // Track the current active call ID
52
53
  private var currentActiveCallId: String?
53
-
54
+
55
+ // Store current call info for getCallStatus
56
+ private var currentCallId: String = ""
57
+ private var currentCallState: String = ""
58
+
54
59
  @Injected(\.callKitAdapter) var callKitAdapter
55
60
  @Injected(\.callKitPushNotificationAdapter) var callKitPushNotificationAdapter
56
61
  private var webviewDelegate: WebviewNavigationDelegate?
57
-
62
+
58
63
  // Add class property to store call states
59
64
  private var callStates: [String: (members: [MemberResponse], participantResponses: [String: String], createdAt: Date, timer: Timer?)] = [:]
60
-
65
+
66
+ // Helper method to update call status and notify listeners
67
+ private func updateCallStatusAndNotify(callId: String, state: String, userId: String? = nil, reason: String? = nil) {
68
+ // Update stored call info
69
+ currentCallId = callId
70
+ currentCallState = state
71
+
72
+ // Create data dictionary with only the fields in the CallEvent interface
73
+ var data: [String: Any] = [
74
+ "callId": callId,
75
+ "state": state
76
+ ]
77
+
78
+ if let userId = userId {
79
+ data["userId"] = userId
80
+ }
81
+
82
+ if let reason = reason {
83
+ data["reason"] = reason
84
+ }
85
+
86
+ // Notify listeners
87
+ notifyListeners("callEvent", data: data)
88
+ }
89
+
61
90
  override public func load() {
62
91
  // Read API key from Info.plist
63
92
  if let apiKey = Bundle.main.object(forInfoDictionaryKey: "CAPACITOR_STREAM_VIDEO_APIKEY") as? String {
@@ -66,7 +95,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
66
95
  if self.apiKey == nil {
67
96
  fatalError("Cannot get apikey")
68
97
  }
69
-
98
+
70
99
  // Check if we have a logged in user for handling incoming calls
71
100
  if let credentials = SecureUserRepository.shared.loadCurrentUser() {
72
101
  print("Loading user for StreamCallPlugin: \(credentials.user.name)")
@@ -74,21 +103,21 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
74
103
  self.initializeStreamVideo()
75
104
  }
76
105
  }
77
-
106
+
78
107
  // Create and set the navigation delegate
79
108
  self.webviewDelegate = WebviewNavigationDelegate(
80
109
  wrappedDelegate: self.webView?.navigationDelegate,
81
110
  onSetupOverlay: { [weak self] in
82
111
  guard let self = self else { return }
83
112
  print("Attempting to setup call view")
84
-
113
+
85
114
  self.setupViews()
86
115
  }
87
116
  )
88
-
117
+
89
118
  self.webView?.navigationDelegate = self.webviewDelegate
90
119
  }
91
-
120
+
92
121
  // private func cleanupStreamVideo() {
93
122
  // // Cancel subscriptions
94
123
  // tokenSubscription?.cancel()
@@ -114,7 +143,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
114
143
  //
115
144
  // state = .notInitialized
116
145
  // }
117
-
146
+
118
147
  private func requireInitialized() throws {
119
148
  guard state == .initialized else {
120
149
  throw NSError(domain: "StreamCallPlugin", code: -1, userInfo: [NSLocalizedDescriptionKey: "StreamVideo not initialized"])
@@ -125,17 +154,17 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
125
154
  call.reject("Missing token parameter")
126
155
  return
127
156
  }
128
-
157
+
129
158
  print("loginMagicToken received token")
130
159
  currentToken = token
131
160
  tokenWaitSemaphore?.signal()
132
161
  call.resolve()
133
162
  }
134
-
163
+
135
164
  private func setupTokenSubscription() {
136
165
  // Cancel existing subscription if any
137
166
  tokenSubscription?.cancel()
138
-
167
+
139
168
  // Create new subscription
140
169
  tokenSubscription = callKitPushNotificationAdapter.$deviceToken.sink { [weak self] (updatedDeviceToken: String) in
141
170
  guard let self = self else { return }
@@ -161,26 +190,23 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
161
190
  }
162
191
  }
163
192
  }
164
-
193
+
165
194
  private func setupActiveCallSubscription() {
166
195
  if let streamVideo = streamVideo {
167
196
  Task {
168
197
  for await event in streamVideo.subscribe() {
169
198
  // print("Event", event)
170
199
  if let ringingEvent = event.rawValue as? CallRingEvent {
171
- notifyListeners("callEvent", data: [
172
- "callId": ringingEvent.callCid,
173
- "state": "ringing"
174
- ])
200
+ updateCallStatusAndNotify(callId: ringingEvent.callCid, state: "ringing")
175
201
  continue
176
202
  }
177
-
203
+
178
204
  if let callCreatedEvent = event.rawValue as? CallCreatedEvent {
179
205
  print("CallCreatedEvent \(String(describing: userId))")
180
-
206
+
181
207
  let callCid = callCreatedEvent.callCid
182
208
  let members = callCreatedEvent.members
183
-
209
+
184
210
  // Create timer on main thread
185
211
  await MainActor.run {
186
212
  // Store in the combined callStates map
@@ -190,20 +216,22 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
190
216
  createdAt: Date(),
191
217
  timer: nil
192
218
  )
193
-
219
+
194
220
  // Start timer to check for timeout every second
195
221
  // Use @objc method as timer target to avoid sendable closure issues
196
222
  let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.checkCallTimeoutTimer(_:)), userInfo: callCid, repeats: true)
197
-
223
+
198
224
  // Update timer in callStates
199
225
  self.callStates[callCid]?.timer = timer
200
226
  }
227
+
228
+ updateCallStatusAndNotify(callId: callCid, state: "created")
201
229
  }
202
-
230
+
203
231
  if let rejectedEvent = event.rawValue as? CallRejectedEvent {
204
232
  let userId = rejectedEvent.user.id
205
233
  let callCid = rejectedEvent.callCid
206
-
234
+
207
235
  // Operate on callStates on the main thread
208
236
  await MainActor.run {
209
237
  // Update the combined callStates map
@@ -212,22 +240,18 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
212
240
  self.callStates[callCid] = callState
213
241
  }
214
242
  }
215
-
243
+
216
244
  print("CallRejectedEvent \(userId)")
217
- notifyListeners("callEvent", data: [
218
- "callId": callCid,
219
- "state": "rejected",
220
- "userId": userId
221
- ])
222
-
245
+ updateCallStatusAndNotify(callId: callCid, state: "rejected", userId: userId)
246
+
223
247
  await checkAllParticipantsResponded(callCid: callCid)
224
248
  continue
225
249
  }
226
-
250
+
227
251
  if let missedEvent = event.rawValue as? CallMissedEvent {
228
252
  let userId = missedEvent.user.id
229
253
  let callCid = missedEvent.callCid
230
-
254
+
231
255
  // Operate on callStates on the main thread
232
256
  await MainActor.run {
233
257
  // Update the combined callStates map
@@ -236,34 +260,29 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
236
260
  self.callStates[callCid] = callState
237
261
  }
238
262
  }
239
-
263
+
240
264
  print("CallMissedEvent \(userId)")
241
- notifyListeners("callEvent", data: [
242
- "callId": callCid,
243
- "state": "missed",
244
- "userId": userId
245
- ])
246
-
265
+ updateCallStatusAndNotify(callId: callCid, state: "missed", userId: userId)
266
+
247
267
  await checkAllParticipantsResponded(callCid: callCid)
248
268
  continue
249
269
  }
250
-
270
+
251
271
  if let participantLeftEvent = event.rawValue as? CallSessionParticipantLeftEvent {
252
272
  let callIdSplit = participantLeftEvent.callCid.split(separator: ":")
253
- if (callIdSplit.count != 2) {
273
+ if callIdSplit.count != 2 {
254
274
  print("CallSessionParticipantLeftEvent invalid cID \(participantLeftEvent.callCid)")
255
275
  continue
256
276
  }
257
-
277
+
258
278
  let callType = callIdSplit[0]
259
279
  let callId = callIdSplit[1]
260
-
280
+
261
281
  let call = streamVideo.call(callType: String(callType), callId: String(callId))
262
282
  if await MainActor.run(body: { (call.state.session?.participants.count ?? 1) - 1 <= 1 }) {
263
-
264
-
283
+
265
284
  print("We are left solo in a call. Ending. cID: \(participantLeftEvent.callCid)")
266
-
285
+
267
286
  Task {
268
287
  if let activeCall = streamVideo.state.activeCall {
269
288
  activeCall.leave()
@@ -271,38 +290,31 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
271
290
  }
272
291
  }
273
292
  }
274
-
293
+
275
294
  if let acceptedEvent = event.rawValue as? CallAcceptedEvent {
276
295
  let userId = acceptedEvent.user.id
277
296
  let callCid = acceptedEvent.callCid
278
-
297
+
279
298
  // Operate on callStates on the main thread
280
299
  await MainActor.run {
281
300
  // Update the combined callStates map
282
301
  if var callState = self.callStates[callCid] {
283
302
  callState.participantResponses[userId] = "accepted"
284
-
303
+
285
304
  // If someone accepted, invalidate the timer as we don't need to check anymore
286
305
  callState.timer?.invalidate()
287
306
  callState.timer = nil
288
-
307
+
289
308
  self.callStates[callCid] = callState
290
309
  }
291
310
  }
292
-
311
+
293
312
  print("CallAcceptedEvent \(userId)")
294
- notifyListeners("callEvent", data: [
295
- "callId": callCid,
296
- "state": "accepted",
297
- "userId": userId
298
- ])
313
+ updateCallStatusAndNotify(callId: callCid, state: "accepted", userId: userId)
299
314
  continue
300
315
  }
301
-
302
- notifyListeners("callEvent", data: [
303
- "callId": streamVideo.state.activeCall?.callId ?? "",
304
- "state": event.type
305
- ])
316
+
317
+ updateCallStatusAndNotify(callId: streamVideo.state.activeCall?.callId ?? "", state: event.type)
306
318
  }
307
319
  }
308
320
  }
@@ -311,60 +323,54 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
311
323
  // Create new subscription
312
324
  activeCallSubscription = streamVideo?.state.$activeCall.sink { [weak self] newState in
313
325
  guard let self = self else { return }
314
-
326
+
315
327
  Task { @MainActor in
316
328
  do {
317
329
  try self.requireInitialized()
318
330
  print("Call State Update:")
319
331
  print("- Call is nil: \(newState == nil)")
320
-
332
+
321
333
  if let state = newState?.state {
322
334
  print("- state: \(state)")
323
335
  print("- Session ID: \(state.sessionId)")
324
336
  print("- All participants: \(String(describing: state.participants))")
325
337
  print("- Remote participants: \(String(describing: state.remoteParticipants))")
326
-
338
+
327
339
  // Store the active call ID when a call becomes active
328
340
  self.currentActiveCallId = newState?.cId
329
341
  print("Updated current active call ID: \(String(describing: self.currentActiveCallId))")
330
-
342
+
331
343
  // Update overlay and make visible when there's an active call
332
344
  self.overlayViewModel?.updateCall(newState)
333
345
  self.overlayView?.isHidden = false
334
346
  self.webView?.isOpaque = false
335
-
347
+
336
348
  // Notify that a call has started
337
- self.notifyListeners("callEvent", data: [
338
- "callId": newState?.cId ?? "",
339
- "state": "joined"
340
- ])
349
+ self.updateCallStatusAndNotify(callId: newState?.cId ?? "", state: "joined")
341
350
  } else {
342
351
  // Get the call ID that was active before the state changed to nil
343
352
  let endingCallId = self.currentActiveCallId
344
353
  print("Call ending: \(String(describing: endingCallId))")
345
-
354
+
346
355
  // If newState is nil, hide overlay and clear call
347
356
  self.overlayViewModel?.updateCall(nil)
348
357
  self.overlayView?.isHidden = true
349
358
  self.webView?.isOpaque = true
350
-
359
+
351
360
  // Notify that call has ended - use the properly tracked call ID
352
- self.notifyListeners("callEvent", data: [
353
- "callId": endingCallId ?? "",
354
- "state": "left"
355
- ])
356
-
361
+ self.updateCallStatusAndNotify(callId: endingCallId ?? "", state: "left")
362
+
357
363
  // Clean up any resources for this call
358
364
  if let callCid = endingCallId {
359
365
  // Invalidate and remove the timer
360
366
  self.callStates[callCid]?.timer?.invalidate()
361
-
367
+
362
368
  // Remove call from callStates
363
369
  self.callStates.removeValue(forKey: callCid)
364
-
370
+
365
371
  print("Cleaned up resources for ended call: \(callCid)")
366
372
  }
367
-
373
+
368
374
  // Clear the active call ID
369
375
  self.currentActiveCallId = nil
370
376
  }
@@ -374,45 +380,45 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
374
380
  }
375
381
  }
376
382
  }
377
-
383
+
378
384
  @objc private func checkCallTimeoutTimer(_ timer: Timer) {
379
385
  guard let callCid = timer.userInfo as? String else { return }
380
-
386
+
381
387
  Task { [weak self] in
382
388
  guard let self = self else { return }
383
389
  await self.checkCallTimeout(callCid: callCid)
384
390
  }
385
391
  }
386
-
392
+
387
393
  private func checkCallTimeout(callCid: String) async {
388
394
  // Get a local copy of the call state from the main thread
389
395
  let callState: (members: [MemberResponse], participantResponses: [String: String], createdAt: Date, timer: Timer?)? = await MainActor.run {
390
396
  return self.callStates[callCid]
391
397
  }
392
-
398
+
393
399
  guard let callState = callState else { return }
394
-
400
+
395
401
  // Calculate time elapsed since call creation
396
402
  let now = Date()
397
403
  let elapsedSeconds = now.timeIntervalSince(callState.createdAt)
398
-
404
+
399
405
  // Check if 30 seconds have passed
400
406
  if elapsedSeconds >= 30.0 {
401
407
 
402
408
  // Check if anyone has accepted
403
409
  let hasAccepted = callState.participantResponses.values.contains { $0 == "accepted" }
404
-
410
+
405
411
  if !hasAccepted {
406
412
  print("Call \(callCid) has timed out after \(elapsedSeconds) seconds")
407
413
  print("No one accepted call \(callCid), marking all non-responders as missed")
408
-
414
+
409
415
  // Mark all members who haven't responded as "missed"
410
416
  for member in callState.members {
411
417
  let memberId = member.userId
412
418
  let needsToBeMarkedAsMissed = await MainActor.run {
413
419
  return self.callStates[callCid]?.participantResponses[memberId] == nil
414
420
  }
415
-
421
+
416
422
  if needsToBeMarkedAsMissed {
417
423
  // Update callStates map on main thread
418
424
  await MainActor.run {
@@ -422,23 +428,19 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
422
428
  self.callStates[callCid] = updatedCallState
423
429
  }
424
430
  }
425
-
431
+
426
432
  // Notify listeners
427
433
  await MainActor.run {
428
- self.notifyListeners("callEvent", data: [
429
- "callId": callCid,
430
- "state": "missed",
431
- "userId": memberId
432
- ])
434
+ self.updateCallStatusAndNotify(callId: callCid, state: "missed", userId: memberId)
433
435
  }
434
436
  }
435
437
  }
436
-
438
+
437
439
  // End the call
438
440
  if let call = streamVideo?.state.activeCall, call.cId == callCid {
439
441
  call.leave()
440
442
  }
441
-
443
+
442
444
  // Clean up timer on main thread
443
445
  await MainActor.run {
444
446
  self.callStates[callCid]?.timer?.invalidate()
@@ -447,74 +449,66 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
447
449
  if let updatedCallState = updatedCallState {
448
450
  self.callStates[callCid] = updatedCallState
449
451
  }
450
-
452
+
451
453
  // Remove from callStates
452
454
  self.callStates.removeValue(forKey: callCid)
453
455
  }
454
-
456
+
455
457
  // Update UI
456
458
  await MainActor.run {
457
459
  self.overlayViewModel?.updateCall(nil)
458
460
  self.overlayView?.isHidden = true
459
461
  self.webView?.isOpaque = true
460
- self.notifyListeners("callEvent", data: [
461
- "callId": callCid,
462
- "state": "ended",
463
- "reason": "timeout"
464
- ])
462
+ self.updateCallStatusAndNotify(callId: callCid, state: "ended", reason: "timeout")
465
463
  }
466
464
  }
467
465
  }
468
466
  }
469
-
467
+
470
468
  private func checkAllParticipantsResponded(callCid: String) async {
471
469
  // Get a local copy of the call state from the main thread
472
470
  let callState: (members: [MemberResponse], participantResponses: [String: String], createdAt: Date, timer: Timer?)? = await MainActor.run {
473
471
  return self.callStates[callCid]
474
472
  }
475
-
473
+
476
474
  guard let callState = callState else {
477
475
  print("Call state not found for cId: \(callCid)")
478
476
  return
479
477
  }
480
-
478
+
481
479
  let totalParticipants = callState.members.count
482
480
  let responseCount = callState.participantResponses.count
483
-
481
+
484
482
  print("Total participants: \(totalParticipants), Responses: \(responseCount)")
485
-
483
+
486
484
  let allResponded = responseCount >= totalParticipants
487
- let allRejectedOrMissed = allResponded &&
485
+ let allRejectedOrMissed = allResponded &&
488
486
  callState.participantResponses.values.allSatisfy { $0 == "rejected" || $0 == "missed" }
489
-
487
+
490
488
  if allResponded && allRejectedOrMissed {
491
489
  print("All participants have rejected or missed the call")
492
-
493
- // End the call
490
+
491
+ // End the call
494
492
  if let call = streamVideo?.state.activeCall, call.cId == callCid {
495
493
  call.leave()
496
494
  }
497
-
495
+
498
496
  // Clean up timer and remove from callStates on main thread
499
497
  await MainActor.run {
500
498
  // Clean up timer
501
499
  self.callStates[callCid]?.timer?.invalidate()
502
-
500
+
503
501
  // Remove from callStates
504
502
  self.callStates.removeValue(forKey: callCid)
505
-
503
+
506
504
  self.overlayViewModel?.updateCall(nil)
507
505
  self.overlayView?.isHidden = true
508
506
  self.webView?.isOpaque = true
509
- self.notifyListeners("callEvent", data: [
510
- "callId": callCid,
511
- "state": "ended",
512
- "reason": "all_rejected_or_missed"
513
- ])
507
+ self.updateCallStatusAndNotify(callId: callCid, state: "ended", reason: "all_rejected_or_missed")
514
508
  }
515
509
  }
516
510
  }
517
-
511
+
518
512
  @objc func login(_ call: CAPPluginCall) {
519
513
  guard let token = call.getString("token"),
520
514
  let userId = call.getString("userId"),
@@ -522,7 +516,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
522
516
  call.reject("Missing required parameters")
523
517
  return
524
518
  }
525
-
519
+
526
520
  let imageURL = call.getString("imageURL")
527
521
  let user = User(
528
522
  id: userId,
@@ -530,31 +524,31 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
530
524
  imageURL: imageURL.flatMap { URL(string: $0) },
531
525
  customData: [:]
532
526
  )
533
-
527
+
534
528
  let credentials = UserCredentials(user: user, tokenValue: token)
535
529
  SecureUserRepository.shared.save(user: credentials)
536
530
  // Initialize Stream Video with new credentials
537
531
  initializeStreamVideo()
538
-
532
+
539
533
  if state != .initialized {
540
534
  call.reject("Failed to initialize StreamVideo")
541
535
  return
542
536
  }
543
-
537
+
544
538
  // Update the CallOverlayView with new StreamVideo instance
545
539
  Task { @MainActor in
546
540
  self.overlayViewModel?.updateStreamVideo(self.streamVideo)
547
541
  }
548
-
542
+
549
543
  call.resolve([
550
544
  "success": true
551
545
  ])
552
546
  }
553
-
547
+
554
548
  @objc func logout(_ call: CAPPluginCall) {
555
549
  // Remove VOIP token from repository
556
550
  SecureUserRepository.shared.save(voipPushToken: nil)
557
-
551
+
558
552
  // Try to delete the device from Stream if we have the last token
559
553
  if let lastVoIPToken = lastVoIPToken {
560
554
  Task {
@@ -565,16 +559,16 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
565
559
  }
566
560
  }
567
561
  }
568
-
562
+
569
563
  // Cancel subscriptions
570
564
  tokenSubscription?.cancel()
571
565
  tokenSubscription = nil
572
566
  activeCallSubscription?.cancel()
573
567
  activeCallSubscription = nil
574
568
  lastVoIPToken = nil
575
-
569
+
576
570
  SecureUserRepository.shared.removeCurrentUser()
577
-
571
+
578
572
  // Update the CallOverlayView with nil StreamVideo instance
579
573
  Task { @MainActor in
580
574
  self.overlayViewModel?.updateCall(nil)
@@ -582,19 +576,19 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
582
576
  self.overlayView?.isHidden = true
583
577
  self.webView?.isOpaque = true
584
578
  }
585
-
579
+
586
580
  call.resolve([
587
581
  "success": true
588
582
  ])
589
583
  }
590
-
584
+
591
585
  @objc func isCameraEnabled(_ call: CAPPluginCall) {
592
586
  do {
593
587
  try requireInitialized()
594
588
  } catch {
595
589
  call.reject("SDK not initialized")
596
590
  }
597
-
591
+
598
592
  if let activeCall = streamVideo?.state.activeCall {
599
593
  call.resolve([
600
594
  "enabled": activeCall.camera.status == .enabled
@@ -629,6 +623,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
629
623
 
630
624
  let callType = call.getString("type") ?? "default"
631
625
  let shouldRing = call.getBool("ring") ?? true
626
+ let team = call.getString("team")
632
627
 
633
628
  // Generate a unique call ID
634
629
  let callId = UUID().uuidString
@@ -640,6 +635,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
640
635
  print("- Call Type: \(callType)")
641
636
  print("- Users: \(members)")
642
637
  print("- Should Ring: \(shouldRing)")
638
+ print("- Team: \(team)")
643
639
 
644
640
  // Create the call object
645
641
  let streamCall = streamVideo?.call(callType: callType, callId: callId)
@@ -649,7 +645,7 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
649
645
  try await streamCall?.create(
650
646
  memberIds: members,
651
647
  custom: [:],
652
- ring: shouldRing
648
+ team: team, ring: shouldRing
653
649
  )
654
650
 
655
651
  // Join the call
@@ -900,4 +896,17 @@ public class StreamCallPlugin: CAPPlugin, CAPBridgedPlugin {
900
896
  ])
901
897
  }
902
898
  }
899
+
900
+ @objc func getCallStatus(_ call: CAPPluginCall) {
901
+ // Use stored state rather than accessing SDK state directly
902
+ if currentCallId.isEmpty || currentCallState == "left" {
903
+ call.reject("Not in a call")
904
+ return
905
+ }
906
+
907
+ call.resolve([
908
+ "callId": currentCallId,
909
+ "state": currentCallState
910
+ ])
911
+ }
903
912
  }