From 341d8171a0d665250ad79137188107180b20fc78 Mon Sep 17 00:00:00 2001 From: Benoit Martins Date: Mon, 8 Jan 2024 13:32:18 +0100 Subject: [PATCH] Add video call, fullscreen mode and automatic video acceptance --- Linphone/Core/CoreContext.swift | 5 ++- Linphone/TelecomManager/TelecomManager.swift | 4 ++ Linphone/UI/Call/CallView.swift | 37 ++++++++++++++----- .../UI/Call/ViewModel/CallViewModel.swift | 33 ++++++++++++++--- .../Contacts/Model/ContactAvatarModel.swift | 2 - .../ViewModel/HistoryListViewModel.swift | 1 - 6 files changed, 63 insertions(+), 19 deletions(-) diff --git a/Linphone/Core/CoreContext.swift b/Linphone/Core/CoreContext.swift index e897b6027..98bdb7127 100644 --- a/Linphone/Core/CoreContext.swift +++ b/Linphone/Core/CoreContext.swift @@ -104,8 +104,11 @@ final class CoreContext: ObservableObject { self.mCore.videoCaptureEnabled = true self.mCore.videoDisplayEnabled = true + self.mCore.recordAwareEnabled = true - self.mCore.videoActivationPolicy!.automaticallyAccept = true + let videoActivationPolicy = self.mCore.videoActivationPolicy! + videoActivationPolicy.automaticallyAccept = true + self.mCore.videoActivationPolicy! = videoActivationPolicy try? self.mCore.start() diff --git a/Linphone/TelecomManager/TelecomManager.swift b/Linphone/TelecomManager/TelecomManager.swift index d21d7c525..855e70305 100644 --- a/Linphone/TelecomManager/TelecomManager.swift +++ b/Linphone/TelecomManager/TelecomManager.swift @@ -313,6 +313,10 @@ class TelecomManager: ObservableObject { } else { let video = (core.videoActivationPolicy?.automaticallyAccept ?? false) && (call.remoteParams?.videoEnabled ?? false) + if video { + Log.info("[Call] Remote video is activated") + } + if call.userData == nil { let appData = CallAppData() TelecomManager.setAppData(sCall: call, appData: appData) diff --git a/Linphone/UI/Call/CallView.swift b/Linphone/UI/Call/CallView.swift index 7c90468af..cd23af51e 100644 --- a/Linphone/UI/Call/CallView.swift +++ b/Linphone/UI/Call/CallView.swift @@ -49,8 +49,8 @@ struct CallView: View { var body: some View { GeometryReader { geo in if #available(iOS 16.4, *) { - innerView(geoHeight: geo.size.height, geoWidth: geo.size.width) - .sheet(isPresented: + innerView(geometry: geo) + .sheet(isPresented: .constant( telecomManager.callStarted && !fullscreenVideo @@ -424,8 +424,7 @@ struct CallView: View { } @ViewBuilder - func innerView(geoHeight: CGFloat, geoWidth: CGFloat) -> some View { - + func innerView(geometry: GeometryProxy) -> some View { VStack { if !fullscreenVideo { Rectangle() @@ -535,7 +534,16 @@ struct CallView: View { core.nativeVideoWindow = view } } - .frame(width: 120*5, height: 160*5) + .frame( + width: + angleDegree == 0 + ? 120 * ((geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom) / 160) + : 120 * ((geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) / 120), + height: + angleDegree == 0 + ? 160 * ((geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom) / 160) + : 160 * ((geometry.size.width + geometry.safeAreaInsets.leading + geometry.safeAreaInsets.trailing) / 120) + ) .scaledToFill() .clipped() .onTapGesture { @@ -552,14 +560,16 @@ struct CallView: View { core.nativePreviewWindow = view } } - .frame(width: 120*1.2, height: 160*1.2) + .frame(width: angleDegree == 0 ? 120*1.2 : 160*1.2, height: angleDegree == 0 ? 160*1.2 : 120*1.2) .cornerRadius(20) .padding(10) - .rotationEffect(Angle(degrees: angleDegree)) .padding(.trailing, abs(angleDegree/2)) } } - .frame(maxWidth: fullscreenVideo ? geoWidth : geoWidth - 8, maxHeight: fullscreenVideo ? geoHeight + 140 : geoHeight - 140) + .frame( + maxWidth: fullscreenVideo ? geometry.size.width : geometry.size.width - 8, + maxHeight: fullscreenVideo ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - 140 + ) } if !telecomManager.callStarted && !fullscreenVideo { @@ -581,7 +591,10 @@ struct CallView: View { .background(.clear) } } - .frame(maxWidth: fullscreenVideo ? geoWidth : geoWidth - 8, maxHeight: fullscreenVideo ? geoHeight + 140 : geoHeight - 140) + .frame( + maxWidth: fullscreenVideo ? geometry.size.width : geometry.size.width - 8, + maxHeight: fullscreenVideo ? geometry.size.height + geometry.safeAreaInsets.top + geometry.safeAreaInsets.bottom : geometry.size.height - 140 + ) .background(Color.gray600) .cornerRadius(20) .padding(.horizontal, fullscreenVideo ? 0 : 4) @@ -596,6 +609,8 @@ struct CallView: View { angleDegree = 90 } } + + callViewModel.orientationUpdate(orientation: orientation) } .onAppear { if orientation == .portrait && orientation == .portraitUpsideDown { @@ -607,6 +622,8 @@ struct CallView: View { angleDegree = 90 } } + + callViewModel.orientationUpdate(orientation: orientation) } if !fullscreenVideo { @@ -680,7 +697,7 @@ struct CallView: View { .background(Color.gray500) .cornerRadius(40) } - .frame(height: geoHeight * 0.15) + .frame(height: geometry.size.height * 0.15) .padding(.horizontal, 20) .padding(.top, -6) } diff --git a/Linphone/UI/Call/ViewModel/CallViewModel.swift b/Linphone/UI/Call/ViewModel/CallViewModel.swift index 3d18060b3..834b8874b 100644 --- a/Linphone/UI/Call/ViewModel/CallViewModel.swift +++ b/Linphone/UI/Call/ViewModel/CallViewModel.swift @@ -123,10 +123,10 @@ class CallViewModel: ObservableObject { do { let params = try core.createCallParams(call: self.currentCall) - params.videoEnabled = !params.videoEnabled - Log.info( - "[CallViewModel] Updating call with video enabled set to \(params.videoEnabled)" - ) + params.videoEnabled = !params.videoEnabled + Log.info( + "[CallViewModel] Updating call with video enabled set to \(params.videoEnabled)" + ) try self.currentCall!.update(params: params) self.cameraDisplayed = self.currentCall!.cameraEnabled == true @@ -141,7 +141,7 @@ class CallViewModel: ObservableObject { coreContext.doOnCoreQueue { core in let currentDevice = core.videoDevice Log.info("[CallViewModel] Current camera device is \(currentDevice)") - + core.videoDevicesList.forEach { camera in if camera != currentDevice && camera != "StaticImage: Static picture" { Log.info("[CallViewModel] New camera device will be \(camera)") @@ -237,4 +237,27 @@ class CallViewModel: ObservableObject { return 2 } } + + func orientationUpdate(orientation: UIDeviceOrientation) { + coreContext.doOnCoreQueue { core in + let oldLinphoneOrientation = core.deviceRotation + var newRotation = 0 + switch orientation { + case .portrait: + newRotation = 0 + case .portraitUpsideDown: + newRotation = 180 + case .landscapeRight: + newRotation = 90 + case .landscapeLeft: + newRotation = 270 + default: + newRotation = oldLinphoneOrientation + } + + if oldLinphoneOrientation != newRotation { + core.deviceRotation = newRotation + } + } + } } diff --git a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift index 28016921c..fb469c160 100644 --- a/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift +++ b/Linphone/UI/Main/Contacts/Model/ContactAvatarModel.swift @@ -65,8 +65,6 @@ class ContactAvatarModel: ObservableObject { func addSubscription() { friendSuscription = self.friend?.publisher?.onPresenceReceived?.postOnMainQueue { (cbValue: (Friend)) in - print("publisherpublisher onLogCollectionUploadStateChanged \(cbValue.address?.asStringUriOnly() ?? "")") - self.presenceStatus = cbValue.consolidatedPresence if cbValue.consolidatedPresence == .Online || cbValue.consolidatedPresence == .Busy { if cbValue.consolidatedPresence == .Online || cbValue.presenceModel!.latestActivityTimestamp != -1 { diff --git a/Linphone/UI/Main/History/ViewModel/HistoryListViewModel.swift b/Linphone/UI/Main/History/ViewModel/HistoryListViewModel.swift index d08ad626c..9bd9c0a05 100644 --- a/Linphone/UI/Main/History/ViewModel/HistoryListViewModel.swift +++ b/Linphone/UI/Main/History/ViewModel/HistoryListViewModel.swift @@ -49,7 +49,6 @@ class HistoryListViewModel: ObservableObject { } self.callLogSubscription = core.publisher?.onCallLogUpdated?.postOnCoreQueue { (_: (_: Core, _: CallLog)) in - print("publisherpublisher onCallLogUpdated") let account = core.defaultAccount let logs = account != nil ? account!.callLogs : core.callLogs