remove database access on call creation

pull/1061/head
Ryan ZHAO 3 weeks ago
parent 4e5f081b68
commit e5984601e8

@ -14,14 +14,18 @@ import SessionSnodeKit
public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
private let dependencies: Dependencies
public let webRTCSession: WebRTCSession
var currentConnectionStep: ConnectionStep
var connectionStepsRecord: [Bool]
// MARK: - Metadata Properties
public let uuid: String
public let callId: UUID // This is for CallKit
public let sessionId: String
let contactName: String
let mode: CallMode
var audioMode: AudioMode
public let webRTCSession: WebRTCSession
let isOutgoing: Bool
var remoteSDP: RTCSessionDescription? = nil {
didSet {
@ -30,16 +34,8 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
}
}
}
var callInteractionId: Int64?
var answerCallAction: CXAnswerCallAction? = nil
let contactName: String
let profilePicture: UIImage
let animatedProfilePicture: YYImage?
var currentConnectionStep: ConnectionStep
var connectionStepsRecord: [Bool]
// MARK: - Control
lazy public var videoCapturer: RTCVideoCapturer = {
@ -161,9 +157,10 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
// MARK: - Initialization
init(_ db: Database, for sessionId: String, uuid: String, mode: CallMode, outgoing: Bool = false, using dependencies: Dependencies) {
init(for sessionId: String, contactName: String, uuid: String, mode: CallMode, outgoing: Bool = false, using dependencies: Dependencies) {
self.dependencies = dependencies
self.sessionId = sessionId
self.contactName = contactName
self.uuid = uuid
self.callId = UUID()
self.mode = mode
@ -172,20 +169,6 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
self.isOutgoing = outgoing
self.currentConnectionStep = (mode == .offer ? OfferStep.initializing : AnswerStep.receivedOffer)
self.connectionStepsRecord = [Bool](repeating: false, count: (mode == .answer ? 5 : 6))
let avatarData: Data? = dependencies[singleton: .displayPictureManager].displayPicture(db, id: .user(sessionId))
self.contactName = Profile.displayName(db, id: sessionId, threadVariant: .contact, using: dependencies)
self.profilePicture = avatarData
.map { UIImage(data: $0) }
.defaulting(to: PlaceholderIcon.generate(seed: sessionId, text: self.contactName, size: 300))
self.animatedProfilePicture = avatarData
.map { data -> YYImage? in
switch data.guessedImageFormat {
case .gif, .webp: return YYImage(data: data)
default: return nil
}
}
WebRTCSession.current = self.webRTCSession
self.webRTCSession.delegate = self
@ -262,8 +245,6 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
)
.inserted(db)
self.callInteractionId = interaction?.id
self.updateCurrentConnectionStepIfPossible(OfferStep.initializing)
try? webRTCSession
@ -330,14 +311,16 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
// MARK: - Call Message Handling
public func updateCallMessage(mode: EndCallMode, using dependencies: Dependencies) {
guard let callInteractionId: Int64 = callInteractionId else { return }
let duration: TimeInterval = self.duration
let hasStartedConnecting: Bool = self.hasStartedConnecting
dependencies[singleton: .storage].writeAsync(
updates: { db in
guard let interaction: Interaction = try? Interaction.fetchOne(db, id: callInteractionId) else {
updates: { [sessionId, uuid] db in
guard let interaction: Interaction = try? Interaction
.filter(Interaction.Columns.threadId == sessionId)
.filter(Interaction.Columns.messageUuid == uuid)
.fetchOne(db)
else {
return
}

@ -202,11 +202,21 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
public func showCallUIForCall(caller: String, uuid: String, mode: CallMode, interactionId: Int64?) {
guard
let call: SessionCall = dependencies[singleton: .storage].read({ [dependencies] db in
SessionCall(db, for: caller, uuid: uuid, mode: mode, using: dependencies)
SessionCall(
for: caller,
contactName: Profile.displayName(
db,
id: caller,
threadVariant: .contact,
using: dependencies
),
uuid: uuid,
mode: mode,
using: dependencies
)
})
else { return }
call.callInteractionId = interactionId
call.reportIncomingCallIfNeeded { [dependencies] error in
if let error = error {
Log.error(.calls, "Failed to report incoming call to CallKit due to error: \(error)")

@ -130,9 +130,8 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
return result
}()
private lazy var profilePictureView: UIImageView = {
public lazy var profilePictureView: UIImageView = {
let result = UIImageView()
result.image = self.call.profilePicture
result.set(.width, to: CallVC.avatarRadius * 2)
result.set(.height, to: CallVC.avatarRadius * 2)
result.layer.cornerRadius = CallVC.avatarRadius
@ -144,13 +143,11 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
private lazy var animatedImageView: YYAnimatedImageView = {
let result: YYAnimatedImageView = YYAnimatedImageView()
result.image = self.call.animatedProfilePicture
result.set(.width, to: CallVC.avatarRadius * 2)
result.set(.height, to: CallVC.avatarRadius * 2)
result.layer.cornerRadius = CallVC.avatarRadius
result.layer.masksToBounds = true
result.contentMode = .scaleAspectFill
result.isHidden = (self.call.animatedProfilePicture == nil)
return result
}()
@ -382,12 +379,12 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
super.init(nibName: nil, bundle: nil)
setupStateChangeCallbacks()
setUpStateChangeCallbacks()
self.modalPresentationStyle = .overFullScreen
self.modalTransitionStyle = .crossDissolve
}
func setupStateChangeCallbacks() {
func setUpStateChangeCallbacks() {
self.call.remoteVideoStateDidChange = { isEnabled in
DispatchQueue.main.async {
UIView.animate(withDuration: 0.25) {
@ -475,6 +472,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
view.themeBackgroundColor = .backgroundPrimary
setUpViewHierarchy()
setUpProfilePictureImage()
if shouldRestartCamera { cameraManager.prepare() }
@ -492,7 +490,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
}
}
}
setupOrientationMonitoring()
setUpOrientationMonitoring()
NotificationCenter.default.addObserver(self, selector: #selector(audioRouteDidChange), name: AVAudioSession.routeChangeNotification, object: nil)
}
@ -569,6 +567,33 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
callDurationLabel.center(in: callInfoLabelContainer)
}
func setUpProfilePictureImage() {
let avatarData: Data? = dependencies[singleton: .storage].read { [call, dependencies] db in
dependencies[singleton: .displayPictureManager].displayPicture(db, id: .user(call.sessionId))
}
self.profilePictureView.image = avatarData
.map { UIImage(data: $0) }
.defaulting(to: PlaceholderIcon.generate(seed: call.sessionId, text: call.contactName, size: 300))
let maybeAnimatedProfilePicture = avatarData
.map { data -> YYImage? in
switch data.guessedImageFormat {
case .gif, .webp: return YYImage(data: data)
default: return nil
}
}
if let animatedProfilePicture = maybeAnimatedProfilePicture {
self.animatedImageView.image = animatedProfilePicture
self.animatedImageView.isHidden = false
self.profilePictureView.isHidden = true
} else {
self.animatedImageView.isHidden = true
self.profilePictureView.isHidden = false
}
}
private func addFloatingVideoView() {
guard let window: UIWindow = dependencies[singleton: .appContext].mainWindow else { return }
@ -598,7 +623,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate, AVRoutePickerViewDel
// MARK: - Orientation
private func setupOrientationMonitoring() {
private func setUpOrientationMonitoring() {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(didChangeDeviceOrientation), name: UIDevice.orientationDidChangeNotification, object: UIDevice.current)
}

@ -135,7 +135,7 @@ final class MiniCallView: UIView, RTCVideoViewDelegate {
imageView.clipsToBounds = true
imageView.layer.cornerRadius = 32
imageView.contentMode = .scaleAspectFill
imageView.image = callVC.call.profilePicture
imageView.image = callVC.profilePictureView.image
result.addSubview(imageView)
imageView.set(.width, to: 64)
imageView.set(.height, to: 64)
@ -196,7 +196,7 @@ final class MiniCallView: UIView, RTCVideoViewDelegate {
self?.callVC.call.removeRemoteVideoRenderer(remoteVideoView)
}
self?.callVC.setupStateChangeCallbacks()
self?.callVC.setUpStateChangeCallbacks()
MiniCallView.current = nil
self?.removeFromSuperview()
})

@ -182,8 +182,8 @@ extension ConversationVC:
let call: SessionCall = viewModel.dependencies[singleton: .storage]
.read({ [dependencies = viewModel.dependencies] db in
SessionCall(
db,
for: threadId,
contactName: self.viewModel.threadData.displayName,
uuid: UUID().uuidString.lowercased(),
mode: .offer,
outgoing: true,

@ -273,6 +273,7 @@ public class PushRegistrationManager: NSObject, PKPushRegistryDelegate {
let uuid: String = payload["uuid"] as? String,
let caller: String = payload["caller"] as? String,
let timestampMs: UInt64 = payload["timestamp"] as? UInt64,
let contactName: String = payload["contactName"] as? String,
TimestampUtils.isWithinOneMinute(timestampMs: timestampMs)
else {
dependencies[singleton: .callManager].reportFakeCall(info: "Missing payload data") // stringlint:ignore
@ -282,35 +283,15 @@ public class PushRegistrationManager: NSObject, PKPushRegistryDelegate {
dependencies[singleton: .storage].resumeDatabaseAccess()
dependencies.mutate(cache: .libSessionNetwork) { $0.resumeNetworkAccess() }
let maybeCall: SessionCall? = dependencies[singleton: .storage].write { [dependencies] db -> SessionCall? in
do {
let call: SessionCall = SessionCall(
db,
for: caller,
uuid: uuid,
mode: .answer,
using: dependencies
)
let interaction: Interaction? = try Interaction
.filter(Interaction.Columns.threadId == caller)
.filter(Interaction.Columns.messageUuid == uuid)
.fetchOne(db)
call.callInteractionId = interaction?.id
return call
}
catch {
Log.error(.calls, "Failed to create call due to error: \(error)")
}
return nil
}
let call: SessionCall = SessionCall(
for: caller,
contactName: contactName,
uuid: uuid,
mode: .answer,
using: dependencies
)
guard let call: SessionCall = maybeCall else {
dependencies[singleton: .callManager].reportFakeCall(info: "Could not retrieve call from database") // stringlint:ignore
return
}
Log.info(.calls, "Calls created with UUID: \(uuid), caller: \(caller), contactName: \(contactName)")
dependencies[singleton: .jobRunner].appDidBecomeActive()

@ -487,13 +487,20 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
) {
if Preferences.isCallKitSupported {
guard let caller: String = callMessage.sender, let timestamp = callMessage.sentTimestampMs else { return }
let contactName: String = Profile.displayName(
db,
id: caller,
threadVariant: .contact,
using: dependencies
)
let reportCall: () -> () = { [weak self, dependencies] in
// stringlint:ignore_start
let payload: [String: Any] = [
"uuid": callMessage.uuid,
"caller": caller,
"timestamp": timestamp
"timestamp": timestamp,
"contactName": contactName
]
// stringlint:ignore_stop

Loading…
Cancel
Save