-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
Copy pathCallServiceState.swift
82 lines (64 loc) · 2.41 KB
/
CallServiceState.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import SignalServiceKit
protocol CallServiceStateObserver: AnyObject {
/// Fired on the main thread when the current call changes.
@MainActor
func didUpdateCall(from oldValue: SignalCall?, to newValue: SignalCall?)
}
protocol CallServiceStateDelegate: AnyObject {
@MainActor
func callServiceState(_ callServiceState: CallServiceState, didTerminateCall call: SignalCall)
}
class CallServiceState {
weak var delegate: CallServiceStateDelegate?
init(currentCall: AtomicValue<SignalCall?>) {
self._currentCall = currentCall
}
/// Current call *must* be set on the main thread. It may be read off the
/// main thread if the current call state must be consulted, but other call
/// state may race (observer state, sleep state, etc.)
private let _currentCall: AtomicValue<SignalCall?>
/// Represents the call currently occuring on this device.
var currentCall: SignalCall? { _currentCall.get() }
@MainActor
func setCurrentCall(_ currentCall: SignalCall?) {
let oldValue = _currentCall.swap(currentCall)
guard currentCall !== oldValue else {
return
}
for observer in self.observers.elements {
observer.didUpdateCall(from: oldValue, to: currentCall)
}
}
/**
* Clean up any existing call state and get ready to receive a new call.
*/
@MainActor
func terminateCall(_ call: SignalCall) {
Logger.info("call: \(call as Optional)")
// If call is for the current call, clear it out first.
if call === currentCall {
setCurrentCall(nil)
}
delegate?.callServiceState(self, didTerminateCall: call)
}
// MARK: - Observers
private var observers = WeakArray<any CallServiceStateObserver>()
@MainActor
func addObserver(_ observer: any CallServiceStateObserver, syncStateImmediately: Bool = false) {
observers.append(observer)
if syncStateImmediately {
// Synchronize observer with current call state
observer.didUpdateCall(from: nil, to: currentCall)
}
}
// The observer-related methods should be invoked on the main thread.
func removeObserver(_ observer: any CallServiceStateObserver) {
AssertIsOnMainThread()
observers.removeAll { $0 === observer }
}
}