forked from mirrors/linphone-iphone
Implement PiP for video calls
This commit is contained in:
parent
b3d83c1580
commit
511c6e4093
5 changed files with 180 additions and 6 deletions
|
|
@ -22,6 +22,7 @@
|
||||||
667E5D812B8E444E00EBCFC4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */; };
|
667E5D812B8E444E00EBCFC4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */; };
|
||||||
6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */; };
|
6691CA7E2B839C2D00B2A7B8 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */; };
|
||||||
66A3E5B72CAE8E5C00FCB7FA /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */; };
|
66A3E5B72CAE8E5C00FCB7FA /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = D70C93DD2AC2D0F60063CA3B /* Localizable.xcstrings */; };
|
||||||
|
66C468FB2D2BE54800A836F7 /* PIPViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C468FA2D2BE54300A836F7 /* PIPViewModel.swift */; };
|
||||||
66C491F92B24D25B00CEA16D /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; };
|
66C491F92B24D25B00CEA16D /* ConfigExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491F82B24D25A00CEA16D /* ConfigExtension.swift */; };
|
||||||
66C491FB2B24D32600CEA16D /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; };
|
66C491FB2B24D32600CEA16D /* CoreExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FA2B24D32600CEA16D /* CoreExtension.swift */; };
|
||||||
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */; };
|
66C491FD2B24D36500CEA16D /* AudioRouteUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */; };
|
||||||
|
|
@ -227,6 +228,7 @@
|
||||||
6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleMeetingFragment.swift; sourceTree = "<group>"; };
|
6646A7A22BB2E224006B842A /* ScheduleMeetingFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleMeetingFragment.swift; sourceTree = "<group>"; };
|
||||||
667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
667E5D802B8E444D00EBCFC4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
6691CA7D2B839C2D00B2A7B8 /* NotificationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||||
|
66C468FA2D2BE54300A836F7 /* PIPViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PIPViewModel.swift; sourceTree = "<group>"; };
|
||||||
66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = "<group>"; };
|
66C491F82B24D25A00CEA16D /* ConfigExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigExtension.swift; sourceTree = "<group>"; };
|
||||||
66C491FA2B24D32600CEA16D /* CoreExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreExtension.swift; sourceTree = "<group>"; };
|
66C491FA2B24D32600CEA16D /* CoreExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreExtension.swift; sourceTree = "<group>"; };
|
||||||
66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRouteUtils.swift; sourceTree = "<group>"; };
|
66C491FC2B24D36500CEA16D /* AudioRouteUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioRouteUtils.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -858,6 +860,7 @@
|
||||||
children = (
|
children = (
|
||||||
D7B99E982B29B39000BE7BF2 /* CallViewModel.swift */,
|
D7B99E982B29B39000BE7BF2 /* CallViewModel.swift */,
|
||||||
D734499A2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift */,
|
D734499A2BC694C900778C56 /* MeetingWaitingRoomViewModel.swift */,
|
||||||
|
66C468FA2D2BE54300A836F7 /* PIPViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModel;
|
path = ViewModel;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -1307,6 +1310,7 @@
|
||||||
D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */,
|
D72250692ADFBF2D008FB426 /* SideMenu.swift in Sources */,
|
||||||
C6DC4E3F2C19C289009096FD /* SideMenuEntry.swift in Sources */,
|
C6DC4E3F2C19C289009096FD /* SideMenuEntry.swift in Sources */,
|
||||||
D714DE622C1C4636006C1F1D /* RegisterCodeConfirmationFragment.swift in Sources */,
|
D714DE622C1C4636006C1F1D /* RegisterCodeConfirmationFragment.swift in Sources */,
|
||||||
|
66C468FB2D2BE54800A836F7 /* PIPViewModel.swift in Sources */,
|
||||||
D7CEE0352B7A210300FD79B7 /* ConversationsView.swift in Sources */,
|
D7CEE0352B7A210300FD79B7 /* ConversationsView.swift in Sources */,
|
||||||
D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */,
|
D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */,
|
||||||
D71968922B86369D00DF4459 /* ChatBubbleView.swift in Sources */,
|
D71968922B86369D00DF4459 /* ChatBubbleView.swift in Sources */,
|
||||||
|
|
@ -1557,8 +1561,11 @@
|
||||||
);
|
);
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = Linphone/Info.plist;
|
INFOPLIST_FILE = Linphone/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = Linphone;
|
||||||
|
INFOPLIST_KEY_NSCalendarsUsageDescription = "Deprecated - Prior to iOS 17 full calendar access is required";
|
||||||
INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
|
INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
|
||||||
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
|
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
|
||||||
|
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "App requires access to the local network to establish VoIP connections";
|
||||||
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
|
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
|
||||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
|
|
@ -1610,8 +1617,10 @@
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = Linphone/Info.plist;
|
INFOPLIST_FILE = Linphone/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Linphone;
|
INFOPLIST_KEY_CFBundleDisplayName = Linphone;
|
||||||
|
INFOPLIST_KEY_NSCalendarsUsageDescription = "Deprecated - Prior to iOS 17 full calendar access is required";
|
||||||
INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
|
INFOPLIST_KEY_NSCameraUsageDescription = "Camera usage is required for video VOIP calls";
|
||||||
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
|
INFOPLIST_KEY_NSContactsUsageDescription = "Make calls with your friends";
|
||||||
|
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "App requires access to the local network to establish VoIP connections";
|
||||||
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
|
INFOPLIST_KEY_NSMicrophoneUsageDescription = "Microphone usage is required for VOIP calls";
|
||||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
|
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Share photos with your friends and customize avatars";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ final class CoreContext: ObservableObject {
|
||||||
|
|
||||||
static let shared = CoreContext()
|
static let shared = CoreContext()
|
||||||
private var sharedMainViewModel = SharedMainViewModel.shared
|
private var sharedMainViewModel = SharedMainViewModel.shared
|
||||||
|
var pipViewModel = PIPViewModel()
|
||||||
|
|
||||||
var coreVersion: String = Core.getVersion
|
var coreVersion: String = Core.getVersion
|
||||||
@Published var loggedIn: Bool = false
|
@Published var loggedIn: Bool = false
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
|
||||||
<string>App requires access to the local network to establish VoIP connections</string>
|
|
||||||
<key>CFBundleURLTypes</key>
|
<key>CFBundleURLTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
|
|
@ -111,6 +109,8 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>ITSEncryptionExportComplianceCode</key>
|
<key>ITSEncryptionExportComplianceCode</key>
|
||||||
<string>b5cb085f-772a-4a4f-8c77-5d1332b1f93f</string>
|
<string>b5cb085f-772a-4a4f-8c77-5d1332b1f93f</string>
|
||||||
|
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
|
||||||
|
<string></string>
|
||||||
<key>NSSupportsSuddenTermination</key>
|
<key>NSSupportsSuddenTermination</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
|
|
@ -126,15 +126,12 @@
|
||||||
<array>
|
<array>
|
||||||
<string>remote-notification</string>
|
<string>remote-notification</string>
|
||||||
<string>voip</string>
|
<string>voip</string>
|
||||||
|
<string>audio</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UILaunchScreen</key>
|
<key>UILaunchScreen</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIImageName</key>
|
<key>UIImageName</key>
|
||||||
<string>linphone</string>
|
<string>linphone</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSCalendarsUsageDescription</key>
|
|
||||||
<string>Deprecated - Prior to iOS 17 full calendar access is required</string>
|
|
||||||
<key>NSCalendarsWriteOnlyAccessUsageDescription</key>
|
|
||||||
<string></string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
||||||
|
|
@ -534,6 +534,10 @@ struct CallView: View {
|
||||||
LinphoneVideoViewHolder { view in
|
LinphoneVideoViewHolder { view in
|
||||||
coreContext.doOnCoreQueue { core in
|
coreContext.doOnCoreQueue { core in
|
||||||
core.nativeVideoWindow = view
|
core.nativeVideoWindow = view
|
||||||
|
Log.info("debugtrace -- LinphoneVideoViewHolder set view 1")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
CoreContext.shared.pipViewModel.setupPiPViewController(remoteView: view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(
|
.frame(
|
||||||
|
|
@ -549,6 +553,9 @@ struct CallView: View {
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if callViewModel.videoDisplayed {
|
if callViewModel.videoDisplayed {
|
||||||
|
if coreContext.pipViewModel.pipController?.isPictureInPictureActive ?? false {
|
||||||
|
coreContext.pipViewModel.pipController?.stopPictureInPicture()
|
||||||
|
}
|
||||||
callViewModel.videoDisplayed = false
|
callViewModel.videoDisplayed = false
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
callViewModel.videoDisplayed = true
|
callViewModel.videoDisplayed = true
|
||||||
|
|
@ -557,6 +564,9 @@ struct CallView: View {
|
||||||
}
|
}
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
if callViewModel.videoDisplayed {
|
if callViewModel.videoDisplayed {
|
||||||
|
if !(coreContext.pipViewModel.pipController?.isPictureInPictureActive ?? false){
|
||||||
|
coreContext.pipViewModel.pipController?.startPictureInPicture()
|
||||||
|
}
|
||||||
callViewModel.videoDisplayed = false
|
callViewModel.videoDisplayed = false
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||||
callViewModel.videoDisplayed = true
|
callViewModel.videoDisplayed = true
|
||||||
|
|
@ -893,6 +903,10 @@ struct CallView: View {
|
||||||
LinphoneVideoViewHolder { view in
|
LinphoneVideoViewHolder { view in
|
||||||
coreContext.doOnCoreQueue { core in
|
coreContext.doOnCoreQueue { core in
|
||||||
core.nativeVideoWindow = view
|
core.nativeVideoWindow = view
|
||||||
|
Log.info("debugtrace -- LinphoneVideoViewHolder set view 2")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
CoreContext.shared.pipViewModel.setupPiPViewController(remoteView: view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2025 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-iphone
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import linphonesw
|
||||||
|
import SwiftUI
|
||||||
|
import AVKit
|
||||||
|
|
||||||
|
class PIPViewModel: NSObject, AVPictureInPictureControllerDelegate {
|
||||||
|
|
||||||
|
var pipController: AVPictureInPictureController?
|
||||||
|
var pipRemoteVideoView = SampleBufferVideoCallView()
|
||||||
|
var videoCallView = UIView()
|
||||||
|
|
||||||
|
var callStateChangedDelegate: CallDelegate?
|
||||||
|
|
||||||
|
func setupPiPViewController(remoteView: UIView) {
|
||||||
|
Log.info("debugtrace setupPiPViewController")
|
||||||
|
videoCallView = remoteView
|
||||||
|
let pipVideoCallController = PictureInPictureVideoCallViewController()
|
||||||
|
pipRemoteVideoView = pipVideoCallController.pipRemoteVideoView
|
||||||
|
let pipContentSource = AVPictureInPictureController.ContentSource(
|
||||||
|
activeVideoCallSourceView: videoCallView,
|
||||||
|
contentViewController: pipVideoCallController)
|
||||||
|
pipController = AVPictureInPictureController(contentSource: pipContentSource)
|
||||||
|
pipController?.delegate = self
|
||||||
|
pipController?.canStartPictureInPictureAutomaticallyFromInline = true
|
||||||
|
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
if let call = core.currentCall {
|
||||||
|
self.callStateChangedDelegate = CallDelegateStub(onStateChanged: { (_: Call, cstate: Call.State, _: String) in
|
||||||
|
if cstate != .StreamsRunning && CoreContext.shared.pipViewModel.pipController?.isPictureInPictureActive ?? false {
|
||||||
|
Log.info("debugtrace -- callstate changed stop pip")
|
||||||
|
CoreContext.shared.pipViewModel.pipController?.stopPictureInPicture()
|
||||||
|
if cstate == .End || cstate == .Error {
|
||||||
|
self.callStateChangedDelegate = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
call.addDelegate(delegate: self.callStateChangedDelegate!)
|
||||||
|
Log.info("debugtrace -- added callstatechanged delegate")
|
||||||
|
} else {
|
||||||
|
Log.info("debugtrace -- no current call")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ControlsViewModel.shared.isVideoEnabled.readCurrentAndObserve{ (video) in
|
||||||
|
pipVideoCallController.matchVideoDimension()
|
||||||
|
self.pipController?.canStartPictureInPictureAutomaticallyFromInline = video == true
|
||||||
|
}
|
||||||
|
|
||||||
|
CallsViewModel.shared.currentCallData.observe(onChange: { callData in
|
||||||
|
if (callData??.call.state != .StreamsRunning && self.pipController?.isPictureInPictureActive) {
|
||||||
|
self.pipController?.stopPictureInPicture()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||||
|
Log.info("debugtrace pictureInPictureControllerWillStartPictureInPicture")
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
core.nativeVideoWindow = self.pipRemoteVideoView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
|
||||||
|
Log.info("debugtrace pictureInPictureControllerDidStopPictureInPicture")
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
core.nativeVideoWindow = self.videoCallView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
|
||||||
|
CoreContext.shared.doOnCoreQueue { core in
|
||||||
|
core.nativeVideoWindow = self.videoCallView
|
||||||
|
}
|
||||||
|
Log.error("Start Picture in Picture video call error : \(error)")
|
||||||
|
// DispatchQueue.main.async { self.configurationPiPViewController() }
|
||||||
|
}
|
||||||
|
|
||||||
|
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
|
||||||
|
Log.info("debugtrace restoreUserInterfaceForPictureInPictureStopWithCompletionHandler")
|
||||||
|
|
||||||
|
|
||||||
|
TelecomManager.shared.callDisplayed = true
|
||||||
|
/* a
|
||||||
|
if (CallsViewModel.shared.currentCallData.value??.call.state == .StreamsRunning && PhoneMainView.instance().currentView != self.compositeViewDescription()) {
|
||||||
|
PhoneMainView.instance().changeCurrentView(self.compositeViewDescription())
|
||||||
|
//Core.get().nativeVideoWindow = pipRemoteVideoView // let the video on the pip view during the stop animation
|
||||||
|
}
|
||||||
|
//pictureInPictureController.contentSource?.activeVideoCallContentViewController.view.layer.cornerRadius = ActiveCallView.center_view_corner_radius
|
||||||
|
*/
|
||||||
|
completionHandler(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PictureInPictureVideoCallViewController: AVPictureInPictureVideoCallViewController {
|
||||||
|
|
||||||
|
var pipRemoteVideoView = SampleBufferVideoCallView()
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
view.backgroundColor = .black
|
||||||
|
view.clipsToBounds = true
|
||||||
|
view.addSubview(pipRemoteVideoView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
view.layer.cornerRadius = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLayoutSubviews() {
|
||||||
|
matchVideoDimension()
|
||||||
|
super.viewDidLayoutSubviews()
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchVideoDimension() {
|
||||||
|
Log.info("debugtrace - matchVideoDimension")
|
||||||
|
self.preferredContentSize = CGSize(width: Double(720), height: Double(480))
|
||||||
|
pipRemoteVideoView.frame = view.bounds
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// swiftlint:disable force_cast
|
||||||
|
class SampleBufferVideoCallView: UIView {
|
||||||
|
override class var layerClass: AnyClass {
|
||||||
|
AVSampleBufferDisplayLayer.self
|
||||||
|
}
|
||||||
|
|
||||||
|
var sampleBufferDisplayLayer: AVSampleBufferDisplayLayer {
|
||||||
|
layer as! AVSampleBufferDisplayLayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// swiftlint:enable force_cast
|
||||||
Loading…
Add table
Reference in a new issue