@stream-io/react-native-callingx 0.6.0 → 0.6.1
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/CHANGELOG.md +10 -0
- package/ios/CallingxImpl.swift +15 -31
- package/ios/UUIDStorage.swift +45 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [0.6.1](https://github.com/GetStream/stream-video-js/compare/@stream-io/react-native-callingx-0.6.0...@stream-io/react-native-callingx-0.6.1) (2026-07-02)
|
|
6
|
+
|
|
7
|
+
### Dependency Updates
|
|
8
|
+
|
|
9
|
+
- `@stream-io/typescript-config` updated to version `0.1.0`
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- made CXCallObserver static warm instance ([#2306](https://github.com/GetStream/stream-video-js/issues/2306)) ([ac79c64](https://github.com/GetStream/stream-video-js/commit/ac79c64f7231b12295e726f258e92c28b239d28b))
|
|
14
|
+
|
|
5
15
|
## [0.6.0](https://github.com/GetStream/stream-video-js/compare/@stream-io/react-native-callingx-0.5.1...@stream-io/react-native-callingx-0.6.0) (2026-06-26)
|
|
6
16
|
|
|
7
17
|
### Dependency Updates
|
package/ios/CallingxImpl.swift
CHANGED
|
@@ -208,26 +208,15 @@ import stream_react_native_webrtc
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
@objc public static func canRegisterCall() -> Bool {
|
|
211
|
-
let hasCall = hasRegisteredCall()
|
|
212
211
|
let shouldReject = Settings.getShouldRejectCallWhenBusy()
|
|
213
|
-
|
|
212
|
+
guard shouldReject else { return true }
|
|
213
|
+
return !hasRegisteredCall()
|
|
214
214
|
}
|
|
215
|
-
|
|
215
|
+
|
|
216
216
|
@objc public static func hasRegisteredCall() -> Bool {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if appUUIDs.isEmpty { return false }
|
|
221
|
-
|
|
222
|
-
let observer = CXCallObserver()
|
|
223
|
-
for call in observer.calls {
|
|
224
|
-
for uuid in appUUIDs {
|
|
225
|
-
if call.uuid == uuid {
|
|
226
|
-
return true
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return false
|
|
217
|
+
// Backed by the warm CXCallObserver maintained in UUIDStorage — no per-call observer
|
|
218
|
+
// construction and no cold-snapshot misses. Intersects our calls with CallKit's live set.
|
|
219
|
+
return uuidStorage?.hasRegisteredCall() ?? false
|
|
231
220
|
}
|
|
232
221
|
|
|
233
222
|
@objc public static func getAudioOutput() -> String? {
|
|
@@ -427,8 +416,12 @@ import stream_react_native_webrtc
|
|
|
427
416
|
|
|
428
417
|
// This is mostly needed for very first setup, as we need to override the default
|
|
429
418
|
// provider configuration which is set in the constructor.
|
|
430
|
-
// IMPORTANT: We override CXProvider instance only
|
|
431
|
-
|
|
419
|
+
// IMPORTANT: We override the CXProvider instance only when there are no calls in
|
|
420
|
+
// flight, otherwise we'd destroy CallKit state/events for a live call. We check our
|
|
421
|
+
// own storage rather than CXCallObserver here: the observer trails registration and
|
|
422
|
+
// can briefly report empty (e.g. a VoIP-push call reported just before setup runs),
|
|
423
|
+
// which would wrongly tear down the provider mid-call.
|
|
424
|
+
if (CallingxImpl.uuidStorage?.count() ?? 0) == 0 {
|
|
432
425
|
let oldProvider = CallingxImpl.sharedProvider
|
|
433
426
|
let newProvider = CXProvider(configuration: Settings.getProviderConfiguration())
|
|
434
427
|
newProvider.setDelegate(self, queue: nil)
|
|
@@ -581,18 +574,9 @@ import stream_react_native_webrtc
|
|
|
581
574
|
}
|
|
582
575
|
|
|
583
576
|
@objc public func isCallTracked(_ callId: String) -> Bool {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
let observer = CXCallObserver()
|
|
590
|
-
for call in observer.calls {
|
|
591
|
-
if call.uuid == uuid {
|
|
592
|
-
return true
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
return false
|
|
577
|
+
// Backed by the warm CXCallObserver in UUIDStorage — no per-call observer construction
|
|
578
|
+
// and no cold-snapshot misses. True when the call is tracked AND confirmed live by CallKit.
|
|
579
|
+
return CallingxImpl.uuidStorage?.isCallTracked(forCid: callId) ?? false
|
|
596
580
|
}
|
|
597
581
|
|
|
598
582
|
@objc public func setCurrentCallActive(_ callId: String) -> Bool {
|
package/ios/UUIDStorage.swift
CHANGED
|
@@ -1,14 +1,58 @@
|
|
|
1
1
|
import Foundation
|
|
2
|
+
import CallKit
|
|
2
3
|
|
|
3
|
-
@objcMembers public class UUIDStorage: NSObject {
|
|
4
|
+
@objcMembers public class UUIDStorage: NSObject, CXCallObserverDelegate {
|
|
4
5
|
/// Primary storage: cid -> CallingxCall
|
|
5
6
|
private var callsByCid: [String: CallingxCall] = [:]
|
|
6
7
|
/// Reverse lookup: lowercased UUID string -> CallingxCall
|
|
7
8
|
private var callsByUUID: [String: CallingxCall] = [:]
|
|
8
9
|
private let queue = DispatchQueue(label: "com.stream.uuidstorage", attributes: [])
|
|
9
10
|
|
|
11
|
+
/// Warm, long-lived observer of CallKit's call state — a cold observer can report empty even for a
|
|
12
|
+
/// call that's been live for a while.
|
|
13
|
+
private let callObserver = CXCallObserver()
|
|
14
|
+
/// CallKit's live view, maintained from observer callbacks. NOTE: contains UUIDs of ALL
|
|
15
|
+
/// system calls. Only ever intersect it with our own UUIDs — never treat it as "our calls".
|
|
16
|
+
private var liveCallKitUUIDs: Set<UUID> = []
|
|
17
|
+
|
|
10
18
|
public override init() {
|
|
11
19
|
super.init()
|
|
20
|
+
callObserver.setDelegate(self, queue: queue)
|
|
21
|
+
queue.async { [weak self] in
|
|
22
|
+
guard let self = self else { return }
|
|
23
|
+
self.liveCallKitUUIDs = Set(
|
|
24
|
+
self.callObserver.calls.filter { !$0.hasEnded }.map { $0.uuid }
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// MARK: - CXCallObserverDelegate
|
|
30
|
+
|
|
31
|
+
/// IMPORTANT: delivered on `queue`, NEVER call the `queue.sync` helpers below —
|
|
32
|
+
/// re-entering the serial queue would deadlock.
|
|
33
|
+
public func callObserver(_ callObserver: CXCallObserver, callChanged call: CXCall) {
|
|
34
|
+
if call.hasEnded {
|
|
35
|
+
liveCallKitUUIDs.remove(call.uuid)
|
|
36
|
+
} else {
|
|
37
|
+
liveCallKitUUIDs.insert(call.uuid)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// MARK: - CallKit liveness queries
|
|
42
|
+
|
|
43
|
+
public func hasRegisteredCall() -> Bool {
|
|
44
|
+
return queue.sync {
|
|
45
|
+
guard !callsByCid.isEmpty else { return false }
|
|
46
|
+
let ours = Set(callsByCid.values.map { $0.uuid })
|
|
47
|
+
return !ours.isDisjoint(with: liveCallKitUUIDs)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public func isCallTracked(forCid cid: String) -> Bool {
|
|
52
|
+
return queue.sync {
|
|
53
|
+
guard let call = callsByCid[cid] else { return false }
|
|
54
|
+
return liveCallKitUUIDs.contains(call.uuid)
|
|
55
|
+
}
|
|
12
56
|
}
|
|
13
57
|
|
|
14
58
|
// MARK: - CallingxCall-based API (new)
|
package/package.json
CHANGED